Skip to content

Commit b715d07

Browse files
authored
Merge pull request #234 from mozilla/create_sample_table-prealloc
Preallocate storage in create_sample_table
2 parents 7f33add + ce49670 commit b715d07

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

mp4parse/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl ToU64 for usize {
5858

5959
/// A trait to indicate a type can be infallibly converted to `usize`.
6060
/// This should only be implemented for infallible conversions, so only unsigned types are valid.
61-
trait ToUsize {
61+
pub trait ToUsize {
6262
fn to_usize(self) -> usize;
6363
}
6464

mp4parse_capi/src/lib.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use byteorder::WriteBytesExt;
4343
use num::{CheckedAdd, CheckedSub};
4444
use num::{PrimInt, Zero};
4545
use std::convert::TryFrom;
46+
use std::convert::TryInto;
4647

4748
use std::io::Read;
4849
use std::ops::Neg;
@@ -60,6 +61,7 @@ use mp4parse::MediaContext;
6061
use mp4parse::MediaScaledTime;
6162
use mp4parse::MediaTimeScale;
6263
use mp4parse::SampleEntry;
64+
use mp4parse::ToUsize;
6365
use mp4parse::Track;
6466
use mp4parse::TrackScaledTime;
6567
use mp4parse::TrackTimeScale;
@@ -1385,6 +1387,21 @@ impl<'a> TimeToSampleIterator<'a> {
13851387
// For example:
13861388
// (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10),
13871389
// (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+
13881405
struct SampleToChunkIterator<'a> {
13891406
chunks: std::ops::Range<u32>,
13901407
sample_count: u32,
@@ -1399,7 +1416,12 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
13991416
let has_chunk = self.chunks.next().or_else(|| {
14001417
self.chunks = self.locate();
14011418
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+
)
14031425
.and_then(|res| {
14041426
self.remain_chunk_count = res;
14051427
self.chunks.next()
@@ -1460,19 +1482,20 @@ fn create_sample_table(
14601482
_ => false,
14611483
};
14621484

1463-
let mut sample_table = TryVec::new();
14641485
let mut sample_size_iter = stsz.sample_sizes.iter();
14651486

14661487
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
14671488
// 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-
};
14741489

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) {
14761499
let chunk_id = i.0 as usize;
14771500
let sample_counts = i.1;
14781501
let mut cur_position = match stco.offsets.get(chunk_id) {
@@ -1565,7 +1588,8 @@ fn create_sample_table(
15651588
// calculate to correct the composition end time.
15661589
if !sample_table.is_empty() {
15671590
// 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+
15691593
for i in 0..sample_table.len() {
15701594
sort_table.push(i).ok()?;
15711595
}

0 commit comments

Comments
 (0)