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/.
44use num_traits:: { CheckedAdd , CheckedSub , PrimInt , Zero } ;
5- use std:: ops:: { Add , Neg , Sub } ;
5+ use std:: {
6+ convert:: TryInto ,
7+ ops:: { Add , Neg , Sub } ,
8+ } ;
69
710use super :: * ;
811
@@ -139,6 +142,7 @@ pub struct Indice {
139142pub fn create_sample_table (
140143 track : & Track ,
141144 track_offset_time : CheckedInteger < i64 > ,
145+ optional_available_size : Option < usize > ,
142146) -> Option < TryVec < Indice > > {
143147 let timescale = match track. timescale {
144148 Some ( ref t) => TrackTimeScale :: < i64 > ( t. 0 as i64 , t. 1 ) ,
@@ -153,16 +157,48 @@ pub fn create_sample_table(
153157 // According to spec, no sync table means every sample is sync sample.
154158 let has_sync_table = matches ! ( track. stss, Some ( _) ) ;
155159
156- let mut sample_size_iter = stsz. sample_sizes . iter ( ) ;
157-
158160 // Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
159161 // offset address.
160162
161163 // With large numbers of samples, the cost of many allocations dominates,
162164 // 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) ?;
165+ let total_sample_count = {
166+ let mut sample_size_iter = stsz. sample_sizes . iter ( ) ;
167+ let mut sample_number: usize = 0 ;
168+ for ( chunk_id, sample_counts) in sample_to_chunk_iter ( & stsc. samples , & stco. offsets ) {
169+ match optional_available_size {
170+ Some ( available_size) => {
171+ let mut end_offset = match stco. offsets . get ( chunk_id as usize ) {
172+ Some ( v) => * v as usize ,
173+ None => return None ,
174+ } ;
175+ for _ in 0 ..sample_counts {
176+ match ( stsz. sample_size , sample_size_iter. next ( ) ) {
177+ ( _, Some ( single_sample_size) ) => {
178+ end_offset += * single_sample_size as usize
179+ }
180+ ( sample_size, _) if sample_size > 0 => {
181+ end_offset += sample_size as usize
182+ }
183+ _ => return None ,
184+ }
185+ if end_offset > available_size {
186+ break ;
187+ }
188+ sample_number = match sample_number. checked_add ( 1 ) {
189+ Some ( v) => v,
190+ None => return None ,
191+ } ;
192+ }
193+ }
194+ None => sample_number += sample_counts as usize ,
195+ }
196+ }
197+ sample_number
198+ } ;
199+
200+ let mut sample_size_iter = stsz. sample_sizes . iter ( ) ;
201+
166202 let mut sample_table = TryVec :: with_capacity ( total_sample_count) . ok ( ) ?;
167203
168204 for i in sample_to_chunk_iter ( & stsc. samples , & stco. offsets ) {
@@ -174,11 +210,19 @@ pub fn create_sample_table(
174210 } ;
175211 for _ in 0 ..sample_counts {
176212 let start_offset = cur_position;
177- let end_offset = match ( stsz. sample_size , sample_size_iter. next ( ) ) {
213+ let end_offset: CheckedInteger < u64 > = match ( stsz. sample_size , sample_size_iter. next ( ) )
214+ {
178215 ( _, Some ( t) ) => ( start_offset + * t) ?,
179216 ( t, _) if t > 0 => ( start_offset + t) ?,
180217 _ => 0 . into ( ) ,
181218 } ;
219+ match optional_available_size
220+ . map ( TryInto :: try_into)
221+ . and_then ( Result :: ok)
222+ {
223+ Some ( available_size) if end_offset. 0 > available_size => break ,
224+ _ => ( ) ,
225+ }
182226 if end_offset == 0 {
183227 return None ;
184228 }
0 commit comments