Skip to content

Commit 8fa1613

Browse files
authored
Account for video with DTS shift and resulting negative dts values (#16)
* Account for video with DTS shift and resulting negative dts values * typo fix
1 parent 7a4c51a commit 8fa1613

File tree

1 file changed

+27
-11
lines changed

1 file changed

+27
-11
lines changed

src/reader.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ impl Mp4 {
135135
let mut last_stss_index = 0;
136136
let mut last_sample_in_ctts_run = -1i64;
137137
let mut ctts_run_index = -1i64;
138+
let mut dts_shift = 0;
138139

139140
let mut samples = Vec::<Sample>::new();
140141

@@ -204,7 +205,7 @@ impl Mp4 {
204205
samples[sample_n - 1].duration =
205206
stts.entries[stts_run_index as usize].sample_delta as u64;
206207

207-
samples[sample_n - 1].decode_timestamp + samples[sample_n - 1].duration
208+
samples[sample_n - 1].decode_timestamp + samples[sample_n - 1].duration as i64
208209
} else {
209210
0
210211
};
@@ -219,9 +220,14 @@ impl Mp4 {
219220
ctts.entries[ctts_run_index as usize].sample_count as i64;
220221
}
221222

222-
decode_timestamp.saturating_add_signed(
223-
ctts.entries[ctts_run_index as usize].sample_offset as i64,
224-
)
223+
// dts shift is determined by the smallest negative sample offset:
224+
// https://github.com/FFmpeg/FFmpeg/blob/455db6fe109cf905fe518ea2690495948937438f/libavformat/mov.c#L3671
225+
let offset = ctts.entries[ctts_run_index as usize].sample_offset as i64;
226+
if offset < 0 {
227+
dts_shift = dts_shift.max(-offset);
228+
}
229+
230+
decode_timestamp + offset
225231
} else {
226232
decode_timestamp
227233
};
@@ -253,7 +259,16 @@ impl Mp4 {
253259
}
254260

255261
if let Some(last_sample) = samples.last_mut() {
256-
last_sample.duration = trak.mdia.mdhd.duration - last_sample.decode_timestamp;
262+
last_sample.duration =
263+
trak.mdia.mdhd.duration - last_sample.decode_timestamp as u64;
264+
}
265+
266+
// Fixup all DTS by the dts shift if there's one.
267+
// https://github.com/FFmpeg/FFmpeg/blob/455db6fe109cf905fe518ea2690495948937438f/libavformat/mov.c#L4271
268+
if dts_shift > 0 {
269+
for sample in &mut samples {
270+
sample.decode_timestamp -= dts_shift;
271+
}
257272
}
258273

259274
tracks.insert(
@@ -333,17 +348,17 @@ impl Mp4 {
333348
let mut decode_timestamp = 0;
334349
if track.first_traf_merged || sample_n > 0 {
335350
let prev = &track.samples[track.samples.len() - 1];
336-
decode_timestamp = prev.decode_timestamp + prev.duration;
351+
decode_timestamp = prev.decode_timestamp + prev.duration as i64;
337352
} else {
338353
if let Some(tfdt) = &traf.tfdt {
339-
decode_timestamp = tfdt.base_media_decode_time;
354+
decode_timestamp = tfdt.base_media_decode_time as i64;
340355
}
341356
track.first_traf_merged = true;
342357
}
343358

344359
let composition_timestamp = if trun.flags & TrunBox::FLAG_SAMPLE_CTS != 0 {
345360
decode_timestamp
346-
+ trun.sample_cts.get(sample_n).copied().unwrap_or(0) as u64
361+
+ trun.sample_cts.get(sample_n).copied().unwrap_or(0) as i64
347362
} else {
348363
decode_timestamp
349364
};
@@ -381,6 +396,7 @@ impl Mp4 {
381396
.copied()
382397
.unwrap_or(default_sample_size) as u64;
383398

399+
// Sample offset in bytes. (Must be positive, otherwise this would be outside of the file.)
384400
let sample_offset = if traf_idx == 0 && sample_n == 0 {
385401
if data_offset_present {
386402
base_data_offset
@@ -419,7 +435,7 @@ impl Mp4 {
419435
track.duration = track
420436
.samples
421437
.last()
422-
.map(|v| v.decode_timestamp + v.duration)
438+
.map(|v| v.duration.saturating_add_signed(v.composition_timestamp))
423439
.unwrap_or_default();
424440
}
425441
}
@@ -508,11 +524,11 @@ pub struct Sample {
508524

509525
/// Timestamp of the sample at which it should be decoded,
510526
/// in time units.
511-
pub decode_timestamp: u64,
527+
pub decode_timestamp: i64,
512528

513529
/// Timestamp of the sample at which the sample should be displayed,
514530
/// in time units.
515-
pub composition_timestamp: u64,
531+
pub composition_timestamp: i64,
516532

517533
/// Duration of the sample in time units.
518534
pub duration: u64,

0 commit comments

Comments
 (0)