use crate::sys::*;
use anyhow::Result;
use cyberex::{void::*, xself::*};
use std::{ffi::CStr, marker::PhantomPinned, os::raw::*, pin::Pin};
use th_rs::{define::TH_ESStreamInfo, helper::packet::packet::Packet};
unsafe extern "C" fn com_cb(data: *const u8, len: c_int, info_ptr: *const c_void, user: *mut c_void) {
let p = opacue_to_mut::<Codec>(user as _);
let slice_data = std::slice::from_raw_parts(data, len as _);
let info = &*(info_ptr as *const TH_ESStreamInfo);
let packet = Packet::new(slice_data, info);
let _ = p.packet.insert(packet);
}
pub struct Codec {
p: HyVoid<()>,
packet: Option<Packet>,
err_buf: Vec<u8>,
_pin: PhantomPinned,
}
impl Codec {
pub fn new_with_config(select_str: &str, config_str: &str) -> Result<Pin<Box<Self>>> {
let pin_obj = Box::pin(Self {
p: HyVoid::from_ptr(unsafe { CodecCreate() }),
packet: None,
err_buf: vec![0; 128],
_pin: PhantomPinned,
});
let this = self_from_pinbox(&pin_obj);
let mut err_buf = vec![0; 128];
let ctx = this.p.as_ptr();
if unsafe { CodecConfig(ctx, config_str.as_ptr().cast(), config_str.len()) } != 0 {
let err_msg = CStr::from_bytes_until_nul(&err_buf)?.to_str()?;
anyhow::bail!("Init codec fail, error: {}", err_msg)
}
if unsafe {
CodecInit(
ctx,
select_str.as_ptr().cast(),
select_str.len() as _,
Some(com_cb),
HyVoidConst::from_ref(this).as_ptr() as _,
err_buf.as_mut_ptr().cast(),
err_buf.len() as _,
)
} != 0
{
let err_msg = CStr::from_bytes_until_nul(&err_buf)?.to_str()?;
anyhow::bail!("Init codec fail, error: {}", err_msg)
}
Ok(pin_obj)
}
pub fn new(select_str: &str) -> Result<Pin<Box<Self>>> {
Self::new_with_config(select_str, "")
}
pub fn write<'a>(self: &'a mut Pin<Box<Self>>, data: &[u8], info: &TH_ESStreamInfo) -> Result<Option<&'a Packet>> {
let this = unsafe { self_mut_from_pinbox(self) };
let err_buf = &mut this.err_buf;
this.packet.take();
if unsafe {
CodecInputData(
this.p.as_ptr(),
data.as_ptr().cast(),
data.len() as _,
info as *const _ as *const _,
err_buf.as_mut_ptr().cast(),
err_buf.len() as _,
)
} != 0
{
let err_msg = CStr::from_bytes_until_nul(&err_buf)?.to_str()?;
anyhow::bail!("Input data codec fail, error: {}", err_msg)
}
Ok(self.packet.as_ref())
}
}
impl Drop for Codec {
fn drop(&mut self) {
unsafe {
CodecDestory(self.p.as_ptr());
}
}
}