rav1d-cli 1.1.0

Rust port of the dav1d AV1 decoder CLI tools
use crate::compat::errno::errno_location;
use crate::compat::stdio::fseeko;
use crate::compat::stdio::stderr;
use libc::fclose;
use libc::fopen;
use libc::fprintf;
use libc::fread;
use libc::strerror;
use rav1d::include::dav1d::data::Dav1dData;
use rav1d::include::dav1d::headers::Dav1dObuType;
use rav1d::include::dav1d::headers::DAV1D_OBU_FRAME;
use rav1d::include::dav1d::headers::DAV1D_OBU_FRAME_HDR;
use rav1d::include::dav1d::headers::DAV1D_OBU_SEQ_HDR;
use rav1d::include::dav1d::headers::DAV1D_OBU_TD;
use rav1d::include::dav1d::headers::DAV1D_OBU_TILE_GRP;
use rav1d::src::lib::dav1d_data_create;
use rav1d::src::lib::dav1d_data_unref;
use std::cmp;
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::NonNull;

#[repr(C)]
pub struct DemuxerPriv {
    pub f: *mut libc::FILE,
    pub temporal_unit_size: usize,
    pub frame_unit_size: usize,
}

#[repr(C)]
pub struct Demuxer {
    pub priv_data_size: c_int,
    pub name: *const c_char,
    pub probe_sz: c_int,
    pub probe: Option<unsafe extern "C" fn(*const u8) -> c_int>,
    pub open: Option<
        unsafe extern "C" fn(
            *mut DemuxerPriv,
            *const c_char,
            *mut c_uint,
            *mut c_uint,
            *mut c_uint,
        ) -> c_int,
    >,
    pub read: Option<unsafe extern "C" fn(*mut DemuxerPriv, *mut Dav1dData) -> c_int>,
    pub seek: Option<unsafe extern "C" fn(*mut DemuxerPriv, u64) -> c_int>,
    pub close: Option<unsafe extern "C" fn(*mut DemuxerPriv) -> ()>,
}

pub type AnnexbInputContext = DemuxerPriv;

unsafe fn leb128(f: *mut libc::FILE, len: *mut usize) -> c_int {
    let mut val: u64 = 0 as c_int as u64;
    let mut i: c_uint = 0 as c_int as c_uint;
    let mut more: c_uint;
    loop {
        let mut v: u8 = 0;
        if fread(&mut v as *mut u8 as *mut c_void, 1, 1, f) < 1 {
            return -1;
        }
        more = (v as c_int & 0x80 as c_int) as c_uint;
        val |= ((v as c_int & 0x7f as c_int) as u64) << i.wrapping_mul(7 as c_int as c_uint);
        i = i.wrapping_add(1);
        if !(more != 0 && i < 8 as c_uint) {
            break;
        }
    }
    if val > u32::MAX as u64 || more != 0 {
        return -1;
    }
    *len = val as usize;
    return i as c_int;
}

unsafe fn leb(mut ptr: *const u8, mut sz: c_int, len: *mut usize) -> c_int {
    let mut val: u64 = 0 as c_int as u64;
    let mut i: c_uint = 0 as c_int as c_uint;
    let mut more: c_uint;
    loop {
        let fresh0 = sz;
        sz = sz - 1;
        if fresh0 == 0 {
            return -1;
        }
        let fresh1 = ptr;
        ptr = ptr.offset(1);
        let v = *fresh1 as c_int;
        more = (v & 0x80 as c_int) as c_uint;
        val |= ((v & 0x7f as c_int) as u64) << i.wrapping_mul(7 as c_int as c_uint);
        i = i.wrapping_add(1);
        if !(more != 0 && i < 8 as c_uint) {
            break;
        }
    }
    if val > u32::MAX as u64 || more != 0 {
        return -1;
    }
    *len = val as usize;
    return i as c_int;
}

