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

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.