Skip to content

Commit 5e4200a

Browse files
committed
Add Probe() to accurately determine the number of streams for VCD
1 parent 5c3bb09 commit 5e4200a

File tree

3 files changed

+87
-21
lines changed

3 files changed

+87
-21
lines changed

demux.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,47 @@ func (d *Demux) HasHeaders() bool {
130130
return true
131131
}
132132

133+
// Probe probes the file for the actual number of video/audio streams.
134+
func (d *Demux) Probe(probeSize int) bool {
135+
prevPos := d.buf.tell()
136+
137+
videoStream := false
138+
audioStreams := [4]bool{false, false, false, false}
139+
140+
for {
141+
d.startCode = d.buf.nextStartCode()
142+
if d.startCode == PacketVideo1 {
143+
videoStream = true
144+
} else if d.startCode >= PacketAudio1 && d.startCode <= PacketAudio4 {
145+
audioStreams[d.startCode-PacketAudio1] = true
146+
}
147+
148+
if d.startCode == -1 || d.buf.tell()-prevPos > probeSize {
149+
break
150+
}
151+
}
152+
153+
d.numVideoStreams = 0
154+
if videoStream {
155+
d.numVideoStreams = 1
156+
}
157+
158+
d.numAudioStreams = 0
159+
for i := 0; i < 4; i++ {
160+
if audioStreams[i] {
161+
d.numAudioStreams++
162+
}
163+
}
164+
165+
d.buf.seek(prevPos)
166+
167+
if d.numVideoStreams > 0 || d.numAudioStreams > 0 {
168+
return true
169+
}
170+
171+
return false
172+
}
173+
133174
// NumVideoStreams returns the number of video streams found in the system header.
134175
func (d *Demux) NumVideoStreams() int {
135176
if d.HasHeaders() {

mpeg.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ func New(r io.Reader) (*MPEG, error) {
114114
return m, nil
115115
}
116116

117-
// HasHeaders checks whether we have headers on all available streams, and if we can accurately
118-
// report the number of video/audio streams, video dimensions, framerate and audio samplerate.
117+
// HasHeaders checks whether we have headers on all available streams, and if we can report the
118+
// number of video/audio streams, video dimensions, framerate and audio samplerate.
119119
func (m *MPEG) HasHeaders() bool {
120120
if !m.demux.HasHeaders() {
121121
return false
@@ -132,6 +132,25 @@ func (m *MPEG) HasHeaders() bool {
132132
return true
133133
}
134134

135+
// Probe probes the MPEG-PS data to find the actual number of video and audio streams within the buffer.
136+
// For certain files (e.g. VideoCD) this can be more accurate than just reading the number of streams from the headers.
137+
// This should only be used when the underlying reader is seekable.
138+
// The necessary probe size is dependent on the files you expect to read. Usually a few hundred KB should be enough to find all streams.
139+
// Use Num{Audio|Video}Streams() afterwards to get the number of streams in the file.
140+
// Returns true if any streams were found within the probe size.
141+
func (m *MPEG) Probe(probeSize int) bool {
142+
if !m.demux.Probe(probeSize) {
143+
return false
144+
}
145+
146+
// Re-init decoders
147+
m.hasDecoders = false
148+
m.videoPacketType = 0
149+
m.audioPacketType = 0
150+
151+
return m.initDecoders()
152+
}
153+
135154
// Done returns done channel.
136155
func (m *MPEG) Done() chan bool {
137156
return m.done
@@ -451,7 +470,7 @@ func (m *MPEG) SeekFrame(tm time.Duration, seekExact bool) *Frame {
451470
duration := m.demux.Duration(typ)
452471

453472
if tm.Seconds() < 0 {
454-
tm = 0
473+
tm = time.Duration(0)
455474
} else if tm.Seconds() > duration {
456475
tm = time.Duration(duration * float64(time.Second))
457476
}
@@ -570,33 +589,31 @@ func (m *MPEG) initDecoders() bool {
570589
m.videoPacketType = PacketVideo1
571590
}
572591

573-
m.videoBuffer, err = NewBuffer(nil)
574-
if err != nil {
575-
return false
576-
}
592+
if m.videoDecoder == nil {
593+
m.videoBuffer, err = NewBuffer(nil)
594+
if err != nil {
595+
return false
596+
}
577597

578-
m.videoBuffer.SetLoadCallback(m.readVideoPacket)
598+
m.videoBuffer.SetLoadCallback(m.readVideoPacket)
599+
m.videoDecoder = NewVideo(m.videoBuffer)
600+
}
579601
}
580602

581603
if m.demux.NumAudioStreams() > 0 {
582604
if m.audioEnabled {
583605
m.audioPacketType = PacketAudio1 + m.audioStreamIndex
584606
}
585607

586-
m.audioBuffer, err = NewBuffer(nil)
587-
if err != nil {
588-
return false
589-
}
590-
591-
m.audioBuffer.SetLoadCallback(m.readAudioPacket)
592-
}
593-
594-
if m.videoBuffer != nil {
595-
m.videoDecoder = NewVideo(m.videoBuffer)
596-
}
608+
if m.audioDecoder == nil {
609+
m.audioBuffer, err = NewBuffer(nil)
610+
if err != nil {
611+
return false
612+
}
597613

598-
if m.audioBuffer != nil {
599-
m.audioDecoder = NewAudio(m.audioBuffer)
614+
m.audioBuffer.SetLoadCallback(m.readAudioPacket)
615+
m.audioDecoder = NewAudio(m.audioBuffer)
616+
}
600617
}
601618

602619
m.hasDecoders = true

mpeg_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ func TestDemux(t *testing.T) {
4848
t.Fatal(err)
4949
}
5050

51+
if !demux.Probe(5000 * 1024) {
52+
t.Error("Probe: no MPEG video or audio streams found")
53+
}
54+
5155
if !demux.HasHeaders() {
5256
t.Error("HasHeaders: no headers")
5357
}
@@ -152,6 +156,10 @@ func TestMpeg(t *testing.T) {
152156
t.Fatal(err)
153157
}
154158

159+
if !mpg.Probe(5000 * 1024) {
160+
t.Error("Probe: no MPEG video or audio streams found")
161+
}
162+
155163
if !mpg.HasHeaders() {
156164
t.Error("HasHeaders: no headers")
157165
}

0 commit comments

Comments
 (0)