#[inline]
unsafe fn parse_obu_header(
    mut buf: *const u8,
    mut buf_size: c_int,
    obu_size: *mut usize,
    type_0: *mut Dav1dObuType,
    allow_implicit_size: c_int,
) -> c_int {
    let ret;
    let extension_flag;
    let has_size_flag;
    if buf_size == 0 {
        return -1;
    }
    if *buf as c_int & 0x80 as c_int != 0 {
        return -1;
    }
    *type_0 = ((*buf as c_int & 0x78 as c_int) >> 3) as Dav1dObuType;
    extension_flag = (*buf as c_int & 0x4 as c_int) >> 2;
    has_size_flag = (*buf as c_int & 0x2 as c_int) >> 1;
    buf = buf.offset(1);
    buf_size -= 1;
    if extension_flag != 0 {
        if buf_size == 0 {
            return -1;
        }
        buf = buf.offset(1);
        buf_size -= 1;
    }
    if has_size_flag != 0 {
        ret = leb(buf, buf_size, obu_size);
        if ret < 0 {
            return -1;
        }
        return *obu_size as c_int + ret + 1 + extension_flag;
    } else {
        if allow_implicit_size == 0 {
            return -1;
        }
    }
    *obu_size = buf_size as usize;
    return buf_size + 1 + extension_flag;
}

unsafe extern "C" fn annexb_probe(data: *const u8) -> c_int {
    let mut ret;
    let mut cnt = 0;
    let mut temporal_unit_size: usize = 0;
    ret = leb(
        data.offset(cnt as isize),
        2048 - cnt,
        &mut temporal_unit_size,
    );
    if ret < 0 {
        return 0 as c_int;
    }
    cnt += ret;
    let mut frame_unit_size: usize = 0;
    ret = leb(data.offset(cnt as isize), 2048 - cnt, &mut frame_unit_size);
    if ret < 0 || frame_unit_size.wrapping_add(ret as usize) > temporal_unit_size {
        return 0 as c_int;
    }
    cnt += ret;
    temporal_unit_size =
        (temporal_unit_size as c_ulong).wrapping_sub(ret as c_ulong) as usize as usize;
    let mut obu_unit_size: usize = 0;
    ret = leb(data.offset(cnt as isize), 2048 - cnt, &mut obu_unit_size);
    if ret < 0 || obu_unit_size.wrapping_add(ret as usize) >= frame_unit_size {
        return 0 as c_int;
    }
    cnt += ret;
    temporal_unit_size =
        (temporal_unit_size).wrapping_sub(obu_unit_size.wrapping_add(ret as usize));
    frame_unit_size = (frame_unit_size).wrapping_sub(obu_unit_size.wrapping_add(ret as usize));
    let mut obu_size: usize = 0;
    let mut type_0: Dav1dObuType = 0 as Dav1dObuType;
    ret = parse_obu_header(
        data.offset(cnt as isize),
        cmp::min(2048 - cnt, obu_unit_size as c_int),
        &mut obu_size,
        &mut type_0,
        1 as c_int,
    );
    if ret < 0 || type_0 as c_uint != DAV1D_OBU_TD as c_int as c_uint || obu_size > 0 {
        return 0 as c_int;
    }
    cnt += obu_unit_size as c_int;
    let mut seq = 0;
    while cnt < 2048 {
        ret = leb(data.offset(cnt as isize), 2048 - cnt, &mut obu_unit_size);
        if ret < 0 || obu_unit_size.wrapping_add(ret as usize) > frame_unit_size {
            return 0 as c_int;
        }
        cnt += ret;
        temporal_unit_size =
            (temporal_unit_size as c_ulong).wrapping_sub(ret as c_ulong) as usize as usize;
        frame_unit_size =
            (frame_unit_size as c_ulong).wrapping_sub(ret as c_ulong) as usize as usize;
        ret = parse_obu_header(
            data.offset(cnt as isize),
            cmp::min(2048 - cnt, obu_unit_size as c_int),
            &mut obu_size,
            &mut type_0,
            1 as c_int,
        );
        if ret < 0 {
            return 0 as c_int;
        }
        cnt += obu_unit_size as c_int;
        match type_0 as c_uint {
            DAV1D_OBU_SEQ_HDR => {
                seq = 1 as c_int;
            }
            DAV1D_OBU_FRAME | DAV1D_OBU_FRAME_HDR => return seq,
            DAV1D_OBU_TD | DAV1D_OBU_TILE_GRP => return 0 as c_int,
            _ => {}
        }
        temporal_unit_size = temporal_unit_size.wrapping_sub(obu_unit_size);
        frame_unit_size = frame_unit_size.wrapping_sub(obu_unit_size) as usize as usize;
        if frame_unit_size <= 0 {
            return 0 as c_int;
        }
    }
    return seq;
}

