Skip to content

Commit c47fc92

Browse files
committed
fix: handle stts case with single trailing zero duration
1 parent 7924ad3 commit c47fc92

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

mp4/stts.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,15 @@ func (b *SttsBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string
166166
return bd.err
167167
}
168168

169-
// GetSampleNrAtTime - get sample number at or as soon as possible after time
169+
// GetSampleNrAtTime returns the 1-based sample number at or as soon as possible after time.
170+
// Match a final single zero duration if present.
171+
// If time is too big to reach, an error is returned.
170172
// Time is calculated by summing up durations of previous samples
171173
func (b *SttsBox) GetSampleNrAtTime(sampleStartTime uint64) (sampleNr uint32, err error) {
172174
accTime := uint64(0)
173175
accNr := uint32(0)
174-
for i := 0; i < len(b.SampleCount); i++ {
176+
nrEntries := len(b.SampleCount)
177+
for i := 0; i < nrEntries; i++ {
175178
timeDelta := uint64(b.SampleTimeDelta[i])
176179
if sampleStartTime < accTime+uint64(b.SampleCount[i])*timeDelta {
177180
relTime := (sampleStartTime - accTime)
@@ -184,5 +187,10 @@ func (b *SttsBox) GetSampleNrAtTime(sampleStartTime uint64) (sampleNr uint32, er
184187
accNr += b.SampleCount[i]
185188
accTime += timeDelta * uint64(b.SampleCount[i])
186189
}
190+
// Check if there is a final single zero duration and time matches.
191+
if b.SampleTimeDelta[nrEntries-1] == 0 && b.SampleCount[nrEntries-1] == 1 &&
192+
sampleStartTime == accTime {
193+
return accNr, nil
194+
}
187195
return 0, fmt.Errorf("no matching sample found for time=%d", sampleStartTime)
188196
}

mp4/stts_test.go

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,36 @@ func TestGetSampleNrAtTime(t *testing.T) {
1717
SampleTimeDelta: []uint32{10, 14},
1818
}
1919

20+
sttsZero := SttsBox{
21+
SampleCount: []uint32{2, 1},
22+
SampleTimeDelta: []uint32{10, 0}, // Single zero duration at end
23+
}
24+
2025
testCases := []struct {
26+
stts SttsBox
2127
startTime uint64
2228
sampleNr uint32
2329
expectError bool
2430
}{
25-
{0, 1, false},
26-
{1, 2, false},
27-
{10, 2, false},
28-
{20, 3, false},
29-
{30, 4, false},
30-
{31, 5, false},
31-
{43, 5, false},
32-
{44, 5, false},
33-
{45, 6, false},
34-
{57, 6, false},
35-
{58, 0, true},
31+
{stts, 0, 1, false},
32+
{stts, 1, 2, false},
33+
{stts, 10, 2, false},
34+
{stts, 20, 3, false},
35+
{stts, 30, 4, false},
36+
{stts, 31, 5, false},
37+
{stts, 43, 5, false},
38+
{stts, 44, 5, false},
39+
{stts, 45, 6, false},
40+
{stts, 57, 6, false},
41+
{stts, 58, 0, true},
42+
{sttsZero, 0, 1, false},
43+
{sttsZero, 10, 2, false},
44+
{sttsZero, 20, 3, false},
45+
{sttsZero, 21, 3, true},
3646
}
3747

3848
for _, tc := range testCases {
39-
gotNr, err := stts.GetSampleNrAtTime(tc.startTime)
49+
gotNr, err := tc.stts.GetSampleNrAtTime(tc.startTime)
4050
if tc.expectError {
4151
if err == nil {
4252
t.Errorf("Did not get error for startTime %d", tc.startTime)

0 commit comments

Comments
 (0)