WIP ffmpeg filter graphs
This commit is contained in:
parent
ffc53708d1
commit
b9023a0131
|
@ -7,12 +7,13 @@ use std::path::{Path, PathBuf};
|
|||
use std::pin::Pin;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use failure::Fallible;
|
||||
|
||||
use ferretro::retro;
|
||||
use ferretro::retro::ffi::{PixelFormat, GameGeometry, SystemAvInfo, SystemInfo};
|
||||
use ferretro::retro::wrapper::{LibretroWrapper, Handler};
|
||||
|
||||
use ffmpeg::{format, frame, media, ChannelLayout};
|
||||
use ffmpeg::{format, filter, frame, media, ChannelLayout};
|
||||
use ffmpeg::util::rational::Rational;
|
||||
|
||||
struct MyEmulator {
|
||||
|
@ -23,9 +24,71 @@ struct MyEmulator {
|
|||
video_frames: VecDeque<frame::Video>,
|
||||
video_encoder: ffmpeg::encoder::Video,
|
||||
audio_encoder: ffmpeg::encoder::Audio,
|
||||
video_filter: filter::Graph,
|
||||
audio_filter: filter::Graph,
|
||||
sys_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn video_filter(
|
||||
video_encoder: &ffmpeg::encoder::video::Video,
|
||||
av_info: &SystemAvInfo,
|
||||
pix_fmt: PixelFormat,
|
||||
) -> Result<filter::Graph, ffmpeg::Error> {
|
||||
let mut vfilter = filter::Graph::new();
|
||||
let pix_fmt = match pix_fmt {
|
||||
PixelFormat::ARGB1555 => if cfg!(target_endian = "big") { "rgb555be" } else { "rgb555le" },
|
||||
PixelFormat::ARGB8888 => "argb",
|
||||
PixelFormat::RGB565 => if cfg!(target_endian = "big") { "rgb565be" } else { "rgb565le" },
|
||||
};
|
||||
let pixel_aspect = av_info.geometry.aspect_ratio / (av_info.geometry.base_width as f32 / av_info.geometry.base_height as f32);
|
||||
let args = format!(
|
||||
"buffer=width={}:height={}:pix_fmt={}:frame_rate={}:pixel_aspect={}",
|
||||
av_info.geometry.base_width,
|
||||
av_info.geometry.base_height,
|
||||
pix_fmt,
|
||||
av_info.timing.fps,
|
||||
pixel_aspect,
|
||||
);
|
||||
vfilter.add(&filter::find("buffer").unwrap(), "in", &args);
|
||||
//scale?
|
||||
vfilter.add(&filter::find("buffersink").unwrap(), "out", "");
|
||||
|
||||
{
|
||||
let mut out = vfilter.get("out").unwrap();
|
||||
out.set_pixel_format(video_encoder.format());
|
||||
}
|
||||
|
||||
vfilter.output("in", 0)?
|
||||
.input("out", 0)?;
|
||||
vfilter.validate()?;
|
||||
|
||||
Ok(vfilter)
|
||||
}
|
||||
|
||||
fn audio_filter(
|
||||
audio_encoder: &ffmpeg::encoder::audio::Audio,
|
||||
sample_rate: f64,
|
||||
) -> Result<filter::Graph, ffmpeg::Error> {
|
||||
let mut afilter = filter::Graph::new();
|
||||
let args = format!("sample_rate={}:sample_fmt=s16:channel_layout=stereo", sample_rate);
|
||||
afilter.add(&filter::find("abuffer").unwrap(), "in", &args);
|
||||
//aresample?
|
||||
afilter.add(&filter::find("abuffersink").unwrap(), "out", "");
|
||||
|
||||
{
|
||||
let mut out = afilter.get("out").unwrap();
|
||||
out.set_sample_format(audio_encoder.format());
|
||||
out.set_channel_layout(audio_encoder.channel_layout());
|
||||
out.set_sample_rate(audio_encoder.rate());
|
||||
}
|
||||
|
||||
afilter.output("in", 0)?
|
||||
.input("out", 0)?;
|
||||
afilter.validate()?;
|
||||
|
||||
Ok(afilter)
|
||||
}
|
||||
|
||||
impl MyEmulator {
|
||||
pub fn new(
|
||||
core_path: impl AsRef<Path>,
|
||||
|
@ -44,16 +107,15 @@ impl MyEmulator {
|
|||
video_encoder.set_frame_rate(av_info.timing.fps.into());
|
||||
video_encoder.set_width(av_info.geometry.base_width);
|
||||
video_encoder.set_height(av_info.geometry.base_height);
|
||||
video_encoder.set_format(format::Pixel::YUV420P);
|
||||
video_encoder.set_aspect_ratio(av_info.geometry.aspect_ratio as f64);
|
||||
|
||||
audio_encoder.set_rate(44100);
|
||||
audio_encoder.set_format(audio_encoder.codec().unwrap().audio().unwrap().formats().unwrap().nth(0).unwrap());
|
||||
audio_encoder.set_channels(2);
|
||||
audio_encoder.set_channel_layout(ChannelLayout::STEREO);
|
||||
audio_encoder.set_rate(system_av_info.timing.sample_rate.round() as i32);
|
||||
|
||||
let video_encoder_2 = video_encoder.open().unwrap();
|
||||
let audio_encoder_2 = audio_encoder.open().unwrap();
|
||||
let video_filter = video_filter(&video_encoder, &av_info).unwrap();
|
||||
let audio_filter = audio_filter(&audio_encoder, av_info.timing.sample_rate).unwrap();
|
||||
|
||||
let video_encoder = video_encoder.open().unwrap();
|
||||
let audio_encoder = audio_encoder.open().unwrap();
|
||||
|
||||
let emu = MyEmulator {
|
||||
retro,
|
||||
|
@ -61,8 +123,10 @@ impl MyEmulator {
|
|||
audio_buf: Default::default(),
|
||||
video_pixel_format: format::Pixel::RGB555,
|
||||
video_frames: Default::default(),
|
||||
video_encoder: video_encoder_2,
|
||||
audio_encoder: audio_encoder_2,
|
||||
video_encoder,
|
||||
audio_encoder,
|
||||
video_filter,
|
||||
audio_filter,
|
||||
sys_path: sys_path.as_ref().map(|x| x.as_ref().to_path_buf()),
|
||||
};
|
||||
|
||||
|
@ -77,7 +141,6 @@ impl MyEmulator {
|
|||
self.retro.run();
|
||||
|
||||
let vframe = self.video_frames.pop_front().unwrap();
|
||||
eprintln!("video {}x{}, {} audio samples", vframe.width(), vframe.height(), self.audio_buf.len());
|
||||
let mut aframe = frame::Audio::new(
|
||||
format::Sample::I16(format::sample::Type::Packed),
|
||||
self.audio_buf.len(),
|
||||
|
@ -194,25 +257,29 @@ struct Opt {
|
|||
system: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Fallible<()> {
|
||||
let opt: Opt = Opt::from_args();
|
||||
ffmpeg::init().unwrap();
|
||||
|
||||
let mut octx = format::output(&opt.video).unwrap();
|
||||
let vcodec = ffmpeg::encoder::find(octx.format().codec(&opt.video, media::Type::Video))
|
||||
.unwrap()
|
||||
.video()
|
||||
.unwrap();
|
||||
let acodec = ffmpeg::encoder::find(octx.format().codec(&opt.video, media::Type::Audio))
|
||||
.unwrap()
|
||||
.audio()
|
||||
.unwrap();
|
||||
let mut octx = format::output(&opt.video)?;
|
||||
|
||||
let mut video_encoder = octx.add_stream(vcodec).unwrap().codec().encoder().video().unwrap();
|
||||
let mut audio_encoder = octx.add_stream(acodec).unwrap().codec().encoder().audio().unwrap();
|
||||
let detected_vcodec = octx.format().codec(&opt.video, media::Type::Video);
|
||||
let detected_acodec = octx.format().codec(&opt.video, media::Type::Audio);
|
||||
|
||||
let vcodec = ffmpeg::encoder::find(detected_vcodec).unwrap().video()?;
|
||||
let acodec = ffmpeg::encoder::find(detected_acodec).unwrap().audio()?;
|
||||
|
||||
let mut video_encoder = octx.add_stream(vcodec)?.codec().encoder().video()?;
|
||||
let mut audio_encoder = octx.add_stream(acodec)?.codec().encoder().audio()?;
|
||||
|
||||
video_encoder.set_bit_rate(64000);
|
||||
video_encoder.set_format(video_encoder.codec().unwrap().video()?.formats().unwrap().nth(0).unwrap());
|
||||
|
||||
audio_encoder.set_bit_rate(64000);
|
||||
audio_encoder.set_rate(44100);
|
||||
audio_encoder.set_format(audio_encoder.codec().unwrap().audio()?.formats().unwrap().nth(0).unwrap());
|
||||
audio_encoder.set_channels(2);
|
||||
audio_encoder.set_channel_layout(ChannelLayout::STEREO);
|
||||
|
||||
let mut emu = MyEmulator::new(opt.core, &opt.system, video_encoder, audio_encoder);
|
||||
emu.load_game(opt.rom);
|
||||
|
@ -224,4 +291,5 @@ fn main() {
|
|||
}
|
||||
|
||||
octx.write_trailer().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue