Skip to content

Commit 4499bc5

Browse files
alfredoyangkinetiknz
alfredoyang
authored andcommitted
let TrackScaledTime and TrackTimeScale be generic for sign/unsign problem.
1 parent 63ad36d commit 4499bc5

File tree

4 files changed

+81
-53
lines changed

4 files changed

+81
-53
lines changed

mp4parse/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ afl = { version = "0.1.1", optional = true }
2828
afl-plugin = { version = "0.1.1", optional = true }
2929
abort_on_panic = { version = "1.0.0", optional = true }
3030
bitreader = { version = "0.3.0" }
31+
num-traits = "0.1.37"
3132

3233
[dev-dependencies]
3334
test-assembler = "0.1.2"

mp4parse/src/lib.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ extern crate afl;
1010

1111
extern crate byteorder;
1212
extern crate bitreader;
13+
extern crate num_traits;
1314
use byteorder::{ReadBytesExt, WriteBytesExt};
1415
use bitreader::{BitReader, ReadInto};
1516
use std::io::{Read, Take};
1617
use std::io::Cursor;
1718
use std::cmp;
19+
use num_traits::Num;
1820

1921
mod boxes;
2022
use boxes::{BoxType, FourCC};
@@ -406,12 +408,20 @@ pub struct MediaScaledTime(pub u64);
406408
/// The track's local (mdhd) timescale.
407409
/// Members are timescale units per second and the track id.
408410
#[derive(Debug, Copy, Clone, PartialEq)]
409-
pub struct TrackTimeScale(pub u64, pub usize);
411+
pub struct TrackTimeScale<T: Num>(pub T, pub usize);
410412

411413
/// A time to be scaled by the track's local (mdhd) timescale.
412414
/// Members are time in scale units and the track id.
413415
#[derive(Debug, Copy, Clone, PartialEq)]
414-
pub struct TrackScaledTime(pub u64, pub usize);
416+
pub struct TrackScaledTime<T: Num>(pub T, pub usize);
417+
418+
impl <T> std::ops::Add for TrackScaledTime<T> where T: Num {
419+
type Output = TrackScaledTime<T>;
420+
421+
fn add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T> {
422+
TrackScaledTime::<T>(self.0 + other.0, self.1)
423+
}
424+
}
415425

