@@ -43,6 +43,7 @@ use byteorder::WriteBytesExt;
43
43
use num:: { CheckedAdd , CheckedSub } ;
44
44
use num:: { PrimInt , Zero } ;
45
45
use std:: convert:: TryFrom ;
46
+ use std:: convert:: TryInto ;
46
47
47
48
use std:: io:: Read ;
48
49
use std:: ops:: Neg ;
@@ -60,6 +61,7 @@ use mp4parse::MediaContext;
60
61
use mp4parse:: MediaScaledTime ;
61
62
use mp4parse:: MediaTimeScale ;
62
63
use mp4parse:: SampleEntry ;
64
+ use mp4parse:: ToUsize ;
63
65
use mp4parse:: Track ;
64
66
use mp4parse:: TrackScaledTime ;
65
67
use mp4parse:: TrackTimeScale ;
@@ -1385,6 +1387,21 @@ impl<'a> TimeToSampleIterator<'a> {
1385
1387
// For example:
1386
1388
// (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10),
1387
1389
// (7, 10), (8, 10), (9, 2)
1390
+ fn sample_to_chunk_iter < ' a > (
1391
+ stsc_samples : & ' a TryVec < mp4parse:: SampleToChunk > ,
1392
+ stco_offsets : & ' a TryVec < u64 > ,
1393
+ ) -> SampleToChunkIterator < ' a > {
1394
+ SampleToChunkIterator {
1395
+ chunks : ( 0 ..0 ) ,
1396
+ sample_count : 0 ,
1397
+ stsc_peek_iter : stsc_samples. as_slice ( ) . iter ( ) . peekable ( ) ,
1398
+ remain_chunk_count : stco_offsets
1399
+ . len ( )
1400
+ . try_into ( )
1401
+ . expect ( "stco.entry_count is u32" ) ,
1402
+ }
1403
+ }
1404
+
1388
1405
struct SampleToChunkIterator < ' a > {
1389
1406
chunks : std:: ops:: Range < u32 > ,
1390
1407
sample_count : u32 ,
@@ -1399,7 +1416,12 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
1399
1416
let has_chunk = self . chunks . next ( ) . or_else ( || {
1400
1417
self . chunks = self . locate ( ) ;
1401
1418
self . remain_chunk_count
1402
- . checked_sub ( self . chunks . len ( ) as u32 )
1419
+ . checked_sub (
1420
+ self . chunks
1421
+ . len ( )
1422
+ . try_into ( )
1423
+ . expect ( "len() of a Range<u32> must fit in u32" ) ,
1424
+ )
1403
1425
. and_then ( |res| {
1404
1426
self . remain_chunk_count = res;
1405
1427
self . chunks . next ( )
@@ -1460,19 +1482,20 @@ fn create_sample_table(
1460
1482
_ => false ,
1461
1483
} ;
1462
1484
1463
- let mut sample_table = TryVec :: new ( ) ;
1464
1485
let mut sample_size_iter = stsz. sample_sizes . iter ( ) ;
1465
1486
1466
1487
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
1467
1488
// offset address.
1468
- let stsc_iter = SampleToChunkIterator {
1469
- chunks : ( 0 ..0 ) ,
1470
- sample_count : 0 ,
1471
- stsc_peek_iter : stsc. samples . as_slice ( ) . iter ( ) . peekable ( ) ,
1472
- remain_chunk_count : stco. offsets . len ( ) as u32 ,
1473
- } ;
1474
1489
1475
- for i in stsc_iter {
1490
+ // With large numbers of samples, the cost of many allocations dominates,
1491
+ // so it's worth iterating twice to allocate sample_table just once.
1492
+ let total_sample_count = sample_to_chunk_iter ( & stsc. samples , & stco. offsets )
1493
+ . by_ref ( )
1494
+ . map ( |( _, sample_counts) | sample_counts. to_usize ( ) )
1495
+ . sum ( ) ;
1496
+ let mut sample_table = TryVec :: with_capacity ( total_sample_count) . ok ( ) ?;
1497
+
1498
+ for i in sample_to_chunk_iter ( & stsc. samples , & stco. offsets ) {
1476
1499
let chunk_id = i. 0 as usize ;
1477
1500
let sample_counts = i. 1 ;
1478
1501
let mut cur_position = match stco. offsets . get ( chunk_id) {
@@ -1565,7 +1588,8 @@ fn create_sample_table(
1565
1588
// calculate to correct the composition end time.
1566
1589
if !sample_table. is_empty ( ) {
1567
1590
// Create an index table refers to sample_table and sorted by start_composisiton time.
1568
- let mut sort_table = TryVec :: new ( ) ;
1591
+ let mut sort_table = TryVec :: with_capacity ( sample_table. len ( ) ) . ok ( ) ?;
1592
+
1569
1593
for i in 0 ..sample_table. len ( ) {
1570
1594
sort_table. push ( i) . ok ( ) ?;
1571
1595
}
0 commit comments