diff --git a/examples/ffmpeg_recorder.rs b/examples/ffmpeg_recorder.rs index 88feba0..d7df52d 100644 --- a/examples/ffmpeg_recorder.rs +++ b/examples/ffmpeg_recorder.rs @@ -30,6 +30,7 @@ struct MyEmulator { sys_path: Option, frame_properties_locked: bool, octx: ffmpeg::format::context::Output, + frame: u64, } fn video_filter( @@ -176,13 +177,14 @@ static bool ffmpeg_init_config(struct ff_config_param *params, audio_encoder.set_channels(2); audio_encoder.set_channel_layout(ChannelLayout::STEREO); - audio_encoder.set_rate(44100); let audio_filter = audio_filter(&audio_encoder, av_info.timing.sample_rate).unwrap(); let mut audio_encoder = audio_encoder.open_as(acodec).unwrap(); audio_encoder.set_rate(av_info.timing.sample_rate.round() as i32); - //audio_output.set_parameters(&audio_encoder); -octx.write_header().unwrap(); + audio_output.set_parameters(&audio_encoder); + + octx.write_header().unwrap(); + let emu = MyEmulator { retro, sys_info, @@ -197,6 +199,7 @@ octx.write_header().unwrap(); sys_path: sys_path.as_ref().map(|x| x.as_ref().to_path_buf()), frame_properties_locked: false, octx, + frame: 0 }; let mut pin_emu = Box::pin(emu); @@ -207,9 +210,32 @@ octx.write_header().unwrap(); } pub fn run(&mut self, frame: i64) { + self.frame += 1; self.retro.run(); let mut vframe = self.video_frames.pop_front().unwrap(); + self.video_filter.get("in").unwrap().source().add(&vframe).unwrap(); + let mut filtered_vframe = frame::Video::empty(); + + while self.video_filter.get("out").unwrap().sink().frame(&mut filtered_vframe).is_ok() { + if self.video_filter.get("in").unwrap().source().failed_requests() > 0 { + println!("🎥 failed to put filter input frame"); + } + filtered_vframe.set_pts(Some(frame)); + self.video_encoder.send_frame(&filtered_vframe).unwrap(); + + let mut encoded_packet = ffmpeg::Packet::empty(); + while let Ok(..) = self.video_encoder.receive_packet(&mut encoded_packet) { + if encoded_packet.size() > 0 { + encoded_packet.set_stream(0); // use stream index... + //encoded_packet.rescale_ts(Rational(1, 1), Rational(1, 60)); + encoded_packet.write(&mut self.octx).unwrap(); // AAA + } + //encoded_packet.write_interleaved(&mut self.octx).unwrap(); // AAA + } + } + + let mut aframe = frame::Audio::new( format::Sample::I16(format::sample::Type::Packed), self.audio_buf.len(), @@ -220,57 +246,24 @@ octx.write_header().unwrap(); aplane.copy_from_slice(self.audio_buf.as_ref()); self.audio_buf.clear(); - //vframe.set_pts(Some(frame)); - unsafe - { - //(*vframe.as_mut_ptr()).pts = frame; - //(*vframe.as_mut_ptr()).pkt_dts = frame; - } - let mut out = ffmpeg::Packet::empty(); - self.video_filter.get("in").unwrap().source().add(&vframe).unwrap(); self.audio_filter.get("in").unwrap().source().add(&aframe).unwrap(); - let mut filtered_vframe = frame::Video::empty(); - // ffmpeg_push_video_thread takes ffmpeg_t handle which is a retroarch struct holding ffmpeg context - // video_frame_record_scale - // grabs frame from input (record_video_data struct) and copies it to ffmpeg_t handle .video.conv_frame.data[0] - // conv_frame is an AVFrame. where's that from - while self.video_filter.get("out").unwrap().sink().frame(&mut filtered_vframe).is_ok() { - if self.video_filter.get("in").unwrap().source().failed_requests() > 0 { + let mut filtered_aframe = frame::Audio::empty(); + while let Ok(..) = self.audio_filter.get("out").unwrap().sink().frame(&mut filtered_aframe) { + if self.audio_filter.get("in").unwrap().source().failed_requests() > 0 { println!("🎥 failed to put filter input frame"); } - let encode_result = self.video_encoder.send_frame(&filtered_vframe).unwrap(); - //eprintln!("encoded: {:?}", encode_result); - /*if encode_result { - out.set_stream(0); - out.write_interleaved(octx).unwrap(); - } - */ + self.audio_encoder.send_frame(&aframe).unwrap(); let mut encoded_packet = ffmpeg::Packet::empty(); - while let Ok(..) = self.video_encoder.receive_packet(&mut encoded_packet) { - //eprintln!("Attempting write: {:?}", encoded_packet); - //encoded_packet.set_stream(0); // use stream index... - - unsafe { - (*self.octx.as_mut_ptr()).debug = 1; - eprintln!("oformat: {:?}", &((*self.octx.as_mut_ptr()).oformat)); - eprintln!("flags: {:?}", (*(*self.octx.as_mut_ptr()).oformat).flags); - } - - if encoded_packet.size() > 0 { - encoded_packet.write(&mut self.octx).unwrap(); // AAA - } - //encoded_packet.rescale_ts(Rational(1, 1), self.time_base); - //encoded_packet.write_interleaved(&mut self.octx).unwrap(); // AAA + while let Ok(..) = self.audio_encoder.receive_packet(&mut encoded_packet) { + if encoded_packet.size() > 0 { + encoded_packet.set_stream(1); + //encoded_packet.rescale_ts(Rational(1, 1), Rational(1, 60)); + encoded_packet.write(&mut self.octx).unwrap(); // AAA + } } - //eprintln!("packet: {:?}", &out.data()); - //self.video_encoder.flush(&mut out).unwrap(); - //eprintln!("flushed packet: {:?}", &out.data()); - } - while let Ok(..) = self.audio_filter.get("out").unwrap().sink().frame(&mut aframe) { - self.audio_encoder.encode(&aframe, &mut out);//.unwrap(); } } @@ -317,7 +310,7 @@ impl retro::wrapper::Handler for MyEmulator { } } - //vframe.set_pts(Some(69)); + //vframe.set_pts(Some(self.frame as i64)); self.video_frames.push_back(vframe); } @@ -430,7 +423,7 @@ fn main() -> Fallible<()> { emu.frame_properties_locked = true; //for frame in 0..60*10 { - for frame in 0..9200 { + for frame in 0..600 { eprintln!("🖼️ frame: {}", frame); emu.run(frame);