use core::{mem::MaybeUninit, ptr};
use x264::*;
use {Data, Encoding, Error, Image, Picture, Result, Setup};
pub struct Encoder {
raw: *mut x264_t,
params: x264_param_t,
}
impl Encoder {
pub fn builder() -> Setup {
Setup::default()
}
#[doc(hidden)]
pub unsafe fn from_raw(raw: *mut x264_t) -> Self {
let mut params = MaybeUninit::uninit();
x264_encoder_parameters(raw, params.as_mut_ptr());
Self {
raw,
params: params.assume_init(),
}
}
pub fn encode(&mut self, pts: i64, image: Image) -> Result<(Data, Picture)> {
assert_eq!(image.width(), self.width());
assert_eq!(image.height(), self.height());
assert_eq!(image.encoding(), self.encoding());
unsafe { self.encode_unchecked(pts, image) }
}
pub unsafe fn encode_unchecked(&mut self, pts: i64, image: Image) -> Result<(Data, Picture)> {
let image = image.raw();
let mut picture = MaybeUninit::uninit();
x264_picture_init(picture.as_mut_ptr());
let mut picture = picture.assume_init();
picture.i_pts = pts;
picture.img = image;
let mut len = 0;
let mut stuff = MaybeUninit::uninit();
let mut raw = MaybeUninit::uninit();
let err = x264_encoder_encode(self.raw, stuff.as_mut_ptr(), &mut len, &mut picture, raw.as_mut_ptr());
if err < 0 {
Err(Error)
} else {
let stuff = stuff.assume_init();
let raw = raw.assume_init();
let data = Data::from_raw_parts(stuff, len as usize);
let picture = Picture::from_raw(raw);
Ok((data, picture))
}
}
pub fn headers(&mut self) -> Result<Data> {
let mut len = 0;
let mut stuff = MaybeUninit::uninit();
let err = unsafe { x264_encoder_headers(self.raw, stuff.as_mut_ptr(), &mut len) };
if err < 0 {
Err(Error)
} else {
let stuff = unsafe { stuff.assume_init() };
Ok(unsafe { Data::from_raw_parts(stuff, len as usize) })
}
}
pub fn flush(self) -> Flush {
Flush { encoder: self }
}
pub fn width(&self) -> i32 {
self.params.i_width
}
pub fn height(&self) -> i32 {
self.params.i_height
}
pub fn encoding(&self) -> Encoding {
unsafe { Encoding::from_raw(self.params.i_csp) }
}
}
impl Drop for Encoder {
fn drop(&mut self) {
unsafe {
x264_encoder_close(self.raw);
}
}
}
pub struct Flush {
encoder: Encoder,
}
impl Flush {
pub fn next(&mut self) -> Option<Result<(Data, Picture)>> {
let enc = self.encoder.raw;
if unsafe { x264_encoder_delayed_frames(enc) } == 0 {
return None;
}
let mut len = 0;
let mut stuff = MaybeUninit::uninit();
let mut raw = MaybeUninit::uninit();
let err =
unsafe { x264_encoder_encode(enc, stuff.as_mut_ptr(), &mut len, ptr::null_mut(), raw.as_mut_ptr()) };
Some(if err < 0 {
Err(Error)
} else {
Ok(unsafe {
(
Data::from_raw_parts(stuff.assume_init(), len as usize),
Picture::from_raw(raw.assume_init()),
)
})
})
}
}