Skip to content

Commit 9c59304

Browse files
authored
playback: support concatenating segments with long gaps (#5172)
Thanks to the new mtxi MP4 box, it's possible to check whether two segments are consecutive without involving dates or timestamps. When the new mtxi box is present in both segments, do not check if the end of the first segment corresponds to the start of the second segment.
1 parent 7750e2b commit 9c59304

File tree

2 files changed

+380
-29
lines changed

2 files changed

+380
-29
lines changed

internal/playback/segment_fmp4.go

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,38 +58,22 @@ func findMtxi(userData []amp4.IBox) *recordstore.Mtxi {
5858
return nil
5959
}
6060

61-
func segmentFMP4AreConsecutive(init1 *fmp4.Init, init2 *fmp4.Init) bool {
62-
mtxi1 := findMtxi(init1.UserData)
63-
mtxi2 := findMtxi(init2.UserData)
64-
65-
switch {
66-
case mtxi1 == nil && mtxi2 != nil:
61+
func segmentFMP4TracksAreEqual(tracks1 []*fmp4.InitTrack, tracks2 []*fmp4.InitTrack) bool {
62+
if len(tracks1) != len(tracks2) {
6763
return false
64+
}
6865

69-
case mtxi1 != nil && mtxi2 == nil:
70-
return false
66+
for i, track1 := range tracks1 {
67+
track2 := tracks2[i]
7168

72-
case mtxi1 == nil && mtxi2 == nil: // legacy method: compare tracks
73-
if len(init1.Tracks) != len(init2.Tracks) {
69+
if track1.ID != track2.ID ||
70+
track1.TimeScale != track2.TimeScale ||
71+
reflect.TypeOf(track1.Codec) != reflect.TypeOf(track2.Codec) {
7472
return false
7573
}
76-
77-
for i, track1 := range init1.Tracks {
78-
track2 := init2.Tracks[i]
79-
80-
if track1.ID != track2.ID ||
81-
track1.TimeScale != track2.TimeScale ||
82-
reflect.TypeOf(track1.Codec) != reflect.TypeOf(track2.Codec) {
83-
return false
84-
}
85-
}
86-
87-
return true
88-
89-
default:
90-
return bytes.Equal(mtxi1.StreamID[:], mtxi2.StreamID[:]) &&
91-
(mtxi1.SegmentNumber+1) == mtxi2.SegmentNumber
9274
}
75+
76+
return true
9377
}
9478

9579
func segmentFMP4CanBeConcatenated(
@@ -98,9 +82,25 @@ func segmentFMP4CanBeConcatenated(
9882
curInit *fmp4.Init,
9983
curStart time.Time,
10084
) bool {
101-
return segmentFMP4AreConsecutive(prevInit, curInit) &&
102-
!curStart.Before(prevEnd.Add(-concatenationTolerance)) &&
103-
!curStart.After(prevEnd.Add(concatenationTolerance))
85+
mtxi1 := findMtxi(prevInit.UserData)
86+
mtxi2 := findMtxi(curInit.UserData)
87+
88+
switch {
89+
case mtxi1 == nil && mtxi2 != nil:
90+
return false
91+
92+
case mtxi1 != nil && mtxi2 == nil:
93+
return false
94+
95+
case mtxi1 == nil && mtxi2 == nil: // legacy method
96+
return segmentFMP4TracksAreEqual(prevInit.Tracks, curInit.Tracks) &&
97+
!curStart.Before(prevEnd.Add(-concatenationTolerance)) &&
98+
!curStart.After(prevEnd.Add(concatenationTolerance))
99+
100+
default:
101+
return bytes.Equal(mtxi1.StreamID[:], mtxi2.StreamID[:]) &&
102+
(mtxi1.SegmentNumber+1) == mtxi2.SegmentNumber
103+
}
104104
}
105105

106106
func segmentFMP4ReadHeader(r io.ReadSeeker) (*fmp4.Init, time.Duration, error) {

0 commit comments

Comments
 (0)