Skip to content

Commit eac91c2

Browse files
author
Adrian
committed
Make time conversion functions return newtype Microseconds<T> to help avoid unit-mixing mistakes
1 parent 16c1d4d commit eac91c2

2 files changed

Lines changed: 33 additions & 21 deletions

File tree

mp4parse/src/unstable.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,11 @@ pub fn create_sample_table(
239239
// ctts_offset is the current sample offset time.
240240
let ctts_offset = ctts_offset_iter.next_offset_time();
241241

242-
let start_composition = track_time_to_us((decode_time + ctts_offset)?, timescale)?;
242+
let start_composition = track_time_to_us((decode_time + ctts_offset)?, timescale)?.0;
243243

244-
let end_composition = track_time_to_us((sum_delta + ctts_offset)?, timescale)?;
244+
let end_composition = track_time_to_us((sum_delta + ctts_offset)?, timescale)?.0;
245245

246-
let start_decode = track_time_to_us(decode_time, timescale)?;
246+
let start_decode = track_time_to_us(decode_time, timescale)?.0;
247247

248248
sample.start_composition = (track_offset_time + start_composition)?;
249249
sample.end_composition = (track_offset_time + end_composition)?;
@@ -490,22 +490,30 @@ where
490490
})
491491
}
492492

493+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
494+
pub struct Microseconds<T>(pub T);
495+
493496
/// Convert `time` in media's global (mvhd) timescale to microseconds,
494497
/// using provided `MediaTimeScale`
495-
pub fn media_time_to_us(time: MediaScaledTime, scale: MediaTimeScale) -> Option<u64> {
498+
pub fn media_time_to_us(time: MediaScaledTime, scale: MediaTimeScale) -> Option<Microseconds<u64>> {
496499
let microseconds_per_second = 1_000_000;
497500
rational_scale::<u64, u64>(time.0, scale.0, microseconds_per_second)
501+
.and_then(|v| Some(Microseconds(v)))
498502
}
499503

500504
/// Convert `time` in track's local (mdhd) timescale to microseconds,
501505
/// using provided `TrackTimeScale<T>`
502-
pub fn track_time_to_us<T>(time: TrackScaledTime<T>, scale: TrackTimeScale<T>) -> Option<T>
506+
pub fn track_time_to_us<T>(
507+
time: TrackScaledTime<T>,
508+
scale: TrackTimeScale<T>,
509+
) -> Option<Microseconds<T>>
503510
where
504511
T: PrimInt + Zero,
505512
{
506513
assert_eq!(time.1, scale.1);
507514
let microseconds_per_second = 1_000_000;
508515
rational_scale::<T, u64>(time.0, scale.0, microseconds_per_second)
516+
.and_then(|v| Some(Microseconds(v)))
509517
}
510518

511519
#[test]
@@ -526,7 +534,7 @@ fn media_time_overflow() {
526534
let duration = MediaScaledTime(9_007_199_254_710_000);
527535
assert_eq!(
528536
media_time_to_us(duration, scale),
529-
Some(100_079_991_719_000_000)
537+
Some(Microseconds(100_079_991_719_000_000u64))
530538
);
531539
}
532540

@@ -536,6 +544,6 @@ fn track_time_overflow() {
536544
let duration = TrackScaledTime(4_413_527_634_807_900u64, 0);
537545
assert_eq!(
538546
track_time_to_us(duration, scale),
539-
Some(100_079_991_719_000_000)
547+
Some(Microseconds(100_079_991_719_000_000u64))
540548
);
541549
}

mp4parse_capi/src/lib.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -621,27 +621,31 @@ pub unsafe extern "C" fn mp4parse_get_track_info(
621621
let track = &context.tracks[track_index];
622622

623623
if let (Some(track_timescale), Some(context_timescale)) = (track.timescale, context.timescale) {
624-
let media_time: CheckedInteger<_> = match track.media_time.map_or(Some(0), |media_time| {
625-
mp4parse::unstable::track_time_to_us(media_time, track_timescale)
626-
}) {
627-
Some(time) => time.into(),
624+
let media_time: CheckedInteger<u64> = match track
625+
.media_time
626+
.map_or(Some(mp4parse::unstable::Microseconds(0)), |media_time| {
627+
mp4parse::unstable::track_time_to_us(media_time, track_timescale)
628+
}) {
629+
Some(time) => time.0.into(),
628630
None => return Mp4parseStatus::Invalid,
629631
};
630-
let empty_duration: CheckedInteger<_> =
631-
match track.empty_duration.map_or(Some(0), |empty_duration| {
632+
let empty_duration: CheckedInteger<u64> = match track.empty_duration.map_or(
633+
Some(mp4parse::unstable::Microseconds(0)),
634+
|empty_duration| {
632635
mp4parse::unstable::media_time_to_us(empty_duration, context_timescale)
633-
}) {
634-
Some(time) => time.into(),
635-
None => return Mp4parseStatus::Invalid,
636-
};
636+
},
637+
) {
638+
Some(time) => time.0.into(),
639+
None => return Mp4parseStatus::Invalid,
640+
};
637641
info.media_time = match media_time - empty_duration {
638642
Some(difference) => difference,
639643
None => return Mp4parseStatus::Invalid,
640644
};
641645

642646
if let Some(track_duration) = track.duration {
643647
match mp4parse::unstable::track_time_to_us(track_duration, track_timescale) {
644-
Some(duration) => info.duration = duration,
648+
Some(duration) => info.duration = duration.0,
645649
None => return Mp4parseStatus::Invalid,
646650
}
647651
} else {
@@ -1111,15 +1115,15 @@ fn get_indice_table(
11111115

11121116
let media_time = match (&track.media_time, &track.timescale) {
11131117
(&Some(t), &Some(s)) => mp4parse::unstable::track_time_to_us(t, s)
1114-
.and_then(|v| i64::try_from(v).ok())
1118+
.and_then(|v| i64::try_from(v.0).ok())
11151119
.map(Into::into),
11161120
_ => None,
11171121
};
11181122

11191123
let empty_duration: Option<CheckedInteger<_>> =
11201124
match (&track.empty_duration, &context.timescale) {
11211125
(&Some(e), &Some(s)) => mp4parse::unstable::media_time_to_us(e, s)
1122-
.and_then(|v| i64::try_from(v).ok())
1126+
.and_then(|v| i64::try_from(v.0).ok())
11231127
.map(Into::into),
11241128
_ => None,
11251129
};
@@ -1176,7 +1180,7 @@ pub unsafe extern "C" fn mp4parse_get_fragment_info(
11761180

11771181
if let (Some(time), Some(scale)) = (duration, context.timescale) {
11781182
info.fragment_duration = match mp4parse::unstable::media_time_to_us(time, scale) {
1179-
Some(time_us) => time_us as u64,
1183+
Some(time_us) => time_us.0 as u64,
11801184
None => return Mp4parseStatus::Invalid,
11811185
}
11821186
}

0 commit comments

Comments
 (0)