@@ -2,7 +2,7 @@ use cap_media_info::{AudioInfo, VideoInfo};
22use cidre:: { cm:: SampleTimingInfo , objc:: Obj , * } ;
33use ffmpeg:: frame;
44use std:: { ops:: Sub , path:: PathBuf , time:: Duration } ;
5- use tracing:: { debug, info} ;
5+ use tracing:: { debug, error , info} ;
66
77// before pausing at all, subtract 0.
88// on pause, record last frame time.
@@ -16,7 +16,7 @@ pub struct MP4Encoder {
1616 asset_writer : arc:: R < av:: AssetWriter > ,
1717 video_input : arc:: R < av:: AssetWriterInput > ,
1818 audio_input : Option < arc:: R < av:: AssetWriterInput > > ,
19- most_recent_timestamp : Option < Duration > ,
19+ most_recent_frame : Option < ( arc :: R < cm :: SampleBuf > , Duration ) > ,
2020 pause_timestamp : Option < Duration > ,
2121 timestamp_offset : Duration ,
2222 is_writing : bool ,
@@ -197,7 +197,7 @@ impl MP4Encoder {
197197 audio_input,
198198 asset_writer,
199199 video_input,
200- most_recent_timestamp : None ,
200+ most_recent_frame : None ,
201201 pause_timestamp : None ,
202202 timestamp_offset : Duration :: ZERO ,
203203 is_writing : false ,
@@ -211,7 +211,7 @@ impl MP4Encoder {
211211 /// They will be made relative when encoding
212212 pub fn queue_video_frame (
213213 & mut self ,
214- frame : & cidre :: cm:: SampleBuf ,
214+ frame : arc :: R < cm:: SampleBuf > ,
215215 timestamp : Duration ,
216216 ) -> Result < ( ) , QueueVideoFrameError > {
217217 if self . is_paused || !self . video_input . is_ready_for_more_media_data ( ) {
@@ -224,7 +224,7 @@ impl MP4Encoder {
224224 . start_session_at_src_time ( cm:: Time :: new ( timestamp. as_millis ( ) as i64 , 1_000 ) ) ;
225225 }
226226
227- self . most_recent_timestamp = Some ( timestamp) ;
227+ self . most_recent_frame = Some ( ( frame . clone ( ) , timestamp) ) ;
228228
229229 if let Some ( pause_timestamp) = self . pause_timestamp {
230230 self . timestamp_offset += timestamp - pause_timestamp;
@@ -331,7 +331,7 @@ impl MP4Encoder {
331331 return ;
332332 }
333333
334- let Some ( timestamp) = self . most_recent_timestamp else {
334+ let Some ( ( _ , timestamp) ) = self . most_recent_frame else {
335335 return ;
336336 } ;
337337
@@ -347,19 +347,34 @@ impl MP4Encoder {
347347 self . is_paused = false ;
348348 }
349349
350- pub fn finish ( & mut self ) {
350+ pub fn finish ( & mut self , timestamp : Option < Duration > ) {
351351 if !self . is_writing {
352352 return ;
353353 }
354354
355- let Some ( most_recent_timestamp ) = self . most_recent_timestamp else {
355+ let Some ( mut most_recent_frame ) = self . most_recent_frame . take ( ) else {
356356 return ;
357357 } ;
358358
359+ // We extend the video to the provided timestamp if possible
360+ if let Some ( timestamp) = timestamp
361+ && let Some ( diff) = timestamp. checked_sub ( most_recent_frame. 1 )
362+ && diff > Duration :: from_millis ( 500 )
363+ {
364+ match self . queue_video_frame ( most_recent_frame. 0 . clone ( ) , timestamp) {
365+ Ok ( ( ) ) => {
366+ most_recent_frame = ( most_recent_frame. 0 , timestamp) ;
367+ }
368+ Err ( e) => {
369+ error ! ( "Failed to queue final video frame: {e}" ) ;
370+ }
371+ }
372+ }
373+
359374 self . is_writing = false ;
360375
361376 self . asset_writer . end_session_at_src_time ( cm:: Time :: new (
362- most_recent_timestamp . sub ( self . timestamp_offset ) . as_millis ( ) as i64 ,
377+ most_recent_frame . 1 . sub ( self . timestamp_offset ) . as_millis ( ) as i64 ,
363378 1000 ,
364379 ) ) ;
365380 self . video_input . mark_as_finished ( ) ;
@@ -381,7 +396,7 @@ impl MP4Encoder {
381396
382397impl Drop for MP4Encoder {
383398 fn drop ( & mut self ) {
384- self . finish ( ) ;
399+ self . finish ( None ) ;
385400 }
386401}
387402
0 commit comments