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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user