@@ -54,6 +54,9 @@ pub struct DecodeEngine {
5454 /// The fundamental unit of time representation for the current stream.
5555 time_base : TimeBase ,
5656
57+ /// Raw stream PTS that maps to the public zero-based timeline.
58+ timeline_origin_pts : i64 ,
59+
5760 /// The presentation timestamp (PTS) of the most recently decoded frame, if available.
5861 current_pts : Option < Duration > ,
5962
@@ -89,11 +92,13 @@ impl DecodeEngine {
8992 let decoder = Decoder :: new ( codec_params) ?;
9093
9194 let time_base = demuxer. time_base ( ) ?;
95+ let timeline_origin_pts = demuxer. timeline_origin_pts ( ) ;
9296
9397 Ok ( Self {
9498 demuxer,
9599 decoder,
96100 time_base,
101+ timeline_origin_pts,
97102 current_pts : None ,
98103 is_exhausted : false ,
99104 has_buffered_seek_frame : false ,
@@ -130,8 +135,9 @@ impl DecodeEngine {
130135 if self . has_buffered_seek_frame {
131136 self . has_buffered_seek_frame = false ;
132137 let frame_ptr = self . decoder . current_frame ( ) ;
133- let audio_frame =
134- AudioFrame :: new ( frame_ptr, self . time_base ) . with_offset ( self . buffered_seek_offset ) ;
138+ let audio_frame = AudioFrame :: new ( frame_ptr, self . time_base )
139+ . with_timeline_origin ( self . timeline_origin_pts )
140+ . with_offset ( self . buffered_seek_offset ) ;
135141
136142 self . buffered_seek_offset = 0 ;
137143 self . current_pts = audio_frame. pts ( ) ;
@@ -143,16 +149,26 @@ impl DecodeEngine {
143149 loop {
144150 match self . decoder . receive_frame ( ) {
145151 Ok ( Some ( frame) ) => {
146- let audio_frame = AudioFrame :: new ( frame, self . time_base ) ;
152+ let audio_frame = AudioFrame :: new ( frame, self . time_base )
153+ . with_timeline_origin ( self . timeline_origin_pts ) ;
147154 self . current_pts = audio_frame. pts ( ) ;
148155
149156 self . debug_verify ( ) ;
150157 return Ok ( Some ( audio_frame) ) ;
151158 }
152- Err ( AudioError :: Eagain ) => match self . demuxer . read_packet ( ) ? {
153- Some ( packet) => self . decoder . send_packet ( packet) ?,
154- None => self . decoder . send_eof_flush ( ) ?,
155- } ,
159+ Err ( AudioError :: Eagain ) => {
160+ if let Some ( packet) = self . demuxer . read_packet ( ) ? {
161+ self . decoder . send_packet ( packet) ?;
162+ } else {
163+ if self . decoder . is_flushing ( ) {
164+ self . is_exhausted = true ;
165+ self . debug_verify ( ) ;
166+ return Ok ( None ) ;
167+ }
168+
169+ self . decoder . send_eof_flush ( ) ?;
170+ }
171+ }
156172 Ok ( None ) => {
157173 self . is_exhausted = true ;
158174 self . debug_verify ( ) ;
@@ -234,6 +250,37 @@ impl DecodeEngine {
234250 Ok ( ( ) )
235251 }
236252
253+ /// Returns the position from which the next `receive_frame` call should resume.
254+ fn next_read_position ( & self ) -> Duration {
255+ if self . has_buffered_seek_frame {
256+ let frame_ptr = self . decoder . current_frame ( ) ;
257+ return AudioFrame :: new ( frame_ptr, self . time_base )
258+ . with_timeline_origin ( self . timeline_origin_pts )
259+ . with_offset ( self . buffered_seek_offset )
260+ . pts ( )
261+ . unwrap_or ( Duration :: ZERO ) ;
262+ }
263+
264+ if self . current_pts . is_none ( ) {
265+ return Duration :: ZERO ;
266+ }
267+
268+ let frame_ptr = self . decoder . current_frame ( ) ;
269+ let frame = AudioFrame :: new ( frame_ptr, self . time_base )
270+ . with_timeline_origin ( self . timeline_origin_pts ) ;
271+ let sample_rate = frame. frame_sample_rate ( ) ;
272+
273+ frame. pts ( ) . map_or ( Duration :: ZERO , |pts| {
274+ if sample_rate > 0 {
275+ let frame_duration_us =
276+ ( frame. samples ( ) as u64 ) . saturating_mul ( 1_000_000 ) / sample_rate as u64 ;
277+ pts. saturating_add ( Duration :: from_micros ( frame_duration_us) )
278+ } else {
279+ pts
280+ }
281+ } )
282+ }
283+
237284 /// Scans the audio stream to determine its exact total duration.
238285 ///
239286 /// This operation performs internal seeking and state resets. It is recommended to
@@ -248,15 +295,10 @@ impl DecodeEngine {
248295 /// * `Ok(None)` if the file is completely empty or lacks valid timestamp data.
249296 /// * `Err(AudioError)` if an I/O or parsing failure halts the scanning process.
250297 pub fn scan_duration ( & mut self , mode : ScanMode ) -> Result < Option < Duration > > {
251- let original_position = if self . has_buffered_seek_frame {
252- let frame_ptr = self . decoder . current_frame ( ) ;
253- AudioFrame :: new ( frame_ptr, self . time_base )
254- . with_offset ( self . buffered_seek_offset )
255- . pts ( )
256- } else {
257- self . current_pts
258- }
259- . unwrap_or ( Duration :: ZERO ) ;
298+ let was_exhausted = self . is_exhausted ;
299+ let original_current_pts = self . current_pts ;
300+
301+ let original_position = self . next_read_position ( ) ;
260302
261303 self . seek ( Duration :: ZERO , SeekMode :: Coarse ) ?;
262304
@@ -323,7 +365,15 @@ impl DecodeEngine {
323365 } ,
324366 }
325367
326- let seek_result = self . seek ( original_position, SeekMode :: Accurate ) ;
368+ let seek_result = if was_exhausted {
369+ self . is_exhausted = true ;
370+ self . current_pts = original_current_pts;
371+ self . has_buffered_seek_frame = false ;
372+ self . buffered_seek_offset = 0 ;
373+ Ok ( ( ) )
374+ } else {
375+ self . seek ( original_position, SeekMode :: Accurate )
376+ } ;
327377
328378 if let Some ( e) = scan_error {
329379 return Err ( e) ;
0 commit comments