rav1d-cli 1.1.0

Rust port of the dav1d AV1 decoder CLI tools
use crate::compat::errno::errno_location;
use crate::compat::stdio::stderr;
use crate::compat::stdio::stdout;
use libc::fclose;
use libc::fopen;
use libc::fprintf;
use libc::fwrite;
use libc::strcmp;
use libc::strerror;
use rav1d::include::dav1d::headers::DAV1D_CHR_UNKNOWN;
use rav1d::include::dav1d::headers::DAV1D_PIXEL_LAYOUT_I400;
use rav1d::include::dav1d::headers::DAV1D_PIXEL_LAYOUT_I420;
use rav1d::include::dav1d::headers::DAV1D_PIXEL_LAYOUT_I444;
use rav1d::include::dav1d::picture::Dav1dPicture;
use rav1d::include::dav1d::picture::Dav1dPictureParameters;
use rav1d::src::lib::dav1d_picture_unref;
use std::ffi::c_char;
use std::ffi::c_int;
use std::ffi::c_uint;
use std::ffi::c_ulong;
use std::ffi::c_void;
use std::ptr;
use std::ptr::NonNull;

#[repr(C)]
pub struct MuxerPriv {
    pub f: *mut libc::FILE,
    pub first: c_int,
    pub fps: [c_uint; 2],
}

#[repr(C)]
pub struct Muxer {
    pub priv_data_size: c_int,
    pub name: *const c_char,
    pub extension: *const c_char,
    pub write_header: Option<
        unsafe extern "C" fn(
            *mut MuxerPriv,
            *const c_char,
            *const Dav1dPictureParameters,
            *const c_uint,
        ) -> c_int,
    >,
    pub write_picture: Option<unsafe extern "C" fn(*mut MuxerPriv, *mut Dav1dPicture) -> c_int>,
    pub write_trailer: Option<unsafe extern "C" fn(*mut MuxerPriv) -> ()>,
    pub verify: Option<unsafe extern "C" fn(*mut MuxerPriv, *const c_char) -> c_int>,
}

pub type Y4m2OutputContext = MuxerPriv;

unsafe extern "C" fn y4m2_open(
    c: *mut Y4m2OutputContext,
    file: *const c_char,
    mut _p: *const Dav1dPictureParameters,
    fps: *const c_uint,
) -> c_int {
    if strcmp(file, b"-\0" as *const u8 as *const c_char) == 0 {
        (*c).f = stdout();
    } else {
        (*c).f = fopen(file, b"wb\0" as *const u8 as *const c_char);
        if ((*c).f).is_null() {
            fprintf(
                stderr(),
                b"Failed to open %s: %s\n\0" as *const u8 as *const c_char,
                file,
                strerror(*errno_location()),
            );
            return -1;
        }
    }
    (*c).first = 1 as c_int;
    (*c).fps[0] = *fps.offset(0);
    (*c).fps[1] = *fps.offset(1);
    return 0 as c_int;
}

unsafe fn write_header(c: *mut Y4m2OutputContext, p: *const Dav1dPicture) -> c_int {
    static mut ss_names: [[*const c_char; 3]; 4] = [
        [
            b"mono\0" as *const u8 as *const c_char,
            b"mono10\0" as *const u8 as *const c_char,
            b"mono12\0" as *const u8 as *const c_char,
        ],
        [
            0 as *const c_char,
            b"420p10\0" as *const u8 as *const c_char,
            b"420p12\0" as *const u8 as *const c_char,
        ],
        [
            b"422\0" as *const u8 as *const c_char,
            b"422p10\0" as *const u8 as *const c_char,
            b"422p12\0" as *const u8 as *const c_char,
        ],
        [
            b"444\0" as *const u8 as *const c_char,
            b"444p10\0" as *const u8 as *const c_char,
            b"444p12\0" as *const u8 as *const c_char,
        ],
    ];
    static mut chr_names_8bpc_i420: [*const c_char; 3] = [
        b"420jpeg\0" as *const u8 as *const c_char,
        b"420mpeg2\0" as *const u8 as *const c_char,
        b"420\0" as *const u8 as *const c_char,
    ];
    let seq_hdr = (*p).seq_hdr.unwrap().as_ref();
    let frame_hdr = (*p).frame_hdr.unwrap().as_ref();
    let ss_name: *const c_char =
        if (*p).p.layout as c_uint == DAV1D_PIXEL_LAYOUT_I420 as c_int as c_uint && (*p).p.bpc == 8
        {
            chr_names_8bpc_i420[(if seq_hdr.chr as c_uint > 2 as c_uint {
                DAV1D_CHR_UNKNOWN as c_int as c_uint
            } else {
                seq_hdr.chr as c_uint
            }) as usize]
        } else {
            ss_names[(*p).p.layout as usize][seq_hdr.hbd as usize]
        };
    let fw: c_uint = (*p).p.w as c_uint;
    let fh: c_uint = (*p).p.h as c_uint;
    let mut aw: u64 = (fh as u64).wrapping_mul(frame_hdr.render_width as u64);
    let mut ah: u64 = (fw as u64).wrapping_mul(frame_hdr.render_height as u64);
    let mut gcd: u64 = ah;
    let mut a: u64 = aw;
    let mut b: u64;
    loop {
        b = a.wrapping_rem(gcd);
        if !(b != 0) {
            break;
        }
        a = gcd;
        gcd = b;
    }
    aw = aw.wrapping_div(gcd);
    ah = ah.wrapping_div(gcd);
    fprintf(
        (*c).f,
        b"YUV4MPEG2 W%u H%u F%u:%u Ip A%lu:%lu C%s\n\0" as *const u8 as *const c_char,
        fw,
        fh,
        (*c).fps[0],
        (*c).fps[1],
        aw,
        ah,
        ss_name,
    );
    return 0 as c_int;
}

