How to put data into a Frame in ffmpeg?

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()};
1 Like

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.

It seems possible to create a Frame from an AVFrame, but that doesn't look like a good solution.

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)

Thanks for the reply. I'm gonna try it too :slight_smile:

I don't understand how to make decoder::Video . There's no method for creating it.

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. :sob:

I'm gonna ask my reptilian-friend, hope he knows something

1 Like

I'm trying to do something with this C example. It creates an AVFrame using av_frame_alloc().

Edit:

Test code
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).