@@ -46,9 +46,9 @@ impl Default for MediaSourceStreamOptions {
4646/// excess data buffered on consecutive `seek()` calls.
4747///
4848/// Second, to better support non-seekable sources, `MediaSourceStream` implements a configurable
49- /// length buffer cache . By default, the buffer caches allows backtracking by up-to the minimum of
50- /// either `buffer_len - 32kB` or the total number of bytes read since instantiation or the last
51- /// buffer cache invalidation. Note that regular a `seek()` will invalidate the buffer cache .
49+ /// length buffer. By default, the buffer allows backtracking by up-to the minimum of either
50+ /// `buffer_len - 32kB` or the total number of bytes read since instantiation or the last buffer
51+ /// invalidation. Note that regular a `seek()` will invalidate the buffer.
5252pub struct MediaSourceStream < ' s > {
5353 /// The source reader.
5454 inner : Box < dyn MediaSource + ' s > ,
@@ -90,17 +90,17 @@ impl<'s> MediaSourceStream<'s> {
9090 }
9191 }
9292
93- /// Returns if the buffer has been exhausted This is a marginally more efficient way of checking
94- /// if `unread_buffer_len() == 0`.
93+ /// Returns if the ring buffer has been exhausted. This is a marginally more efficient way of
94+ /// checking if `unread_buffer_len() == 0`.
9595 #[ inline( always) ]
96- fn is_buffer_exhausted ( & self ) -> bool {
96+ fn is_buffer_empty ( & self ) -> bool {
9797 self . read_pos == self . write_pos
9898 }
9999
100- /// If the buffer has been exhausted, fetch a new block of data to replenish the buffer.
101- fn fetch ( & mut self ) -> io:: Result < ( ) > {
100+ /// If the ring buffer has been exhausted, fetch a new block of data to replenish the buffer.
101+ fn refill_buffer ( & mut self ) -> io:: Result < ( ) > {
102102 // Only fetch when the ring buffer is empty.
103- if self . is_buffer_exhausted ( ) {
103+ if self . is_buffer_empty ( ) {
104104 // Split the vector at the write position to get slices of the two contiguous regions of
105105 // the ring buffer.
106106 let ( vec1, vec0) = self . ring . split_at_mut ( self . write_pos ) ;
@@ -135,27 +135,115 @@ impl<'s> MediaSourceStream<'s> {
135135 Ok ( ( ) )
136136 }
137137
138- /// If the buffer has been exhausted, fetch a new block of data to replenish the buffer. If
139- /// no more data could be fetched, return an end-of-stream error.
140- fn fetch_or_eof ( & mut self ) -> io:: Result < ( ) > {
141- self . fetch ( ) ?;
138+ /// If the ring buffer has been exhausted, fetch a new block of data to replenish the buffer. If
139+ /// no more data could be fetched, return an UnexpectedEof error.
140+ fn refill_buffer_or_eof ( & mut self ) -> io:: Result < ( ) > {
141+ self . refill_buffer ( ) ?;
142142
143- if self . is_buffer_exhausted ( ) {
143+ if self . is_buffer_empty ( ) {
144144 return unexpected_eof_error ( ) ;
145145 }
146146
147147 Ok ( ( ) )
148148 }
149149
150- /// Advances the read position by `len` bytes, taking into account wrap-around.
150+ /// Read as much as possible from the ring buffer to fill `buf`.
151+ fn read_from_buffer < ' b > ( & mut self , mut buf : & ' b mut [ u8 ] ) -> & ' b mut [ u8 ] {
152+ // Keep reading from the ring buffer until either the ring buffer is exhausted, or `buf` has
153+ // been filled.
154+ while !buf. is_empty ( ) {
155+ let Some ( src) = self . maybe_get_readable_slice ( )
156+ else {
157+ break ;
158+ } ;
159+
160+ let count = buf. len ( ) . min ( src. len ( ) ) ;
161+ let ( dst, rest) = buf. split_at_mut ( count) ;
162+ dst. copy_from_slice ( & src[ ..count] ) ;
163+ buf = rest;
164+ self . consume ( count) ;
165+ }
166+
167+ // Return unwritten portion of `buf`.
168+ buf
169+ }
170+
171+ /// Read from the inner source directly to fill `buf`, and then writeback only the required
172+ /// amount into the ring buffer. For large reads, this removes most redundant copies through
173+ /// the ring buffer.
174+ ///
175+ /// Panics if the ring buffer is not empty.
176+ fn read_from_source < ' b > ( & mut self , buf : & ' b mut [ u8 ] ) -> io:: Result < & ' b mut [ u8 ] > {
177+ assert ! ( self . is_buffer_empty( ) ) ;
178+
179+ let read_len = self . inner . read ( buf) ?;
180+
181+ // Update the read and write positions, taking into account wrap-around. Since the ring
182+ // buffer was exhausted these are equal.
183+ let ring_pos = self . write_pos . wrapping_add ( read_len) & self . ring_mask ;
184+ self . write_pos = ring_pos;
185+ self . read_pos = ring_pos;
186+
187+ // Update the stream position accounting.
188+ self . abs_pos += read_len as u64 ;
189+ self . rel_pos += read_len as u64 ;
190+
191+ // Clamp to the largest possible block size that fits best for the amount read.
192+ self . read_block_len = read_len. min ( Self :: MAX_BLOCK_LEN ) . next_power_of_two ( ) ;
193+
194+ // Now, writeback into the ring buffer using what was read into `buf`.
195+
196+ // The amount of bytes to writeback into the ring buffer.
197+ let wb_len = read_len. min ( self . ring . len ( ) ) ;
198+ // The write position at which the writeback will start.
199+ let wb_pos = ring_pos. wrapping_sub ( wb_len) & self . ring_mask ;
200+
201+ // Split the ring buffer into the two continguous write regions.
202+ let ( wb1, wb0) = self . ring . split_at_mut ( wb_pos) ;
203+
204+ let src = & buf[ read_len - wb_len..read_len] ;
205+
206+ if wb0. len ( ) >= wb_len {
207+ wb0[ ..wb_len] . copy_from_slice ( src) ;
208+ }
209+ else {
210+ let ( src0, src1) = src. split_at ( wb0. len ( ) ) ;
211+
212+ let rem = wb_len - wb0. len ( ) ;
213+ wb0. copy_from_slice ( src0) ;
214+ wb1[ ..rem] . copy_from_slice ( & src1[ ..rem] ) ;
215+ } ;
216+
217+ // Return unwritten portion of `buf`.
218+ Ok ( & mut buf[ read_len..] )
219+ }
220+
221+ /// Returns `true` if an operation of length `len` is considered large and eligible for
222+ /// optimizations that bypass the ring buffer.
151223 #[ inline( always) ]
152- fn consume ( & mut self , len : usize ) {
153- self . read_pos = ( self . read_pos + len) & self . ring_mask ;
224+ fn is_large_operation ( & self , len : u64 ) -> bool {
225+ len > 2 * self . ring . len ( ) as u64
154226 }
155227
156- /// Gets the largest contiguous slice of buffered data starting from the read position.
228+ /// Try to get the current contiguous slice of readable data from the ring buffer. Returns
229+ /// `None` if the ring buffer is empty.
157230 #[ inline( always) ]
158- fn continguous_buf ( & self ) -> & [ u8 ] {
231+ fn maybe_get_readable_slice ( & self ) -> Option < & [ u8 ] > {
232+ if self . write_pos > self . read_pos {
233+ Some ( & self . ring [ self . read_pos ..self . write_pos ] )
234+ }
235+ else if self . write_pos < self . read_pos {
236+ Some ( & self . ring [ self . read_pos ..] )
237+ }
238+ else {
239+ None
240+ }
241+ }
242+
243+ /// Get the current contiguous slice of readable data from the ring buffer. Returns an empty
244+ /// slice if the ring buffer is empty.
245+ #[ inline( always) ]
246+ fn get_readable_slice ( & self ) -> & [ u8 ] {
159247 if self . write_pos >= self . read_pos {
160248 & self . ring [ self . read_pos ..self . write_pos ]
161249 }
@@ -164,6 +252,12 @@ impl<'s> MediaSourceStream<'s> {
164252 }
165253 }
166254
255+ /// Advances the read position by `len` bytes, taking into account wrap-around.
256+ #[ inline( always) ]
257+ fn consume ( & mut self , len : usize ) {
258+ self . read_pos = ( self . read_pos + len) & self . ring_mask ;
259+ }
260+
167261 /// Resets the read-ahead buffer, and sets the absolute stream position to `pos`.
168262 fn reset ( & mut self , pos : u64 ) {
169263 self . read_pos = 0 ;
@@ -190,20 +284,36 @@ impl io::Read for MediaSourceStream<'_> {
190284 fn read ( & mut self , mut buf : & mut [ u8 ] ) -> io:: Result < usize > {
191285 let read_len = buf. len ( ) ;
192286
193- while !buf. is_empty ( ) {
194- // Refill the the buffer cache if required.
195- self . fetch ( ) ?;
287+ // First, read as much as possible from the ring buffer.
288+ buf = self . read_from_buffer ( buf) ;
196289
197- // Consume bytes from the readable portion of the buffer cache and copy them into the
198- // remaining portion of the caller's buffer.
199- match self . continguous_buf ( ) . read ( buf) {
200- Ok ( 0 ) => break ,
201- Ok ( count) => {
202- buf = & mut buf[ count..] ;
203- self . consume ( count) ;
290+ // Then, if the remainder is large optimizible, read directly from the source into the
291+ // remaining portion of `buf`. Note, to be true, `buf` must have length significantly larger
292+ // than 0, which means the ring buffer was emptied in the first step. Therefore, it is safe
293+ // to call `read_from_source` which panics if ring buffer is not empty.
294+ if self . is_large_operation ( buf. len ( ) as u64 ) {
295+ buf = self . read_from_source ( buf) ?;
296+ }
297+ else {
298+ // Or, continuously buffer data into the ring buffer from the source, and then read from
299+ // the ring buffer.
300+ while !buf. is_empty ( ) {
301+ // Refill the the ring buffer as required.
302+ self . refill_buffer ( ) ?;
303+
304+ // Consume bytes from the readable portion of the ring buffer and copy them into the
305+ // remaining portion of the caller's buffer.
306+ match self . maybe_get_readable_slice ( ) {
307+ Some ( src) => {
308+ let count = buf. len ( ) . min ( src. len ( ) ) ;
309+ let ( dst, rest) = buf. split_at_mut ( count) ;
310+ dst. copy_from_slice ( & src[ ..count] ) ;
311+ buf = rest;
312+ self . consume ( count) ;
313+ }
314+ // The fetch operation did not buffer anything. There is no more to read.
315+ None => break ,
204316 }
205- Err ( ref e) if e. kind ( ) == io:: ErrorKind :: Interrupted => { }
206- Err ( e) => return Err ( e) ,
207317 }
208318 }
209319
@@ -240,8 +350,8 @@ impl ReadBytes for MediaSourceStream<'_> {
240350 // This function, read_byte, is inlined for performance. To reduce code bloat, place the
241351 // read-ahead buffer replenishment in a seperate function. Call overhead will be negligible
242352 // compared to the actual underlying read.
243- if self . is_buffer_exhausted ( ) {
244- self . fetch_or_eof ( ) ?;
353+ if self . is_buffer_empty ( ) {
354+ self . refill_buffer_or_eof ( ) ?;
245355 }
246356
247357 let value = self . ring [ self . read_pos ] ;
@@ -253,7 +363,7 @@ impl ReadBytes for MediaSourceStream<'_> {
253363 fn read_double_bytes ( & mut self ) -> io:: Result < [ u8 ; 2 ] > {
254364 let mut bytes = [ 0 ; 2 ] ;
255365
256- let buf = self . continguous_buf ( ) ;
366+ let buf = self . get_readable_slice ( ) ;
257367
258368 if buf. len ( ) >= 2 {
259369 bytes. copy_from_slice ( & buf[ ..2 ] ) ;
@@ -271,7 +381,7 @@ impl ReadBytes for MediaSourceStream<'_> {
271381 fn read_triple_bytes ( & mut self ) -> io:: Result < [ u8 ; 3 ] > {
272382 let mut bytes = [ 0 ; 3 ] ;
273383
274- let buf = self . continguous_buf ( ) ;
384+ let buf = self . get_readable_slice ( ) ;
275385
276386 if buf. len ( ) >= 3 {
277387 bytes. copy_from_slice ( & buf[ ..3 ] ) ;
@@ -288,7 +398,7 @@ impl ReadBytes for MediaSourceStream<'_> {
288398 fn read_quad_bytes ( & mut self ) -> io:: Result < [ u8 ; 4 ] > {
289399 let mut bytes = [ 0 ; 4 ] ;
290400
291- let buf = self . continguous_buf ( ) ;
401+ let buf = self . get_readable_slice ( ) ;
292402
293403 if buf. len ( ) >= 4 {
294404 bytes. copy_from_slice ( & buf[ ..4 ] ) ;
@@ -341,18 +451,15 @@ impl ReadBytes for MediaSourceStream<'_> {
341451 // If the stream is seekable and the number of bytes to ignore is large, perform a seek
342452 // first. Note that ignored bytes are rewindable. Therefore, ensure the ring-buffer is
343453 // full after the seek just like if bytes were ignored by consuming them instead.
344- let ring_len = self . ring . len ( ) as u64 ;
345-
346- // Only apply the optimization if seeking 2x or more than the ring-buffer size.
347- while count >= 2 * ring_len && self . is_seekable ( ) {
348- let delta = count. clamp ( 0 , i64:: MAX as u64 ) . sub ( ring_len) ;
454+ while self . is_large_operation ( count) && self . is_seekable ( ) {
455+ let delta = count. min ( i64:: MAX as u64 ) . sub ( self . ring . len ( ) as u64 ) ;
349456 self . seek ( io:: SeekFrom :: Current ( delta as i64 ) ) ?;
350457 count -= delta;
351458 }
352459
353460 // Ignore the remaining bytes be consuming samples from the ring-buffer.
354461 while count > 0 {
355- self . fetch_or_eof ( ) ?;
462+ self . refill_buffer_or_eof ( ) ?;
356463 let discard_count = cmp:: min ( self . unread_buffer_len ( ) as u64 , count) ;
357464 self . consume ( discard_count as usize ) ;
358465 count -= discard_count;
0 commit comments