unsafe extern "C" fn y4m2_write(c: *mut Y4m2OutputContext, p: *mut Dav1dPicture) -> c_int {
    let mut current_block: u64;
    if (*c).first != 0 {
        (*c).first = 0 as c_int;
        let res = write_header(c, p);
        if res < 0 {
            return res;
        }
    }
    fprintf((*c).f, b"FRAME\n\0" as *const u8 as *const c_char);
    let mut ptr: *mut u8;
    let hbd = ((*p).p.bpc > 8) as c_int;
    ptr = (*p).data[0].map_or_else(ptr::null_mut, NonNull::as_ptr) as *mut u8;
    let mut y = 0;
    loop {
        if !(y < (*p).p.h) {
            current_block = 11812396948646013369;
            break;
        }
        if fwrite(ptr as *const c_void, ((*p).p.w << hbd) as usize, 1, (*c).f) != 1 {
            current_block = 11545648641752300099;
            break;
        }
        ptr = ptr.offset((*p).stride[0] as isize);
        y += 1;
    }
    match current_block {
        11812396948646013369 => {
            if (*p).p.layout as c_uint != DAV1D_PIXEL_LAYOUT_I400 as c_int as c_uint {
                let ss_ver = ((*p).p.layout as c_uint == DAV1D_PIXEL_LAYOUT_I420 as c_int as c_uint)
                    as c_int;
                let ss_hor = ((*p).p.layout as c_uint != DAV1D_PIXEL_LAYOUT_I444 as c_int as c_uint)
                    as c_int;
                let cw = (*p).p.w + ss_hor >> ss_hor;
                let ch = (*p).p.h + ss_ver >> ss_ver;
                let mut pl = 1;
                's_64: loop {
                    if !(pl <= 2) {
                        current_block = 13797916685926291137;
                        break;
                    }
                    ptr = (*p).data[pl as usize].map_or_else(ptr::null_mut, NonNull::as_ptr)
                        as *mut u8;
                    let mut y_0 = 0;
                    while y_0 < ch {
                        if fwrite(ptr as *const c_void, (cw << hbd) as usize, 1, (*c).f) != 1 {
                            current_block = 11545648641752300099;
                            break 's_64;
                        }
                        ptr = ptr.offset((*p).stride[1] as isize);
                        y_0 += 1;
                    }
                    pl += 1;
                }
            } else {
                current_block = 13797916685926291137;
            }
            match current_block {
                11545648641752300099 => {}
                _ => {
                    dav1d_picture_unref(NonNull::new(p));
                    return 0 as c_int;
                }
            }
        }
        _ => {}
    }
    dav1d_picture_unref(NonNull::new(p));
    fprintf(
        stderr(),
        b"Failed to write frame data: %s\n\0" as *const u8 as *const c_char,
        strerror(*errno_location()),
    );
    return -1;
}

unsafe extern "C" fn y4m2_close(c: *mut Y4m2OutputContext) {
    if (*c).f != stdout() {
        fclose((*c).f);
    }
}

#[no_mangle]
pub static mut y4m2_muxer: Muxer = Muxer {
    priv_data_size: ::core::mem::size_of::<Y4m2OutputContext>() as c_ulong as c_int,
    name: b"yuv4mpeg2\0" as *const u8 as *const c_char,
    extension: b"y4m\0" as *const u8 as *const c_char,
    write_header: Some(y4m2_open),
    write_picture: Some(y4m2_write),
    write_trailer: Some(y4m2_close),
    verify: None,
};