unsafe extern "C" fn annexb_open(
    c: *mut AnnexbInputContext,
    file: *const c_char,
    fps: *mut c_uint,
    num_frames: *mut c_uint,
    timebase: *mut c_uint,
) -> c_int {
    let mut res;
    let mut len: usize = 0;
    (*c).f = fopen(file, b"rb\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;
    }
    *fps.offset(0) = 25 as c_int as c_uint;
    *fps.offset(1) = 1 as c_int as c_uint;
    *timebase.offset(0) = 25 as c_int as c_uint;
    *timebase.offset(1) = 1 as c_int as c_uint;
    *num_frames = 0 as c_int as c_uint;
    loop {
        res = leb128((*c).f, &mut len);
        if res < 0 {
            break;
        }
        fseeko((*c).f, len as libc::off_t, 1 as c_int);
        *num_frames = (*num_frames).wrapping_add(1);
    }
    fseeko((*c).f, 0, 0 as c_int);
    return 0 as c_int;
}

unsafe extern "C" fn annexb_read(c: *mut AnnexbInputContext, data: *mut Dav1dData) -> c_int {
    let mut len: usize = 0;
    let mut res;
    if (*c).temporal_unit_size == 0 {
        res = leb128((*c).f, &mut (*c).temporal_unit_size);
        if res < 0 {
            return -1;
        }
    }
    if (*c).frame_unit_size == 0 {
        res = leb128((*c).f, &mut (*c).frame_unit_size);
        if res < 0 || ((*c).frame_unit_size).wrapping_add(res as usize) > (*c).temporal_unit_size {
            return -1;
        }
        (*c).temporal_unit_size =
            ((*c).temporal_unit_size as c_ulong).wrapping_sub(res as c_ulong) as usize as usize;
    }
    res = leb128((*c).f, &mut len);
    if res < 0 || len.wrapping_add(res as usize) > (*c).frame_unit_size {
        return -1;
    }
    let ptr: *mut u8 = dav1d_data_create(NonNull::new(data), len);
    if ptr.is_null() {
        return -1;
    }
    (*c).temporal_unit_size =
        ((*c).temporal_unit_size).wrapping_sub(len.wrapping_add(res as usize)) as usize as usize;
    (*c).frame_unit_size =
        ((*c).frame_unit_size).wrapping_sub(len.wrapping_add(res as usize)) as usize;
    if fread(ptr as *mut c_void, len, 1, (*c).f) != 1 {
        fprintf(
            stderr(),
            b"Failed to read frame data: %s\n\0" as *const u8 as *const c_char,
            strerror(*errno_location()),
        );
        dav1d_data_unref(NonNull::new(data));
        return -1;
    }
    return 0 as c_int;
}

unsafe extern "C" fn annexb_close(c: *mut AnnexbInputContext) {
    fclose((*c).f);
}

#[no_mangle]
pub static mut annexb_demuxer: Demuxer = Demuxer {
    priv_data_size: ::core::mem::size_of::<AnnexbInputContext>() as c_ulong as c_int,
    name: b"annexb\0" as *const u8 as *const c_char,
    probe_sz: 2048 as c_int,
    probe: Some(annexb_probe),
    open: Some(annexb_open),
    read: Some(annexb_read),
    seek: None,
    close: Some(annexb_close),
};