36
36
37
37
extern crate mp4parse;
38
38
extern crate byteorder;
39
+ extern crate num_traits;
39
40
40
41
use std:: io:: Read ;
41
42
use std:: collections:: HashMap ;
42
43
use byteorder:: WriteBytesExt ;
44
+ use num_traits:: { PrimInt , Zero } ;
43
45
44
46
// Symbols we need from our rust api.
45
47
use mp4parse:: MediaContext ;
@@ -374,37 +376,33 @@ pub unsafe extern fn mp4parse_get_track_count(parser: *const mp4parse_parser, co
374
376
/// (n * s) / d is split into floor(n / d) * s + (n % d) * s / d.
375
377
///
376
378
/// 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 ( ) {
379
382
return None ;
380
383
}
384
+
381
385
let integer = numerator / denominator;
382
386
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
+ } )
388
394
}
389
395
390
396
fn media_time_to_us ( time : MediaScaledTime , scale : MediaTimeScale ) -> Option < u64 > {
391
397
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)
393
399
}
394
400
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 {
396
403
assert_eq ! ( time. 1 , scale. 1 ) ;
397
404
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)
408
406
}
409
407
410
408
/// Fill the supplied `mp4parse_track_info` with metadata for `track`.
@@ -732,6 +730,7 @@ struct TimeOffsetIterator<'a> {
732
730
cur_sample_range : std:: ops:: Range < u32 > ,
733
731
cur_offset : i64 ,
734
732
ctts_iter : Option < std:: slice:: Iter < ' a , mp4parse:: TimeOffset > > ,
733
+ track_id : usize ,
735
734
}
736
735
737
736
impl < ' a > Iterator for TimeOffsetIterator < ' a > {
@@ -770,10 +769,10 @@ impl<'a> Iterator for TimeOffsetIterator<'a> {
770
769
}
771
770
772
771
impl < ' a > TimeOffsetIterator < ' a > {
773
- fn next_offset_time ( & mut self ) -> i64 {
772
+ fn next_offset_time ( & mut self ) -> TrackScaledTime < i64 > {
774
773
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 ) ,
777
776
}
778
777
}
779
778
}
@@ -788,6 +787,7 @@ struct TimeToSampleIteraor<'a> {
788
787
cur_sample_count : std:: ops:: Range < u32 > ,
789
788
cur_sample_delta : u32 ,
790
789
stts_iter : std:: slice:: Iter < ' a , mp4parse:: Sample > ,
790
+ track_id : usize ,
791
791
}
792
792
793
793
impl < ' a > Iterator for TimeToSampleIteraor < ' a > {
@@ -812,10 +812,10 @@ impl<'a> Iterator for TimeToSampleIteraor<'a> {
812
812
}
813
813
814
814
impl < ' a > TimeToSampleIteraor < ' a > {
815
- fn next_delta ( & mut self ) -> u32 {
815
+ fn next_delta ( & mut self ) -> TrackScaledTime < i64 > {
816
816
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 ) ,
819
819
}
820
820
}
821
821
}
@@ -867,8 +867,8 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
867
867
868
868
fn create_sample_table ( track : & Track , track_offset_time : i64 ) -> Option < Vec < mp4parse_indice > > {
869
869
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 ) ,
872
872
} ;
873
873
874
874
let ( stsc, stco, stsz, stts) =
@@ -943,12 +943,14 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<mp4p
943
943
cur_sample_range : ( 0 .. 0 ) ,
944
944
cur_offset : 0 ,
945
945
ctts_iter : ctts_iter,
946
+ track_id : track. id ,
946
947
} ;
947
948
948
949
let mut stts_iter = TimeToSampleIteraor {
949
950
cur_sample_count : ( 0 .. 0 ) ,
950
951
cur_sample_delta : 0 ,
951
952
stts_iter : stts. samples . as_slice ( ) . iter ( ) ,
953
+ track_id : track. id ,
952
954
} ;
953
955
954
956
// 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
957
959
// composition time => CT(n) = DT(n) + CTTS(n)
958
960
// Note:
959
961
// 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 ) ;
961
963
for sample in sample_table. as_mut_slice ( ) {
962
964
let decode_time = sum_delta;
963
- sum_delta += stts_iter. next_delta ( ) as i64 ;
965
+ sum_delta = sum_delta + stts_iter. next_delta ( ) ;
964
966
965
967
// ctts_offset is the current sample offset time.
966
968
let ctts_offset = ctts_offset_iter. next_offset_time ( ) ;
967
969
968
970
// ctts_offset could be negative but (decode_time + ctts_offset) should always be positive
969
971
// 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
+
971
977
// ctts_offset could be negative but (sum_delta + ctts_offset) should always be positive
972
978
// 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) ;
974
985
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
+ }
978
994
}
979
995
980
996
// Correct composition end time due to 'ctts' causes composition time re-ordering.
@@ -1379,14 +1395,14 @@ fn arg_validation_with_data() {
1379
1395
1380
1396
#[ test]
1381
1397
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 ) ) ;
1383
1399
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 ) ;
1390
1406
}
1391
1407
1392
1408
#[ test]
@@ -1398,7 +1414,7 @@ fn media_time_overflow() {
1398
1414
1399
1415
#[ test]
1400
1416
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 ) ;
1403
1419
assert_eq ! ( track_time_to_us( duration, scale) , Some ( 100079991719000000 ) ) ;
1404
1420
}
0 commit comments