Skip to content

Commit 20c6571

Browse files
committed
Limit the allocated size of the sample indice table by the file size.
1 parent f908f80 commit 20c6571

File tree

2 files changed

+48
-8
lines changed

2 files changed

+48
-8
lines changed

mp4parse/src/unstable.rs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44
use num_traits::{CheckedAdd, CheckedSub, PrimInt, Zero};
5-
use std::ops::{Add, Neg, Sub};
5+
use std::{ops::{Add, Neg, Sub}, convert::TryInto};
66

77
use super::*;
88

@@ -139,6 +139,7 @@ pub struct Indice {
139139
pub fn create_sample_table(
140140
track: &Track,
141141
track_offset_time: CheckedInteger<i64>,
142+
optional_available_size: Option<usize>,
142143
) -> Option<TryVec<Indice>> {
143144
let timescale = match track.timescale {
144145
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
@@ -153,16 +154,44 @@ pub fn create_sample_table(
153154
// According to spec, no sync table means every sample is sync sample.
154155
let has_sync_table = matches!(track.stss, Some(_));
155156

156-
let mut sample_size_iter = stsz.sample_sizes.iter();
157-
158157
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
159158
// offset address.
160159

161160
// With large numbers of samples, the cost of many allocations dominates,
162161
// so it's worth iterating twice to allocate sample_table just once.
163-
let total_sample_count = sample_to_chunk_iter(&stsc.samples, &stco.offsets)
164-
.map(|(_, sample_counts)| sample_counts.to_usize())
165-
.try_fold(0usize, usize::checked_add)?;
162+
let total_sample_count = {
163+
let mut sample_size_iter = stsz.sample_sizes.iter();
164+
let mut sample_number: usize = 0;
165+
for (chunk_id, sample_counts) in sample_to_chunk_iter(&stsc.samples, &stco.offsets) {
166+
match optional_available_size {
167+
Some(available_size) => {
168+
let mut end_offset = match stco.offsets.get(chunk_id as usize) {
169+
Some(v) => *v as usize,
170+
None => return None,
171+
};
172+
for _ in 0..sample_counts {
173+
match (stsz.sample_size, sample_size_iter.next()) {
174+
(_, Some(single_sample_size)) => end_offset += *single_sample_size as usize,
175+
(sample_size, _) if sample_size > 0 => end_offset += sample_size as usize,
176+
_ => return None,
177+
}
178+
if end_offset > available_size {
179+
break;
180+
}
181+
sample_number = match sample_number.checked_add(1) {
182+
Some(v) => v,
183+
None => return None,
184+
};
185+
}
186+
}
187+
None => sample_number += sample_counts as usize,
188+
}
189+
}
190+
sample_number
191+
};
192+
193+
let mut sample_size_iter = stsz.sample_sizes.iter();
194+
166195
let mut sample_table = TryVec::with_capacity(total_sample_count).ok()?;
167196

168197
for i in sample_to_chunk_iter(&stsc.samples, &stco.offsets) {
@@ -174,11 +203,15 @@ pub fn create_sample_table(
174203
};
175204
for _ in 0..sample_counts {
176205
let start_offset = cur_position;
177-
let end_offset = match (stsz.sample_size, sample_size_iter.next()) {
206+
let end_offset: CheckedInteger<u64> = match (stsz.sample_size, sample_size_iter.next()) {
178207
(_, Some(t)) => (start_offset + *t)?,
179208
(t, _) if t > 0 => (start_offset + t)?,
180209
_ => 0.into(),
181210
};
211+
match optional_available_size.map(TryInto::try_into).and_then(Result::ok) {
212+
Some(available_size) if end_offset.0 > available_size => continue,
213+
_ => (),
214+
}
182215
if end_offset == 0 {
183216
return None;
184217
}

mp4parse_capi/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,7 @@ pub unsafe extern "C" fn mp4parse_get_indice_table(
12951295
&(*parser).context,
12961296
&mut (*parser).sample_table,
12971297
track_id,
1298+
None,
12981299
&mut *indices,
12991300
)
13001301
.into()
@@ -1312,6 +1313,7 @@ pub unsafe extern "C" fn mp4parse_get_indice_table(
13121313
pub unsafe extern "C" fn mp4parse_avif_get_indice_table(
13131314
parser: *mut Mp4parseAvifParser,
13141315
track_id: u32,
1316+
available_size: usize,
13151317
indices: *mut Mp4parseByteData,
13161318
) -> Mp4parseStatus {
13171319
if parser.is_null() {
@@ -1330,6 +1332,10 @@ pub unsafe extern "C" fn mp4parse_avif_get_indice_table(
13301332
sequence,
13311333
&mut (*parser).sample_table,
13321334
track_id,
1335+
match available_size {
1336+
0 => None,
1337+
_ => Some(available_size),
1338+
},
13331339
&mut *indices,
13341340
)
13351341
.into();
@@ -1342,6 +1348,7 @@ fn get_indice_table(
13421348
context: &MediaContext,
13431349
sample_table_cache: &mut TryHashMap<u32, TryVec<Indice>>,
13441350
track_id: u32,
1351+
available_size: Option<usize>,
13451352
indices: &mut Mp4parseByteData,
13461353
) -> Result<(), Mp4parseStatus> {
13471354
let tracks = &context.tracks;
@@ -1380,7 +1387,7 @@ fn get_indice_table(
13801387
_ => 0.into(),
13811388
};
13821389

1383-
if let Some(v) = create_sample_table(track, offset_time) {
1390+
if let Some(v) = create_sample_table(track, offset_time, available_size) {
13841391
indices.set_indices(&v);
13851392
sample_table_cache.insert(track_id, v)?;
13861393
return Ok(());

0 commit comments

Comments
 (0)