416426
/// A fragmented file contains no sample data in stts, stsc, and stco.
417427
#[derive(Debug, Default)]
@@ -431,12 +441,12 @@ impl EmptySampleTableBoxes {
431441

432442
#[derive(Debug, Default)]
433443
pub struct Track {
434-
id: usize,
444+
pub id: usize,
435445
pub track_type: TrackType,
436446
pub empty_duration: Option<MediaScaledTime>,
437-
pub media_time: Option<TrackScaledTime>,
438-
pub timescale: Option<TrackTimeScale>,
439-
pub duration: Option<TrackScaledTime>,
447+
pub media_time: Option<TrackScaledTime<u64>>,
448+
pub timescale: Option<TrackTimeScale<u64>>,
449+
pub duration: Option<TrackScaledTime<u64>>,
440450
pub track_id: Option<u32>,
441451
pub codec_type: CodecType,
442452
pub empty_sample_boxes: EmptySampleTableBoxes,
@@ -793,7 +803,7 @@ fn read_edts<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
793803
if elst.edits[idx].media_time < 0 {
794804
return Err(Error::InvalidData("unexpected negative media time in edit"));
795805
}
796-
track.media_time = Some(TrackScaledTime(elst.edits[idx].media_time as u64,
806+
track.media_time = Some(TrackScaledTime::<u64>(elst.edits[idx].media_time as u64,
797807
track.id));
798808
log!("{:?}", elst);
799809
}
@@ -804,16 +814,16 @@ fn read_edts<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
804814
Ok(())
805815
}
806816

807-
fn parse_mdhd<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<(MediaHeaderBox, Option<TrackScaledTime>, Option<TrackTimeScale>)> {
817+
fn parse_mdhd<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<(MediaHeaderBox, Option<TrackScaledTime<u64>>, Option<TrackTimeScale<u64>>)> {
808818
let mdhd = read_mdhd(f)?;
809819
let duration = match mdhd.duration {
810820
std::u64::MAX => None,
811-
duration => Some(TrackScaledTime(duration, track.id)),
821+
duration => Some(TrackScaledTime::<u64>(duration, track.id)),
812822
};
813823
if mdhd.timescale == 0 {
814824
return Err(Error::InvalidData("zero timescale in mdhd"));
815825
}
816-
let timescale = Some(TrackTimeScale(mdhd.timescale as u64, track.id));
826+
let timescale = Some(TrackTimeScale::<u64>(mdhd.timescale as u64, track.id));
817827
Ok((mdhd, duration, timescale))
818828
}
819829

mp4parse_capi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
2626
[dependencies]
2727
byteorder = "1.0.0"
2828
mp4parse = {version = "0.7.1", path = "../mp4parse"}
29+
num-traits = "0.1.37"
2930

3031
[build-dependencies]
3132
rusty-cheddar = "0.3.2"

mp4parse_capi/src/lib.rs

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636

3737
extern crate mp4parse;
3838
extern crate byteorder;
39+
extern crate num_traits;
3940

4041
use std::io::Read;
4142
use std::collections::HashMap;
4243
use byteorder::WriteBytesExt;
44+
use num_traits::{PrimInt, Zero};
4345

4446
// Symbols we need from our rust api.
4547
use mp4parse::MediaContext;
@@ -374,37 +376,33 @@ pub unsafe extern fn mp4parse_get_track_count(parser: *const mp4parse_parser, co
374376
/// (n * s) / d is split into floor(n / d) * s + (n % d) * s / d.
375377
///
376378
/// Return None on overflow or if the denominator is zero.
377-
fn rational_scale(numerator: u64, denominator: u64, scale: u64) -> Option<u64> {
378-
if denominator == 0 {
379+
fn rational_scale<T, S>(numerator: T, denominator: T, scale2: S) -> Option<T>
380+
where T: PrimInt + Zero, S: PrimInt {
381+
if denominator.is_zero() {
379382
return None;
380383
}
384+
381385
let integer = numerator / denominator;
382386
let remainder = numerator % denominator;
383-
match integer.checked_mul(scale) {
384-
Some(integer) => remainder.checked_mul(scale)
385-
.and_then(|remainder| (remainder/denominator).checked_add(integer)),
386-
None => None,
387-
}
387+
num_traits::cast(scale2).and_then(|s| {
388+
match integer.checked_mul(&s) {
389+
Some(integer) => remainder.checked_mul(&s)
390+
.and_then(|remainder| (remainder/denominator).checked_add(&integer)),
391+
None => None,
392+
}
393+
})
388394
}
389395

390396
fn media_time_to_us(time: MediaScaledTime, scale: MediaTimeScale) -> Option<u64> {
391397
let microseconds_per_second = 1000000;
392-
rational_scale(time.0, scale.0, microseconds_per_second)
398+
rational_scale::<u64, u64>(time.0, scale.0, microseconds_per_second)
393399
}
394400

395-
fn track_time_to_us(time: TrackScaledTime, scale: TrackTimeScale) -> Option<u64> {
401+
fn track_time_to_us<T>(time: TrackScaledTime<T>, scale: TrackTimeScale<T>) -> Option<T>
402+
where T: PrimInt + Zero {
396403
assert_eq!(time.1, scale.1);
397404
let microseconds_per_second = 1000000;
398-
rational_scale(time.0, scale.0, microseconds_per_second)
399-
}
400-
401-
fn get_track_time_to_us(time: i64, scale: TrackTimeScale) -> i64 {
402-
assert!(time >= 0);
403-
let track_time = TrackScaledTime(time as u64, scale.1);
404-
match track_time_to_us(track_time, scale) {
405-
Some(v) => v as i64,
406-
_ => 0,
407-
}
405+
rational_scale::<T, u64>(time.0, scale.0, microseconds_per_second)
408406
}
409407

410408
/// Fill the supplied `mp4parse_track_info` with metadata for `track`.
@@ -732,6 +730,7 @@ struct TimeOffsetIterator<'a> {
732730
cur_sample_range: std::ops::Range<u32>,
733731
cur_offset: i64,
734732
ctts_iter: Option<std::slice::Iter<'a, mp4parse::TimeOffset>>,
733+
track_id: usize,
735734
}
736735

737736
impl<'a> Iterator for TimeOffsetIterator<'a> {
@@ -770,10 +769,10 @@ impl<'a> Iterator for TimeOffsetIterator<'a> {
770769
}
771770

772771
impl<'a> TimeOffsetIterator<'a> {
773-
fn next_offset_time(&mut self) -> i64 {
772+
fn next_offset_time(&mut self) -> TrackScaledTime<i64> {
774773
match self.next() {
775-
Some(v) => v as i64,
776-
_ => 0,
774+
Some(v) => TrackScaledTime::<i64>(v as i64, self.track_id),
775+
_ => TrackScaledTime::<i64>(0, self.track_id),
777776
}
778777
}
779778
}
@@ -788,6 +787,7 @@ struct TimeToSampleIteraor<'a> {
788787
cur_sample_count: std::ops::Range<u32>,
789788
cur_sample_delta: u32,
790789
stts_iter: std::slice::Iter<'a, mp4parse::Sample>,
790+
track_id: usize,
791791
}
792792

793793
impl<'a> Iterator for TimeToSampleIteraor<'a> {
@@ -812,10 +812,10 @@ impl<'a> Iterator for TimeToSampleIteraor<'a> {
812812
}
813813

814814
impl<'a> TimeToSampleIteraor<'a> {
815-
fn next_delta(&mut self) -> u32 {
815+
fn next_delta(&mut self) -> TrackScaledTime<i64> {
816816
match self.next() {
817-
Some(v) => v,
818-
_ => 0,
817+
Some(v) => TrackScaledTime::<i64>(v as i64, self.track_id),
818+
_ => TrackScaledTime::<i64>(0, self.track_id),
819819
}
820820
}
821821
}
@@ -867,8 +867,8 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
867867

868868
fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<mp4parse_indice>> {
869869
let timescale = match track.timescale {
870-
Some(t) => t,
871-
_ => return None,
870+
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
871+
_ => TrackTimeScale::<i64>(0, 0),
872872
};
873873

874874
let (stsc, stco, stsz, stts) =
@@ -943,12 +943,14 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<mp4p
943943
cur_sample_range: (0 .. 0),
944944
cur_offset: 0,
945945
ctts_iter: ctts_iter,
946+
track_id: track.id,
946947
};
947948

948949
let mut stts_iter = TimeToSampleIteraor {
949950
cur_sample_count: (0 .. 0),
950951
cur_sample_delta: 0,
951952
stts_iter: stts.samples.as_slice().iter(),
953+
track_id: track.id,
952954
};
953955

954956
// sum_delta is the sum of stts_iter delta.
@@ -957,24 +959,38 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<mp4p
957959
// composition time => CT(n) = DT(n) + CTTS(n)
958960
// Note:
959961
// composition time needs to add the track offset time from 'elst' table.
960-
let mut sum_delta = 0;
962+
let mut sum_delta = TrackScaledTime::<i64>(0, track.id);
961963
for sample in sample_table.as_mut_slice() {
962964
let decode_time = sum_delta;
963-
sum_delta += stts_iter.next_delta() as i64;
965+
sum_delta = sum_delta + stts_iter.next_delta();
964966

965967
// ctts_offset is the current sample offset time.
966968
let ctts_offset = ctts_offset_iter.next_offset_time();
967969

968970
// ctts_offset could be negative but (decode_time + ctts_offset) should always be positive
969971
// value.
970-
let start_composition = get_track_time_to_us(decode_time + ctts_offset, timescale) + track_offset_time;
972+
let start_composition = track_time_to_us(decode_time + ctts_offset, timescale).and_then(|t| {
973+
if t < 0 { return None; }
974+
Some(t)
975+
});
976+
971977
// ctts_offset could be negative but (sum_delta + ctts_offset) should always be positive
972978
// value.
973-
let end_composition = get_track_time_to_us(sum_delta + ctts_offset, timescale) + track_offset_time;
979+
let end_composition = track_time_to_us(sum_delta + ctts_offset, timescale).and_then(|t| {
980+
if t < 0 { return None; }
981+
Some(t)
982+
});
983+
984+
let start_decode = track_time_to_us(decode_time, timescale);
974985

975-
sample.start_decode = get_track_time_to_us(decode_time, timescale);;
976-
sample.start_composition = start_composition;
977-
sample.end_composition = end_composition;
986+
match (start_composition, end_composition, start_decode) {
987+
(Some(s_c), Some(e_c), Some(s_d)) => {
988+
sample.start_composition = s_c + track_offset_time;
989+
sample.end_composition = e_c + track_offset_time;
990+
sample.start_decode = s_d;
991+
},
992+
_ => return None,
993+
}
978994
}
979995

980996
// Correct composition end time due to 'ctts' causes composition time re-ordering.
@@ -1379,14 +1395,14 @@ fn arg_validation_with_data() {
13791395

13801396
#[test]
13811397
fn rational_scale_overflow() {
1382-
assert_eq!(rational_scale(17, 3, 1000), Some(5666));
1398+
assert_eq!(rational_scale::<u64, u64>(17, 3, 1000), Some(5666));
13831399
let large = 0x4000_0000_0000_0000;
1384-
assert_eq!(rational_scale(large, 2, 2), Some(large));
1385-
assert_eq!(rational_scale(large, 4, 4), Some(large));
1386-
assert_eq!(rational_scale(large, 2, 8), None);
1387-
assert_eq!(rational_scale(large, 8, 4), Some(large/2));
1388-
assert_eq!(rational_scale(large + 1, 4, 4), Some(large+1));
1389-
assert_eq!(rational_scale(large, 40, 1000), None);
1400+
assert_eq!(rational_scale::<u64, u64>(large, 2, 2), Some(large));
1401+
assert_eq!(rational_scale::<u64, u64>(large, 4, 4), Some(large));
1402+
assert_eq!(rational_scale::<u64, u64>(large, 2, 8), None);
1403+
assert_eq!(rational_scale::<u64, u64>(large, 8, 4), Some(large/2));
1404+
assert_eq!(rational_scale::<u64, u64>(large + 1, 4, 4), Some(large+1));
1405+
assert_eq!(rational_scale::<u64, u64>(large, 40, 1000), None);
13901406
}
13911407

13921408
#[test]
@@ -1398,7 +1414,7 @@ fn media_time_overflow() {
13981414

13991415
#[test]
14001416
fn track_time_overflow() {
1401-
let scale = TrackTimeScale(44100, 0);
1402-
let duration = TrackScaledTime(4413527634807900, 0);
1417+
let scale = TrackTimeScale(44100 as u64, 0);
1418+
let duration = TrackScaledTime(4413527634807900 as u64, 0);
14031419
assert_eq!(track_time_to_us(duration, scale), Some(100079991719000000));
14041420
}

0 commit comments

Comments
 (0)