Skip to content

Commit

Permalink
muxer: fix discontinuity in part ID (#107)
Browse files Browse the repository at this point in the history
(bluenviron/mediamtx#2317)

this prevented Low-Latency HLS from running smoothly on Safari
  • Loading branch information
aler9 authored Nov 10, 2023
1 parent 006854b commit e7092f1
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 24 deletions.
20 changes: 13 additions & 7 deletions muxer_segment_fmp4.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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{
Expand All @@ -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),
}
Expand All @@ -73,7 +76,7 @@ func newMuxerSegmentFMP4(
s.audioTrack,
s.audioTimeScale,
prefix,
s.genPartID(),
s.takePartID(),
s.storage.NewPart(),
)

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -153,7 +159,7 @@ func (s *muxerSegmentFMP4) writeVideo(
s.audioTrack,
s.audioTimeScale,
s.prefix,
s.genPartID(),
s.takePartID(),
s.storage.NewPart(),
)
}
Expand Down Expand Up @@ -191,7 +197,7 @@ func (s *muxerSegmentFMP4) writeAudio(
s.audioTrack,
s.audioTimeScale,
s.prefix,
s.genPartID(),
s.takePartID(),
s.storage.NewPart(),
)
}
Expand Down
28 changes: 18 additions & 10 deletions muxer_segmenter_fmp4.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -332,7 +336,8 @@ func (m *muxerSegmenterFMP4) writeVideo(
m.prefix,
false,
m.factory,
m.genPartID,
m.takePartID,
m.givePartID,
m.publishPart,
)
if err != nil {
Expand Down Expand Up @@ -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,
Expand All @@ -375,7 +380,8 @@ func (m *muxerSegmenterFMP4) writeVideo(
m.prefix,
forceSwitch,
m.factory,
m.genPartID,
m.takePartID,
m.givePartID,
m.publishPart,
)
if err != nil {
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down
10 changes: 5 additions & 5 deletions muxer_segmenter_mpegts.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -142,7 +142,7 @@ func (m *muxerSegmenterMPEGTS) writeH26x(

// create first segment
m.currentSegment, err = newMuxerSegmentMPEGTS(
m.genSegmentID(),
m.takeSegmentID(),
ntp,
m.segmentMaxSize,
m.writerVideoTrack,
Expand Down Expand Up @@ -176,7 +176,7 @@ func (m *muxerSegmenterMPEGTS) writeH26x(
}

m.currentSegment, err = newMuxerSegmentMPEGTS(
m.genSegmentID(),
m.takeSegmentID(),
ntp,
m.segmentMaxSize,
m.writerVideoTrack,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions muxer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down

0 comments on commit e7092f1

Please sign in to comment.