playback: fix concatenation of segments with multiple tracks (#3198)

the duration of segments was computed erroneously, since it was taking
into consideration the last track only. Now the duration of a segment
corresponds to the maximum duration among all tracks.
This commit is contained in:
Alessandro Ros
2024-04-07 12:48:47 +02:00
committed by GitHub
parent 50322fc14e
commit c263fc6f7b
4 changed files with 60 additions and 39 deletions
+16 -8
View File
@@ -95,7 +95,7 @@ func fmp4ReadInit(r io.ReadSeeker) ([]byte, error) {
return buf, nil
}
func fmp4ReadDuration(r io.ReadSeeker) (time.Duration, error) {
func fmp4ReadMaxDuration(r io.ReadSeeker) (time.Duration, error) {
// find and skip ftyp
buf := make([]byte, 8)
@@ -321,7 +321,7 @@ func fmp4SeekAndMuxParts(
var outPart *fmp4.Part
var outTrack *fmp4.PartTrack
var outBuf seekablebuffer.Buffer
elapsed := uint64(0)
maxElapsed := uint64(0)
initWritten := false
firstSampleWritten := make(map[uint32]struct{})
gop := make(map[uint32][]*fmp4.PartSample)
@@ -370,7 +370,7 @@ func fmp4SeekAndMuxParts(
return nil, err
}
elapsed = tfdt.BaseMediaDecodeTimeV1
elapsed := tfdt.BaseMediaDecodeTimeV1
baseTimeSet := false
for _, e := range trun.Entries {
@@ -426,6 +426,10 @@ func fmp4SeekAndMuxParts(
elapsed += uint64(e.SampleDuration)
}
if elapsed > maxElapsed {
maxElapsed = elapsed
}
if outTrack.Samples != nil {
outPart.Tracks = append(outPart.Tracks, outTrack)
}
@@ -467,9 +471,9 @@ func fmp4SeekAndMuxParts(
return 0, errNoSegmentsFound
}
elapsed -= minTimeMP4
maxElapsed -= minTimeMP4
return durationMp4ToGo(elapsed, fmp4Timescale), nil
return durationMp4ToGo(maxElapsed, fmp4Timescale), nil
}
func fmp4MuxParts(
@@ -485,7 +489,7 @@ func fmp4MuxParts(
var outPart *fmp4.Part
var outTrack *fmp4.PartTrack
var outBuf seekablebuffer.Buffer
elapsed := uint64(0)
maxElapsed := uint64(0)
_, err := mp4.ReadBoxStructure(r, func(h *mp4.ReadHandle) (interface{}, error) {
switch h.BoxInfo.Type.String() {
@@ -534,7 +538,7 @@ func fmp4MuxParts(
return nil, err
}
elapsed = tfdt.BaseMediaDecodeTimeV1
elapsed := tfdt.BaseMediaDecodeTimeV1
for _, e := range trun.Entries {
payload := make([]byte, e.SampleSize)
@@ -561,6 +565,10 @@ func fmp4MuxParts(
elapsed += uint64(e.SampleDuration)
}
if elapsed > maxElapsed {
maxElapsed = elapsed
}
if outTrack.Samples != nil {
outPart.Tracks = append(outPart.Tracks, outTrack)
}
@@ -590,5 +598,5 @@ func fmp4MuxParts(
return 0, err
}
return durationMp4ToGo(elapsed, fmp4Timescale), nil
return durationMp4ToGo(maxElapsed, fmp4Timescale), nil
}
+9 -9
View File
@@ -38,7 +38,7 @@ func seekAndMux(
minTime := start.Sub(segments[0].Start)
maxTime := minTime + duration
var init []byte
var elapsed time.Duration
var maxElapsed time.Duration
err := func() error {
f, err := os.Open(segments[0].Fpath)
@@ -52,7 +52,7 @@ func seekAndMux(
return err
}
elapsed, err = fmp4SeekAndMuxParts(f, init, minTime, maxTime, w)
maxElapsed, err = fmp4SeekAndMuxParts(f, init, minTime, maxTime, w)
if err != nil {
return err
}
@@ -63,10 +63,10 @@ func seekAndMux(
return err
}
duration -= maxElapsed
overallElapsed := maxElapsed
prevInit := init
prevEnd := start.Add(elapsed)
duration -= elapsed
overallElapsed := elapsed
prevEnd := start.Add(maxElapsed)
for _, seg := range segments[1:] {
err := func() error {
@@ -85,7 +85,7 @@ func seekAndMux(
return errStopIteration
}
elapsed, err = fmp4MuxParts(f, overallElapsed, duration, w)
maxElapsed, err = fmp4MuxParts(f, overallElapsed, duration, w)
if err != nil {
return err
}
@@ -100,9 +100,9 @@ func seekAndMux(
return err
}
prevEnd = seg.Start.Add(elapsed)
duration -= elapsed
overallElapsed += elapsed
duration -= maxElapsed
overallElapsed += maxElapsed
prevEnd = seg.Start.Add(maxElapsed)
}
return nil
+32 -19
View File
@@ -59,27 +59,40 @@ func writeSegment1(t *testing.T, fpath string) {
},
{
SequenceNumber: 1,
Tracks: []*fmp4.PartTrack{{
ID: 1,
BaseTime: 30 * 90000,
Samples: []*fmp4.PartSample{
{
Duration: 30 * 90000,
IsNonSyncSample: false,
Payload: []byte{1, 2},
},
{
Duration: 1 * 90000,
IsNonSyncSample: false,
Payload: []byte{3, 4},
},
{
Duration: 1 * 90000,
IsNonSyncSample: true,
Payload: []byte{5, 6},
Tracks: []*fmp4.PartTrack{
{
ID: 1,
BaseTime: 30 * 90000,
Samples: []*fmp4.PartSample{
{
Duration: 30 * 90000,
IsNonSyncSample: false,
Payload: []byte{1, 2},
},
{
Duration: 1 * 90000,
IsNonSyncSample: false,
Payload: []byte{3, 4},
},
{
Duration: 1 * 90000,
IsNonSyncSample: true,
Payload: []byte{5, 6},
},
},
},
}},
{
ID: 2,
BaseTime: 29 * 90000,
Samples: []*fmp4.PartSample{
{
Duration: 30 * 90000,
IsNonSyncSample: false,
Payload: []byte{1, 2},
},
},
},
},
},
}
err = parts.Marshal(&buf2)
+3 -3
View File
@@ -47,7 +47,7 @@ func computeDurationAndConcatenate(recordFormat conf.RecordFormat, segments []*S
return err
}
duration, err := fmp4ReadDuration(f)
maxDuration, err := fmp4ReadMaxDuration(f)
if err != nil {
return err
}
@@ -58,12 +58,12 @@ func computeDurationAndConcatenate(recordFormat conf.RecordFormat, segments []*S
init,
seg.Start) {
prevStart := out[len(out)-1].Start
curEnd := seg.Start.Add(duration)
curEnd := seg.Start.Add(maxDuration)
out[len(out)-1].Duration = listEntryDuration(curEnd.Sub(prevStart))
} else {
out = append(out, listEntry{
Start: seg.Start,
Duration: listEntryDuration(duration),
Duration: listEntryDuration(maxDuration),
})
}