diff --git a/muxer_segment_fmp4.go b/muxer_segment_fmp4.go index 121b144..5242726 100644 --- a/muxer_segment_fmp4.go +++ b/muxer_segment_fmp4.go @@ -19,7 +19,8 @@ type muxerSegmentFMP4 struct { audioTimeScale uint32 prefix string forceSwitched bool - genPartID func() uint64 + takePartID func() uint64 + givePartID func() publishPart func(*muxerPart) name string @@ -42,7 +43,8 @@ func newMuxerSegmentFMP4( prefix string, forceSwitched bool, factory storage.Factory, - genPartID func() uint64, + takePartID func() uint64, + givePartID func(), publishPart func(*muxerPart), ) (*muxerSegmentFMP4, error) { s := &muxerSegmentFMP4{ @@ -56,7 +58,8 @@ func newMuxerSegmentFMP4( audioTimeScale: audioTimeScale, prefix: prefix, forceSwitched: forceSwitched, - genPartID: genPartID, + takePartID: takePartID, + givePartID: givePartID, publishPart: publishPart, name: segmentName(prefix, id, true), } @@ -73,7 +76,7 @@ func newMuxerSegmentFMP4( s.audioTrack, s.audioTimeScale, prefix, - s.genPartID(), + s.takePartID(), s.storage.NewPart(), ) @@ -111,9 +114,12 @@ func (s *muxerSegmentFMP4) finalize(nextDTS time.Duration) error { return err } - s.publishPart(s.currentPart) s.parts = append(s.parts, s.currentPart) + s.publishPart(s.currentPart) + } else { + s.givePartID() } + s.currentPart = nil s.storage.Finalize() @@ -153,7 +159,7 @@ func (s *muxerSegmentFMP4) writeVideo( s.audioTrack, s.audioTimeScale, s.prefix, - s.genPartID(), + s.takePartID(), s.storage.NewPart(), ) } @@ -191,7 +197,7 @@ func (s *muxerSegmentFMP4) writeAudio( s.audioTrack, s.audioTimeScale, s.prefix, - s.genPartID(), + s.takePartID(), s.storage.NewPart(), ) } diff --git a/muxer_segmenter_fmp4.go b/muxer_segmenter_fmp4.go index 1693293..acb8027 100644 --- a/muxer_segmenter_fmp4.go +++ b/muxer_segmenter_fmp4.go @@ -159,18 +159,22 @@ func (m *muxerSegmenterFMP4) close() { } } -func (m *muxerSegmenterFMP4) genSegmentID() uint64 { +func (m *muxerSegmenterFMP4) takeSegmentID() uint64 { id := m.nextSegmentID m.nextSegmentID++ return id } -func (m *muxerSegmenterFMP4) genPartID() uint64 { +func (m *muxerSegmenterFMP4) takePartID() uint64 { id := m.nextPartID m.nextPartID++ return id } +func (m *muxerSegmenterFMP4) givePartID() { + m.nextPartID-- +} + // iPhone iOS fails if part durations are less than 85% of maximum part duration. // find a part duration that is compatible with all received sample durations func (m *muxerSegmenterFMP4) adjustPartDuration(sampleDuration time.Duration) { @@ -322,7 +326,7 @@ func (m *muxerSegmenterFMP4) writeVideo( var err error m.currentSegment, err = newMuxerSegmentFMP4( m.lowLatency, - m.genSegmentID(), + m.takeSegmentID(), sample.ntp, sample.dts, m.segmentMaxSize, @@ -332,7 +336,8 @@ func (m *muxerSegmenterFMP4) writeVideo( m.prefix, false, m.factory, - m.genPartID, + m.takePartID, + m.givePartID, m.publishPart, ) if err != nil { @@ -365,7 +370,7 @@ func (m *muxerSegmenterFMP4) writeVideo( m.currentSegment, err = newMuxerSegmentFMP4( m.lowLatency, - m.genSegmentID(), + m.takeSegmentID(), m.nextVideoSample.ntp, m.nextVideoSample.dts, m.segmentMaxSize, @@ -375,7 +380,8 @@ func (m *muxerSegmenterFMP4) writeVideo( m.prefix, forceSwitch, m.factory, - m.genPartID, + m.takePartID, + m.givePartID, m.publishPart, ) if err != nil { @@ -455,7 +461,7 @@ func (m *muxerSegmenterFMP4) writeAudio(ntp time.Time, dts time.Duration, au []b var err error m.currentSegment, err = newMuxerSegmentFMP4( m.lowLatency, - m.genSegmentID(), + m.takeSegmentID(), sample.ntp, sample.dts, m.segmentMaxSize, @@ -465,7 +471,8 @@ func (m *muxerSegmenterFMP4) writeAudio(ntp time.Time, dts time.Duration, au []b m.prefix, false, m.factory, - m.genPartID, + m.takePartID, + m.givePartID, m.publishPart, ) if err != nil { @@ -501,7 +508,7 @@ func (m *muxerSegmenterFMP4) writeAudio(ntp time.Time, dts time.Duration, au []b m.currentSegment, err = newMuxerSegmentFMP4( m.lowLatency, - m.genSegmentID(), + m.takeSegmentID(), m.nextAudioSample.ntp, m.nextAudioSample.dts, m.segmentMaxSize, @@ -511,7 +518,8 @@ func (m *muxerSegmenterFMP4) writeAudio(ntp time.Time, dts time.Duration, au []b m.prefix, false, m.factory, - m.genPartID, + m.takePartID, + m.givePartID, m.publishPart, ) if err != nil { diff --git a/muxer_segmenter_mpegts.go b/muxer_segmenter_mpegts.go index 543f1f6..c479775 100644 --- a/muxer_segmenter_mpegts.go +++ b/muxer_segmenter_mpegts.go @@ -91,7 +91,7 @@ func (m *muxerSegmenterMPEGTS) close() { } } -func (m *muxerSegmenterMPEGTS) genSegmentID() uint64 { +func (m *muxerSegmenterMPEGTS) takeSegmentID() uint64 { id := m.nextSegmentID m.nextSegmentID++ return id @@ -142,7 +142,7 @@ func (m *muxerSegmenterMPEGTS) writeH26x( // create first segment m.currentSegment, err = newMuxerSegmentMPEGTS( - m.genSegmentID(), + m.takeSegmentID(), ntp, m.segmentMaxSize, m.writerVideoTrack, @@ -176,7 +176,7 @@ func (m *muxerSegmenterMPEGTS) writeH26x( } m.currentSegment, err = newMuxerSegmentMPEGTS( - m.genSegmentID(), + m.takeSegmentID(), ntp, m.segmentMaxSize, m.writerVideoTrack, @@ -214,7 +214,7 @@ func (m *muxerSegmenterMPEGTS) writeMPEG4Audio(ntp time.Time, pts time.Duration, // create first segment var err error m.currentSegment, err = newMuxerSegmentMPEGTS( - m.genSegmentID(), + m.takeSegmentID(), ntp, m.segmentMaxSize, m.writerVideoTrack, @@ -240,7 +240,7 @@ func (m *muxerSegmenterMPEGTS) writeMPEG4Audio(ntp time.Time, pts time.Duration, } m.currentSegment, err = newMuxerSegmentMPEGTS( - m.genSegmentID(), + m.takeSegmentID(), ntp, m.segmentMaxSize, m.writerVideoTrack, diff --git a/muxer_test.go b/muxer_test.go index 6ee54c0..710d62f 100644 --- a/muxer_test.go +++ b/muxer_test.go @@ -291,10 +291,10 @@ func TestMuxerVideoAudio(t *testing.T) { `#EXTINF:4.00000,\n` + `(.*?_seg7\.mp4)\n` + `#EXT-X-PROGRAM-DATE-TIME:2010-01-01T01:01:06Z\n` + - `#EXT-X-PART:DURATION=1.00000,URI="(.*?_part3\.mp4)",INDEPENDENT=YES\n` + + `#EXT-X-PART:DURATION=1.00000,URI="(.*?_part2\.mp4)",INDEPENDENT=YES\n` + `#EXTINF:1.00000,\n` + `(.*?_seg8\.mp4)\n` + - `#EXT-X-PRELOAD-HINT:TYPE=PART,URI="(.*?_part4\.mp4)"\n$`) + `#EXT-X-PRELOAD-HINT:TYPE=PART,URI="(.*?_part3\.mp4)"\n$`) require.Regexp(t, re, string(byts)) ma := re.FindStringSubmatch(string(byts))