Ffi+ffmpeg recast opaque pointer to struct

I am a newbie when it comes to Rust and have been playing around with ffmpeg. I am trying to use the ffmpeg-sys crate to ingest a stream via a tcp socket. The whole point of the program is to consume the stream (both audio and video) and return the metadata (codec, framerate, bitrate, etc.).

The only api that I could find in ffmpeg to do this is creating my own AVIOContext via avio_alloc_context. Some blogs/tutorials I found on the web:

My project's dependencies:

ffmpeg-sys = "3.4"
libc = "0.2"

The code:

extern crate ffmpeg_sys;
extern crate libc;

use ffmpeg_sys::*;

use std::ffi::CString;
use std::ptr;
use std::sync::mpsc;

pub struct Context {
    ctx: *mut AVIOContext,
    tx: mpsc::Sender<Vec<u8>>,
    rx: mpsc::Receiver<Vec<u8>>,

impl Context {
    pub fn new(size: usize) -> (Self, mpsc::Sender<Vec<u8>>) {
        unsafe {
            let buf: *mut u8 = av_mallocz(size) as *mut u8;

            if buf.is_null() {
                panic!("Cannot create buf");

            let (tx, rx) = mpsc::channel();

            let mut ret = Self {
                ctx: ptr::null_mut(),
                tx: tx.clone(),
                rx: rx,

            println!("context pointer = {:p}", &mut ret);

            let ctx = avio_alloc_context(
                size as i32,
                &mut ret as *mut _ as *mut libc::c_void,

            if ctx.is_null() {
                panic!("Cannot create AVIO context");

            ret.ctx = ctx;

            (ret, tx)

impl Drop for Context {
    fn drop(&mut self) {
        if self.ctx.is_null() {

        unsafe {
            av_free((*self.ctx).buffer as *mut _);
            avio_context_free(self.ctx as *mut _);

unsafe extern "C" fn read_packet(
    opaque: *mut libc::c_void,
    buf: *mut u8,
    size: libc::c_int,
    ) -> libc::c_int
    println!("read_packet opaque = {:p}", opaque);
    let ctx: &mut Context = &mut *(opaque as *mut _);

    // here be the boom
    let data = ctx.rx.recv();

    // TODO write data to the internal ffmpeg buffer at ctx.ctx.buffer

fn main() {
    let (ctx, tx) = Context::new(4096);

    tx.send(b"Hello World".to_vec());

    unsafe {
        let mut fmt_ctx = avformat_alloc_context();

        (*fmt_ctx).pb = ctx.ctx;

        let blank_str = CString::new("").unwrap();
        let h264 = CString::new("h264").unwrap();

            &mut fmt_ctx as *mut _,


Note that I am 100% a nublet when it comes to rust and especially unsafe rust. If you run the above code (couldn't create a playground example because of the dependency on ffmpeg) it produces output like:

context pointer = 0x7ffee0156c50
read_packet opaque = 0x7ffee0156c50
Illegal instruction: 4

the api that ffmpeg exposes is to use an opaque pointer which i'm using to contain the AVIOContext pointer and the mpsc::Receiver<Vec<u8>> that I want to use to pass in the data.

I've used rust-lldb to debug the process and the opaque pointer appears to be pointing to the Context struct. When I cast the opaque pointer to a Context object, it is completely mangled in memory.

Any pointers (pun-intended) as to what is going on?


You can't safely cast Rust's references to pointers. Rust puts most things on the stack (like your let ret = Self {}), so it's very easy to cause use-after-free bugs on the C side by giving it bad pointers to Rust's temporary variables.

Use Box::into_raw for passing pointers to C, and Box::from_raw to free the data later (to never mix memory allocators).

1 Like

That suggestion helped me to solve my problem - thank you very much.