Skip to content

Commit 5f779a9

Browse files
committed
Improve create_sample_table performance by preallocating sample storage
This is necessary to prevent timeouts when fuzzing on large inputs. See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24709
1 parent 7f33add commit 5f779a9

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
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: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use mp4parse::MediaContext;
6060
use mp4parse::MediaScaledTime;
6161
use mp4parse::MediaTimeScale;
6262
use mp4parse::SampleEntry;
63+
use mp4parse::ToUsize;
6364
use mp4parse::Track;
6465
use mp4parse::TrackScaledTime;
6566
use mp4parse::TrackTimeScale;
@@ -1385,6 +1386,18 @@ impl<'a> TimeToSampleIterator<'a> {
13851386
// For example:
13861387
// (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10),
13871388
// (7, 10), (8, 10), (9, 2)
1389+
fn sample_to_chunk_iter<'a>(
1390+
stsc_samples: &'a TryVec<mp4parse::SampleToChunk>,
1391+
stco_offsets: &'a TryVec<u64>,
1392+
) -> SampleToChunkIterator<'a> {
1393+
SampleToChunkIterator {
1394+
chunks: (0..0),
1395+
sample_count: 0,
1396+
stsc_peek_iter: stsc_samples.as_slice().iter().peekable(),
1397+
remain_chunk_count: stco_offsets.len() as u32,
1398+
}
1399+
}
1400+
13881401
struct SampleToChunkIterator<'a> {
13891402
chunks: std::ops::Range<u32>,
13901403
sample_count: u32,
@@ -1460,19 +1473,20 @@ fn create_sample_table(
14601473
_ => false,
14611474
};
14621475

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

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

1475-
for i in stsc_iter {
1481+
// With large numbers of samples, the cost of many allocations dominates,
1482+
// so it's worth iterating twice to allocate sample_table just once.
1483+
let total_sample_count = sample_to_chunk_iter(&stsc.samples, &stco.offsets)
1484+
.by_ref()
1485+
.map(|(_, sample_counts)| sample_counts.to_usize())
1486+
.sum();
1487+
let mut sample_table = TryVec::with_capacity(total_sample_count).ok()?;
1488+
1489+
for i in sample_to_chunk_iter(&stsc.samples, &stco.offsets) {
14761490
let chunk_id = i.0 as usize;
14771491
let sample_counts = i.1;
14781492
let mut cur_position = match stco.offsets.get(chunk_id) {
@@ -1565,7 +1579,8 @@ fn create_sample_table(
15651579
// calculate to correct the composition end time.
15661580
if !sample_table.is_empty() {
15671581
// Create an index table refers to sample_table and sorted by start_composisiton time.
1568-
let mut sort_table = TryVec::new();
1582+
let mut sort_table = TryVec::with_capacity(sample_table.len()).ok()?;
1583+
15691584
for i in 0..sample_table.len() {
15701585
sort_table.push(i).ok()?;
15711586
}

0 commit comments

Comments
 (0)