Hi there! I use ffmpeg-next crate. I've created Encoder and Frame. Also I've a slice of bytes, which I got from scrap (it's actually screenshot). How to put this slice of bytes(screenshot into the frame ?
ffmpeg::init().unwrap();
let encoder = ffmpeg_next::codec::encoder::new();
let frame = unsafe{ ffmpeg::util::frame::Frame::empty()};
Hi, the answer would be very helpful to me too. The crates depending on ffmpeg-next do not use video encoding from raw, nor the examples. The C examples are just overcomplicated.
Maybe you have to create a decoder::Video, send a raw image via its Video::send_packet and get the frame via its Video::receive_frame. I will try this. (see this transcoding example)
This crate is weirdly structured, you can create a Decoder with decoder::new, but there is no method. Then there is a video method to obtain a Video.
I will start thinking that video encoding is a technology created by aliens and kept secret by some illuminati reptilian developers to govern the world using undocumented C libraries.
Edit: send_packet actually needs an AVPacket, which is not a simple raw image... and there is no way to create one.
use ffmpeg_next::sys::{AVCodec, AVCodecContext, AVFrame, AVPacket, AVRational};
use std::io::Write;
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/encode_video.c
pub fn test_ffmpeg() {
let codec_ptr: *mut AVCodec = unsafe {ffmpeg_next::sys::avcodec_find_encoder(ffmpeg_next::sys::AVCodecID::AV_CODEC_ID_MPEG4)};
let codec: &mut AVCodec = unsafe {codec_ptr.as_mut()}.unwrap();
let c_ptr: *mut AVCodecContext = unsafe {ffmpeg_next::sys::avcodec_alloc_context3(codec)};
let mut c: &mut AVCodecContext = unsafe {c_ptr.as_mut()}.unwrap();
let pkt_ptr: *mut AVPacket = unsafe {ffmpeg_next::sys::av_packet_alloc()};
c.bit_rate = 400_000;
c.width = 352;
c.height = 288;
c.time_base = AVRational {num: 1, den: 25};
c.framerate = AVRational {num: 25, den: 1};
c.gop_size = 10;
c.max_b_frames = 1;
c.pix_fmt = ffmpeg_next::sys::AVPixelFormat::AV_PIX_FMT_YUV420P;
/*if codec.id == ffmpeg_next::sys::AVCodecID::AV_CODEC_ID_H264 {
unsafe {ffmpeg_next::sys::av_opt_set(c.priv_data, "preset", "slow", 0)};
}*/
assert!(unsafe {ffmpeg_next::sys::avcodec_open2(c_ptr, codec_ptr, std::ptr::null_mut())} >= 0);
let mut f = std::fs::File::create("output.m4a").unwrap();
let frame_ptr: *mut AVFrame = unsafe {ffmpeg_next::sys::av_frame_alloc()};
let mut frame: &mut AVFrame = unsafe {frame_ptr.as_mut()}.unwrap();
frame.format = c.pix_fmt as i32;//ffmpeg_next::sys::AVPixelFormat::AV_PIX_FMT_RGB24 as i32;
frame.width = c.width;
frame.height = c.height;
assert!(unsafe {ffmpeg_next::sys::av_frame_get_buffer(frame_ptr, 0)} >= 0);
for i in 0..25 {
println!("Frame {}", i);
assert!(unsafe {ffmpeg_next::sys::av_frame_make_writable(frame_ptr)} >= 0);
/*for y in 0..frame.height {
for x in 0..frame.width {
unsafe {frame.data[0].offset((y * frame.linesize[0]) as isize)}.set_ptr_value(128);
}
}*/
frame.pts = i as i64;
encode(c_ptr, frame_ptr, pkt_ptr, &mut f);
}
encode(c_ptr, std::ptr::null_mut(), pkt_ptr, &mut f);
if codec.id == ffmpeg_next::sys::AVCodecID::AV_CODEC_ID_MPEG1VIDEO || codec.id == ffmpeg_next::sys::AVCodecID::AV_CODEC_ID_MPEG2VIDEO {
f.write(&[0, 0, 1, 0xb7]).unwrap();
}
f.sync_all().unwrap();
}
fn encode(c_ptr: *mut AVCodecContext, frame_ptr: *mut AVFrame, pkt_ptr: *mut AVPacket, f: &mut std::fs::File) {
let pkt: &mut AVPacket = unsafe {pkt_ptr.as_mut()}.unwrap();
assert!(unsafe {ffmpeg_next::sys::avcodec_send_frame(c_ptr, frame_ptr)} >= 0);
let mut ret = 0i32;
while ret >= 0 {
ret = unsafe {ffmpeg_next::sys::avcodec_receive_packet(c_ptr, pkt_ptr)};
if ret == ffmpeg_next::sys::AVERROR(ffmpeg_next::sys::EAGAIN) || ret == ffmpeg_next::sys::AVERROR_EOF {
return;
} else if ret < 0 {
panic!("Error during encoding");
}
println!("Write packet {}, {}", pkt.pts, pkt.size);
f.write(unsafe {std::slice::from_raw_parts(pkt.data, pkt.size as usize)}).unwrap();
unsafe {ffmpeg_next::sys::av_packet_unref(pkt_ptr)};
}
}
This is a very close translation of the C example. It generates the file output.m4a from raw images, but VLC won't open it and Handbrake says it's empty (but it can read the image size).