#![deny(missing_docs)]
use std::slice;
use std::sync::Arc;
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;
use std::os::raw::c_int;
use std::os::raw::c_void;
use libc::ptrdiff_t;
use libc::size_t;
use num_derive::*;
use num_traits::cast::FromPrimitive;
use crate::prelude as rav1e;
type PixelRange = rav1e::PixelRange;
type ChromaSamplePosition = rav1e::ChromaSamplePosition;
type ChromaSampling = rav1e::ChromaSampling;
type MatrixCoefficients = rav1e::MatrixCoefficients;
type ColorPrimaries = rav1e::ColorPrimaries;
type TransferCharacteristics = rav1e::TransferCharacteristics;
type Rational = rav1e::Rational;
type FrameTypeOverride = rav1e::FrameTypeOverride;
type FrameOpaqueCb = Option<extern fn(*mut c_void)>;
#[derive(Clone)]
enum FrameInternal {
U8(Arc<rav1e::Frame<u8>>),
U16(Arc<rav1e::Frame<u16>>),
}
impl From<rav1e::Frame<u8>> for FrameInternal {
fn from(f: rav1e::Frame<u8>) -> FrameInternal {
FrameInternal::U8(Arc::new(f))
}
}
impl From<rav1e::Frame<u16>> for FrameInternal {
fn from(f: rav1e::Frame<u16>) -> FrameInternal {
FrameInternal::U16(Arc::new(f))
}
}
struct FrameOpaque {
opaque: *mut c_void,
cb: FrameOpaqueCb,
}
unsafe impl Send for FrameOpaque {}
impl Default for FrameOpaque {
fn default() -> Self {
FrameOpaque { opaque: std::ptr::null_mut(), cb: None }
}
}
impl Drop for FrameOpaque {
fn drop(&mut self) {
let FrameOpaque { opaque, cb } = self;
if let Some(cb) = cb {
cb(*opaque);
}
}
}
pub struct Frame {
fi: FrameInternal,
frame_type: FrameTypeOverride,
opaque: Option<FrameOpaque>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)]
pub enum EncoderStatus {
Success = 0,
NeedMoreData,
EnoughData,
LimitReached,
Encoded,
Failure = -1,
NotReady = -2,
}
impl EncoderStatus {
fn to_c(&self) -> *const u8 {
use self::EncoderStatus::*;
match self {
Success => "Normal operation\0".as_ptr(),
NeedMoreData => "The encoder needs more data to produce an output packet\0".as_ptr(),
EnoughData => "There are enough frames in the queue\0".as_ptr(),
LimitReached => "The encoder has already produced the number of frames requested\0".as_ptr(),
Encoded => "A Frame had been encoded but not emitted yet\0".as_ptr(),
Failure => "Generic fatal error\0".as_ptr(),
NotReady => "First-pass stats data not retrieved or not enough second-pass data provided\0".as_ptr(),
}
}
}
impl From<Option<rav1e::EncoderStatus>> for EncoderStatus {
fn from(status: Option<rav1e::EncoderStatus>) -> Self {
match status {
None => EncoderStatus::Success,
Some(s) => match s {
rav1e::EncoderStatus::NeedMoreData => EncoderStatus::NeedMoreData,
rav1e::EncoderStatus::EnoughData => EncoderStatus::EnoughData,
rav1e::EncoderStatus::LimitReached => EncoderStatus::LimitReached,
rav1e::EncoderStatus::Encoded => EncoderStatus::Encoded,
rav1e::EncoderStatus::Failure => EncoderStatus::Failure,
rav1e::EncoderStatus::NotReady => EncoderStatus::NotReady,
},
}
}
}
pub struct Config {
cfg: rav1e::Config,
}
enum EncContext {
U8(rav1e::Context<u8>),
U16(rav1e::Context<u16>),
}
impl EncContext {
fn new_frame(&self) -> FrameInternal {
match self {
EncContext::U8(ctx) => ctx.new_frame().into(),
EncContext::U16(ctx) => ctx.new_frame().into(),
}
}
fn send_frame(
&mut self, frame: Option<FrameInternal>, frame_type: FrameTypeOverride,
opaque: Option<Box<dyn std::any::Any + Send>>,
) -> Result<(), rav1e::EncoderStatus> {
let info =
rav1e::FrameParameters { frame_type_override: frame_type, opaque };
if let Some(frame) = frame {
match (self, frame) {
(EncContext::U8(ctx), FrameInternal::U8(ref f)) => {
ctx.send_frame((f.clone(), info))
}
(EncContext::U16(ctx), FrameInternal::U16(ref f)) => {
ctx.send_frame((f.clone(), info))
}
_ => Err(rav1e::EncoderStatus::Failure),
}
} else {
match self {
EncContext::U8(ctx) => ctx.send_frame(None),
EncContext::U16(ctx) => ctx.send_frame(None),
}
}
}
fn receive_packet(&mut self) -> Result<Packet, rav1e::EncoderStatus> {
fn receive_packet<T: rav1e::Pixel>(
ctx: &mut rav1e::Context<T>,
) -> Result<Packet, rav1e::EncoderStatus> {
ctx.receive_packet().map(|p| {
let mut p = std::mem::ManuallyDrop::new(p);
let opaque = p.opaque.take().map_or_else(
|| std::ptr::null_mut(),
|o| {
let mut opaque = o.downcast::<FrameOpaque>().unwrap();
opaque.cb = None;
opaque.opaque
},
);
let p = std::mem::ManuallyDrop::into_inner(p);
let rav1e::Packet { data, input_frameno, frame_type, .. } = p;
let len = data.len();
let data = Box::into_raw(data.into_boxed_slice()) as *const u8;
Packet { data, len, input_frameno, frame_type, opaque }
})
}
match self {
EncContext::U8(ctx) => receive_packet(ctx),
EncContext::U16(ctx) => receive_packet(ctx),
}
}
fn container_sequence_header(&self) -> Vec<u8> {
match self {
EncContext::U8(ctx) => ctx.container_sequence_header(),
EncContext::U16(ctx) => ctx.container_sequence_header(),
}
}
fn twopass_bytes_needed(&mut self) -> usize {
match self {
EncContext::U8(ctx) => ctx.twopass_bytes_needed(),
EncContext::U16(ctx) => ctx.twopass_bytes_needed(),
}
}
fn twopass_in(&mut self, buf: &[u8]) -> Result<usize, rav1e::EncoderStatus> {
match self {
EncContext::U8(ctx) => ctx.twopass_in(buf),
EncContext::U16(ctx) => ctx.twopass_in(buf),
}
}
fn twopass_out(&mut self) -> Option<&[u8]> {
match self {
EncContext::U8(ctx) => ctx.twopass_out(),
EncContext::U16(ctx) => ctx.twopass_out(),
}
}
fn rc_summary_size(&self) -> usize {
match self {
EncContext::U8(ctx) => ctx.rc_summary_size(),
EncContext::U16(ctx) => ctx.rc_summary_size(),
}
}
fn rc_receive_pass_data(&mut self) -> Option<rav1e::RcData> {
match self {
EncContext::U8(ctx) => ctx.rc_receive_pass_data(),
EncContext::U16(ctx) => ctx.rc_receive_pass_data(),
}
}
fn rc_second_pass_data_required(&self) -> usize {
match self {
EncContext::U8(ctx) => ctx.rc_second_pass_data_required(),
EncContext::U16(ctx) => ctx.rc_second_pass_data_required(),
}
}
fn rc_send_pass_data(
&mut self, data: &[u8],
) -> Result<(), rav1e::EncoderStatus> {
match self {
EncContext::U8(ctx) => ctx.rc_send_pass_data(data),
EncContext::U16(ctx) => ctx.rc_send_pass_data(data),
}
}
}
pub struct Context {
ctx: EncContext,
last_err: Option<rav1e::EncoderStatus>,
}
type FrameType = rav1e::FrameType;
#[repr(C)]
pub struct Packet {
pub data: *const u8,
pub len: size_t,
pub input_frameno: u64,
pub frame_type: FrameType,
pub opaque: *mut c_void,
}
#[no_mangle]
pub unsafe extern fn rav1e_version_short() -> *const c_char {
concat!(env!("CARGO_PKG_VERSION"), "\0").as_ptr() as *const c_char
}
#[no_mangle]
pub unsafe extern fn rav1e_version_full() -> *const c_char {
concat!(
env!("CARGO_PKG_VERSION"),
" (",
env!("VERGEN_SEMVER_LIGHTWEIGHT"),
")\0"
)
.as_ptr() as *const c_char
}
#[repr(C)]
pub struct Data {
pub data: *const u8,
pub len: size_t,
}
#[no_mangle]
pub unsafe extern fn rav1e_data_unref(data: *mut Data) {
if !data.is_null() {
let data = Box::from_raw(data);
let _ = Vec::from_raw_parts(
data.data as *mut u8,
data.len as usize,
data.len as usize,
);
}
}
#[no_mangle]
pub unsafe extern fn rav1e_config_default() -> *mut Config {
let cfg = rav1e::Config::default();
let c = Box::new(Config { cfg });
Box::into_raw(c)
}
unsafe fn decode_slice<'a>(
data: *mut *const u8, len: *mut size_t,
) -> (c_int, Option<&'a [u8]>) {
use std::convert::TryInto;
if *len < 8 {
return (8, None);
}
let buf = slice::from_raw_parts(*data, *len as usize);
let (len_bytes, rest) = buf.split_at(std::mem::size_of::<u64>());
let buf_len = u64::from_be_bytes(len_bytes.try_into().unwrap()) as usize;
let full_len = buf_len + 8;
if buf_len > rest.len() {
return (full_len as c_int, None);
}
*len -= full_len;
*data = (*data).offset(full_len.try_into().unwrap());
(0, Some(&rest[..buf_len]))
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_rc_summary(
cfg: *mut Config, data: *mut *const u8, len: *mut size_t,
) -> c_int {
if data.is_null() {
(*cfg).cfg.rate_control.summary = None;
return 0;
}
let (needed, maybe_buf) = decode_slice(data, len);
if maybe_buf.is_none() {
return needed;
}
let summary = rav1e::RateControlSummary::from_slice(maybe_buf.unwrap()).ok();
if summary.is_none() {
-1
} else {
(*cfg).cfg.rate_control.summary = summary;
0
}
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_emit_data(
cfg: *mut Config, emit: c_int,
) {
(*cfg).cfg.rate_control.emit_pass_data = emit != 0;
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_sample_aspect_ratio(
cfg: *mut Config, sample_aspect_ratio: Rational,
) {
(*cfg).cfg.enc.sample_aspect_ratio = sample_aspect_ratio
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_time_base(
cfg: *mut Config, time_base: Rational,
) {
(*cfg).cfg.enc.time_base = time_base
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_pixel_format(
cfg: *mut Config, bit_depth: u8, subsampling: ChromaSampling,
chroma_pos: ChromaSamplePosition, pixel_range: PixelRange,
) -> c_int {
if bit_depth != 8 && bit_depth != 10 && bit_depth != 12 {
return -1;
}
(*cfg).cfg.enc.bit_depth = bit_depth as usize;
let subsampling_val =
std::mem::transmute::<ChromaSampling, i32>(subsampling);
if ChromaSampling::from_i32(subsampling_val).is_none() {
return -1;
}
(*cfg).cfg.enc.chroma_sampling = subsampling;
let chroma_pos_val =
std::mem::transmute::<ChromaSamplePosition, i32>(chroma_pos);
if ChromaSamplePosition::from_i32(chroma_pos_val).is_none() {
return -1;
}
(*cfg).cfg.enc.chroma_sample_position = chroma_pos;
let pixel_range_val = std::mem::transmute::<PixelRange, i32>(pixel_range);
if PixelRange::from_i32(pixel_range_val).is_none() {
return -1;
}
(*cfg).cfg.enc.pixel_range = pixel_range;
0
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_color_description(
cfg: *mut Config, matrix: MatrixCoefficients, primaries: ColorPrimaries,
transfer: TransferCharacteristics,
) -> c_int {
(*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
matrix_coefficients: matrix,
color_primaries: primaries,
transfer_characteristics: transfer,
});
if (*cfg).cfg.enc.color_description.is_some() {
0
} else {
-1
}
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_content_light(
cfg: *mut Config, max_content_light_level: u16,
max_frame_average_light_level: u16,
) -> c_int {
(*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
max_content_light_level,
max_frame_average_light_level,
});
if (*cfg).cfg.enc.content_light.is_some() {
0
} else {
-1
}
}
#[no_mangle]
pub unsafe extern fn rav1e_config_set_mastering_display(
cfg: *mut Config, primaries: *const rav1e::ChromaticityPoint,
white_point: rav1e::ChromaticityPoint, max_luminance: u32,
min_luminance: u32,
) -> c_int {
let primaries = *(primaries as *const [rav1e::ChromaticityPoint; 3]);
(*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
primaries,
white_point,
max_luminance,
min_luminance,
});
if (*cfg).cfg.enc.mastering_display.is_some() {
0
} else {
-1
}
}
#[no_mangle]
pub unsafe extern fn rav1e_config_unref(cfg: *mut Config) {
if !cfg.is_null() {
let _ = Box::from_raw(cfg);
}
}
fn tile_log2(blk_size: usize, target: usize) -> usize {
let mut k = 0;
while (blk_size << k) < target {
k += 1;
}
k
}
fn check_tile_log2(n: Result<usize, ()>) -> Result<usize, ()> {
match n {
Ok(n) => {
if ((1 << tile_log2(1, n)) - n) == 0 || n == 0 {
Ok(n)
} else {
Err(())
}
}
Err(e) => Err(e),
}
}
fn check_frame_size(n: Result<usize, ()>) -> Result<usize, ()> {
match n {
Ok(n) => {
if n >= 16 && n < u16::max_value().into() {
Ok(n)
} else {
Err(())
}
}
Err(e) => Err(e),
}
}
unsafe fn option_match(
cfg: *mut Config, key: *const c_char, value: *const c_char,
) -> Result<(), ()> {
let key = CStr::from_ptr(key).to_str().map_err(|_| ())?;
let value = CStr::from_ptr(value).to_str().map_err(|_| ())?;
let enc = &mut (*cfg).cfg.enc;
match key {
"width" => enc.width = check_frame_size(value.parse().map_err(|_| ()))?,
"height" => enc.height = check_frame_size(value.parse().map_err(|_| ()))?,
"speed" => {
enc.speed_settings =
rav1e::SpeedSettings::from_preset(value.parse().map_err(|_| ())?)
}
"threads" => (*cfg).cfg.threads = value.parse().map_err(|_| ())?,
"tiles" => enc.tiles = value.parse().map_err(|_| ())?,
"tile_rows" => {
enc.tile_rows = check_tile_log2(value.parse().map_err(|_| ()))?
}
"tile_cols" => {
enc.tile_cols = check_tile_log2(value.parse().map_err(|_| ()))?
}
"tune" => enc.tune = value.parse().map_err(|_| ())?,
"quantizer" => enc.quantizer = value.parse().map_err(|_| ())?,
"min_quantizer" => enc.min_quantizer = value.parse().map_err(|_| ())?,
"bitrate" => enc.bitrate = value.parse().map_err(|_| ())?,
"key_frame_interval" => {
enc.set_key_frame_interval(
enc.min_key_frame_interval,
value.parse().map_err(|_| ())?,
);
}
"min_key_frame_interval" => {
enc.set_key_frame_interval(
value.parse().map_err(|_| ())?,
enc.max_key_frame_interval,
);
}
"switch_frame_interval" => {
enc.switch_frame_interval = value.parse().map_err(|_| ())?
}
"reservoir_frame_delay" => {
enc.reservoir_frame_delay = Some(value.parse().map_err(|_| ())?)
}
"rdo_lookahead_frames" => {
enc.rdo_lookahead_frames = value.parse().map_err(|_| ())?
}
"low_latency" => enc.low_latency = value.parse().map_err(|_| ())?,
"enable_timing_info" => {
enc.enable_timing_info = value.parse().map_err(|_| ())?
}
"still_picture" => enc.still_picture = value.parse().map_err(|_| ())?,
_ => return Err(()),
}
Ok(())
}
#[no_mangle]
pub unsafe extern fn rav1e_config_parse(
cfg: *mut Config, key: *const c_char, value: *const c_char,
) -> c_int {
if option_match(cfg, key, value) == Ok(()) {
0
} else {
-1
}
}
#[no_mangle]
pub unsafe extern fn rav1e_config_parse_int(
cfg: *mut Config, key: *const c_char, value: c_int,
) -> c_int {
let val = CString::new(value.to_string()).unwrap();
if option_match(cfg, key, val.as_ptr()) == Ok(()) {
0
} else {
-1
}
}
#[no_mangle]
pub unsafe extern fn rav1e_context_new(cfg: *const Config) -> *mut Context {
let cfg = &(*cfg).cfg;
let enc = &cfg.enc;
let ctx = match enc.bit_depth {
8 => cfg.new_context().map(EncContext::U8),
_ => cfg.new_context().map(EncContext::U16),
};
if let Ok(ctx) = ctx {
Box::into_raw(Box::new(Context { ctx, last_err: None }))
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern fn rav1e_context_unref(ctx: *mut Context) {
if !ctx.is_null() {
let _ = Box::from_raw(ctx);
}
}
#[no_mangle]
pub unsafe extern fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
let fi = (*ctx).ctx.new_frame();
let frame_type = rav1e::FrameTypeOverride::No;
let f = Frame { fi, frame_type, opaque: None };
let frame = Box::new(f.into());
Box::into_raw(frame)
}
#[no_mangle]
pub unsafe extern fn rav1e_frame_unref(frame: *mut Frame) {
if !frame.is_null() {
let _ = Box::from_raw(frame);
}
}
#[no_mangle]
pub unsafe extern fn rav1e_frame_set_type(
frame: *mut Frame, frame_type: FrameTypeOverride,
) -> c_int {
let frame_type_val =
std::mem::transmute::<FrameTypeOverride, i32>(frame_type);
if FrameTypeOverride::from_i32(frame_type_val).is_none() {
return -1;
}
(*frame).frame_type = frame_type;
0
}
#[no_mangle]
pub unsafe extern fn rav1e_frame_set_opaque(
frame: *mut Frame, opaque: *mut c_void, cb: FrameOpaqueCb,
) {
if opaque.is_null() {
(*frame).opaque = None;
} else {
(*frame).opaque = Some(FrameOpaque { opaque, cb });
}
}
#[no_mangle]
pub unsafe extern fn rav1e_twopass_out(ctx: *mut Context) -> *mut Data {
let buf = (*ctx).ctx.twopass_out();
if buf.is_none() {
return std::ptr::null_mut();
}
let v = buf.unwrap().to_vec();
Box::into_raw(Box::new(Data {
len: v.len(),
data: Box::into_raw(v.into_boxed_slice()) as *mut u8,
}))
}
#[derive(Debug, PartialEq)]
#[repr(C)]
pub enum RcDataKind {
Summary,
Frame,
Empty,
}
#[no_mangle]
pub unsafe extern fn rav1e_rc_summary_size(ctx: *const Context) -> size_t {
(*ctx).ctx.rc_summary_size() as size_t + 8
}
#[no_mangle]
pub unsafe extern fn rav1e_rc_receive_pass_data(
ctx: *mut Context, data: *mut *mut Data,
) -> RcDataKind {
use crate::api::RcData::*;
let (buf, kind) = match (*ctx).ctx.rc_receive_pass_data() {
Some(Summary(data)) => (data, RcDataKind::Summary),
Some(Frame(data)) => (data, RcDataKind::Frame),
None => return RcDataKind::Empty,
};
let mut full_buf = Vec::with_capacity(buf.len() + 8);
full_buf.extend_from_slice(&(buf.len() as u64).to_be_bytes());
full_buf.extend_from_slice(&buf);
let full_buf = full_buf.into_boxed_slice();
*data = Box::into_raw(Box::new(Data {
len: full_buf.len(),
data: Box::into_raw(full_buf) as *mut u8,
}));
kind
}
#[no_mangle]
pub unsafe extern fn rav1e_rc_second_pass_data_required(
ctx: *const Context,
) -> i32 {
(*ctx).ctx.rc_second_pass_data_required() as i32
}
#[no_mangle]
pub unsafe extern fn rav1e_rc_send_pass_data(
ctx: *mut Context, data: *mut *const u8, len: *mut size_t,
) -> c_int {
let (need, maybe_buf) = decode_slice(data, len);
if maybe_buf.is_none() {
return need;
}
let ret = (*ctx)
.ctx
.rc_send_pass_data(maybe_buf.unwrap())
.map(|_v| None)
.unwrap_or_else(|e| Some(e));
(*ctx).last_err = ret;
if ret.is_some() {
-1
} else {
0
}
}
#[no_mangle]
pub unsafe extern fn rav1e_twopass_bytes_needed(ctx: *mut Context) -> size_t {
(*ctx).ctx.twopass_bytes_needed() as size_t
}
#[no_mangle]
pub unsafe extern fn rav1e_twopass_in(
ctx: *mut Context, buf: *mut u8, buf_size: size_t,
) -> c_int {
let buf_slice = slice::from_raw_parts(buf, buf_size as usize);
let r = (*ctx).ctx.twopass_in(buf_slice);
match r {
Ok(v) => v as c_int,
Err(v) => {
(*ctx).last_err = Some(v);
-1
}
}
}
#[no_mangle]
pub unsafe extern fn rav1e_send_frame(
ctx: *mut Context, frame: *mut Frame,
) -> EncoderStatus {
let frame_internal =
if frame.is_null() { None } else { Some((*frame).fi.clone()) };
let frame_type = if frame.is_null() {
rav1e::FrameTypeOverride::No
} else {
(*frame).frame_type
};
let maybe_opaque = if frame.is_null() {
None
} else {
(*frame)
.opaque
.take()
.map(|o| Box::new(o) as Box<dyn std::any::Any + Send>)
};
let ret = (*ctx)
.ctx
.send_frame(frame_internal, frame_type, maybe_opaque)
.map(|_v| None)
.unwrap_or_else(|e| Some(e));
(*ctx).last_err = ret;
ret.into()
}
#[no_mangle]
pub unsafe extern fn rav1e_last_status(ctx: *const Context) -> EncoderStatus {
(*ctx).last_err.into()
}
#[no_mangle]
pub unsafe extern fn rav1e_status_to_str(
status: EncoderStatus,
) -> *const c_char {
if EncoderStatus::from_i32(std::mem::transmute(status)).is_none() {
return std::ptr::null();
}
status.to_c() as *const c_char
}
#[no_mangle]
pub unsafe extern fn rav1e_receive_packet(
ctx: *mut Context, pkt: *mut *mut Packet,
) -> EncoderStatus {
let ret = (*ctx)
.ctx
.receive_packet()
.map(|packet| {
*pkt = Box::into_raw(Box::new(packet));
None
})
.unwrap_or_else(|e| Some(e));
(*ctx).last_err = ret;
ret.into()
}
#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
if !pkt.is_null() {
let pkt = Box::from_raw(pkt);
let _ = Vec::from_raw_parts(
pkt.data as *mut u8,
pkt.len as usize,
pkt.len as usize,
);
}
}
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(
ctx: *const Context,
) -> *mut Data {
let buf = (*ctx).ctx.container_sequence_header();
Box::into_raw(Box::new(Data {
len: buf.len(),
data: Box::into_raw(buf.into_boxed_slice()) as *mut u8,
}))
}
fn rav1e_frame_fill_plane_internal<T: rav1e::Pixel>(
f: &mut Arc<rav1e::Frame<T>>, plane: c_int, data_slice: &[u8],
stride: ptrdiff_t, bytewidth: c_int,
) {
let input = Arc::make_mut(f);
input.planes[plane as usize].copy_from_raw_u8(
data_slice,
stride as usize,
bytewidth as usize,
);
}
#[no_mangle]
pub unsafe extern fn rav1e_frame_fill_plane(
frame: *mut Frame, plane: c_int, data: *const u8, data_len: size_t,
stride: ptrdiff_t, bytewidth: c_int,
) {
let data_slice = slice::from_raw_parts(data, data_len as usize);
match (*frame).fi {
FrameInternal::U8(ref mut f) => {
rav1e_frame_fill_plane_internal(f, plane, data_slice, stride, bytewidth)
}
FrameInternal::U16(ref mut f) => {
rav1e_frame_fill_plane_internal(f, plane, data_slice, stride, bytewidth)
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::ffi::CString;
#[test]
fn forward_opaque() {
unsafe {
let rac = rav1e_config_default();
let w = CString::new("width").unwrap();
rav1e_config_parse_int(rac, w.as_ptr(), 64);
let h = CString::new("height").unwrap();
rav1e_config_parse_int(rac, h.as_ptr(), 64);
let s = CString::new("speed").unwrap();
rav1e_config_parse_int(rac, s.as_ptr(), 10);
let rax = rav1e_context_new(rac);
let f = rav1e_frame_new(rax);
for i in 0..30 {
let v = Box::new(i as u8);
extern fn cb(o: *mut c_void) {
let v = unsafe { Box::from_raw(o as *mut u8) };
eprintln!("Would free {}", v);
}
rav1e_frame_set_opaque(f, Box::into_raw(v) as *mut c_void, Some(cb));
rav1e_send_frame(rax, f);
}
rav1e_send_frame(rax, std::ptr::null_mut());
for _ in 0..15 {
let mut p: *mut Packet = std::ptr::null_mut();
let ret = rav1e_receive_packet(rax, &mut p);
if ret == EncoderStatus::Success {
let v = Box::from_raw((*p).opaque as *mut u8);
eprintln!("Opaque {}", v);
}
if ret == EncoderStatus::LimitReached {
break;
}
}
let v = Box::new(42u64);
extern fn cb(o: *mut c_void) {
let v = unsafe { Box::from_raw(o as *mut u64) };
eprintln!("Would free {}", v);
}
rav1e_frame_set_opaque(f, Box::into_raw(v) as *mut c_void, Some(cb));
rav1e_frame_unref(f);
rav1e_context_unref(rax);
rav1e_config_unref(rac);
}
}
#[test]
fn two_pass_encoding() {
unsafe {
let rac = rav1e_config_default();
let w = CString::new("width").unwrap();
rav1e_config_parse_int(rac, w.as_ptr(), 64);
let h = CString::new("height").unwrap();
rav1e_config_parse_int(rac, h.as_ptr(), 64);
let s = CString::new("speed").unwrap();
rav1e_config_parse_int(rac, s.as_ptr(), 10);
let s = CString::new("bitrate").unwrap();
rav1e_config_parse_int(rac, s.as_ptr(), 1000);
rav1e_config_set_emit_data(rac, 1);
let rax = rav1e_context_new(rac);
let f = rav1e_frame_new(rax);
for _ in 0..10 {
rav1e_send_frame(rax, f);
}
rav1e_send_frame(rax, std::ptr::null_mut());
let mut frame_data = std::collections::VecDeque::new();
let mut summary: *mut Data = std::ptr::null_mut();
loop {
let mut p: *mut Packet = std::ptr::null_mut();
let ret = rav1e_receive_packet(rax, &mut p);
rav1e_packet_unref(p);
if ret == EncoderStatus::LimitReached {
let kind = rav1e_rc_receive_pass_data(rax, &mut summary);
assert_eq!(kind, RcDataKind::Summary);
eprintln!("Got rc summary {} bytes", (*summary).len);
break;
} else if ret == EncoderStatus::Encoded
|| ret == EncoderStatus::Success
{
let mut p: *mut Data = std::ptr::null_mut();
let kind = rav1e_rc_receive_pass_data(rax, &mut p);
assert_eq!(kind, RcDataKind::Frame);
eprintln!("Got rc frame data {} bytes", (*p).len);
frame_data.push_back(p);
}
}
rav1e_config_set_emit_data(rac, 0);
let mut data = (*summary).data;
let mut len = (*summary).len;
let ret = rav1e_config_set_rc_summary(rac, &mut data, &mut len);
assert_eq!(ret, 0);
rav1e_data_unref(summary);
for _ in 0..10 {
rav1e_send_frame(rax, f);
}
rav1e_send_frame(rax, std::ptr::null_mut());
loop {
let mut p: *mut Packet = std::ptr::null_mut();
while rav1e_rc_second_pass_data_required(rax) > 0 {
let d = frame_data.pop_front().unwrap();
let mut data = (*d).data;
let mut len = (*d).len;
rav1e_rc_send_pass_data(rax, &mut data, &mut len);
rav1e_data_unref(d);
}
let ret = rav1e_receive_packet(rax, &mut p);
rav1e_packet_unref(p);
if ret == EncoderStatus::LimitReached {
break;
}
}
rav1e_frame_unref(f);
rav1e_context_unref(rax);
rav1e_config_unref(rac);
}
}
}