feat: basic ffi server to support other languages (#34)
* wip * wip * wip * wip not a fan of the way I do handles .. * errors and async semantic * fix example
This commit is contained in:
@@ -1,9 +1,26 @@
|
||||
use crate::video_frame_buffer::VideoFrameBuffer;
|
||||
use cxx::UniquePtr;
|
||||
use webrtc_sys::video_frame as vf_sys;
|
||||
|
||||
pub use vf_sys::ffi::VideoRotation;
|
||||
#[derive(Debug)]
|
||||
pub enum VideoRotation {
|
||||
VideoRotation0 = 0,
|
||||
VideoRotation90 = 90,
|
||||
VideoRotation180 = 180,
|
||||
VideoRotation270 = 270,
|
||||
}
|
||||
|
||||
use crate::video_frame_buffer::VideoFrameBuffer;
|
||||
impl From<vf_sys::ffi::VideoRotation> for VideoRotation {
|
||||
fn from(rotation: vf_sys::ffi::VideoRotation) -> Self {
|
||||
match rotation {
|
||||
vf_sys::ffi::VideoRotation::VideoRotation0 => Self::VideoRotation0,
|
||||
vf_sys::ffi::VideoRotation::VideoRotation90 => Self::VideoRotation90,
|
||||
vf_sys::ffi::VideoRotation::VideoRotation180 => Self::VideoRotation180,
|
||||
vf_sys::ffi::VideoRotation::VideoRotation270 => Self::VideoRotation270,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VideoFrame {
|
||||
cxx_handle: UniquePtr<vf_sys::ffi::VideoFrame>,
|
||||
@@ -47,7 +64,7 @@ impl VideoFrame {
|
||||
}
|
||||
|
||||
pub fn rotation(&self) -> VideoRotation {
|
||||
self.cxx_handle.rotation()
|
||||
self.cxx_handle.rotation().into()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
|
||||
@@ -2,10 +2,36 @@ use cxx::UniquePtr;
|
||||
use livekit_utils::enum_dispatch;
|
||||
use std::pin::Pin;
|
||||
use std::slice;
|
||||
use vfb_sys::ffi::VideoFrameBufferType;
|
||||
use webrtc_sys::video_frame_buffer as vfb_sys;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VideoFrameBufferType {
|
||||
Native,
|
||||
I420,
|
||||
I420A,
|
||||
I422,
|
||||
I444,
|
||||
I010,
|
||||
NV12,
|
||||
}
|
||||
|
||||
impl From<vfb_sys::ffi::VideoFrameBufferType> for VideoFrameBufferType {
|
||||
fn from(buffer_type: vfb_sys::ffi::VideoFrameBufferType) -> Self {
|
||||
match buffer_type {
|
||||
vfb_sys::ffi::VideoFrameBufferType::Native => Self::Native,
|
||||
vfb_sys::ffi::VideoFrameBufferType::I420 => Self::I420,
|
||||
vfb_sys::ffi::VideoFrameBufferType::I420A => Self::I420A,
|
||||
vfb_sys::ffi::VideoFrameBufferType::I422 => Self::I422,
|
||||
vfb_sys::ffi::VideoFrameBufferType::I444 => Self::I444,
|
||||
vfb_sys::ffi::VideoFrameBufferType::I010 => Self::I010,
|
||||
vfb_sys::ffi::VideoFrameBufferType::NV12 => Self::NV12,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VideoFrameBufferTrait {
|
||||
fn buffer_type(&self) -> VideoFrameBufferType; // Useful for the FFI
|
||||
fn width(&self) -> i32;
|
||||
fn height(&self) -> i32;
|
||||
fn to_i420(self) -> I420Buffer;
|
||||
@@ -25,6 +51,24 @@ pub trait PlanarYuv8Buffer: PlanarYuvBuffer {
|
||||
fn data_v(&self) -> &[u8];
|
||||
}
|
||||
|
||||
pub trait PlanarYuv16BBuffer: PlanarYuvBuffer {
|
||||
fn data_y(&self) -> &[u16];
|
||||
fn data_u(&self) -> &[u16];
|
||||
fn data_v(&self) -> &[u16];
|
||||
}
|
||||
|
||||
pub trait BiplanarYuvBuffer: VideoFrameBufferTrait {
|
||||
fn chroma_width(&self) -> i32;
|
||||
fn chroma_height(&self) -> i32;
|
||||
fn stride_y(&self) -> i32;
|
||||
fn stride_uv(&self) -> i32;
|
||||
}
|
||||
|
||||
pub trait BiplanarYuv8Buffer: BiplanarYuvBuffer {
|
||||
fn data_y(&self) -> &[u8];
|
||||
fn data_uv(&self) -> &[u8];
|
||||
}
|
||||
|
||||
pub enum VideoFrameBuffer {
|
||||
Native(NativeBuffer),
|
||||
I420(I420Buffer),
|
||||
@@ -38,16 +82,26 @@ pub enum VideoFrameBuffer {
|
||||
impl VideoFrameBuffer {
|
||||
pub(crate) fn new(mut cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
unsafe {
|
||||
match cxx_handle.buffer_type() {
|
||||
match cxx_handle.buffer_type().into() {
|
||||
VideoFrameBufferType::Native => Self::Native(NativeBuffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::I420 => {
|
||||
Self::I420(I420Buffer::new(cxx_handle.pin_mut().get_i420()))
|
||||
}
|
||||
VideoFrameBufferType::I420A => Self::I420A(I420ABuffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::I422 => Self::I422(I422Buffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::I444 => Self::I444(I444Buffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::I010 => Self::I010(I010Buffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::NV12 => Self::NV12(NV12Buffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::I420A => {
|
||||
Self::I420A(I420ABuffer::new(cxx_handle.pin_mut().get_i420a()))
|
||||
}
|
||||
VideoFrameBufferType::I422 => {
|
||||
Self::I422(I422Buffer::new(cxx_handle.pin_mut().get_i422()))
|
||||
}
|
||||
VideoFrameBufferType::I444 => {
|
||||
Self::I444(I444Buffer::new(cxx_handle.pin_mut().get_i444()))
|
||||
}
|
||||
VideoFrameBufferType::I010 => {
|
||||
Self::I010(I010Buffer::new(cxx_handle.pin_mut().get_i010()))
|
||||
}
|
||||
VideoFrameBufferType::NV12 => {
|
||||
Self::NV12(NV12Buffer::new(cxx_handle.pin_mut().get_nv12()))
|
||||
}
|
||||
_ => unreachable!(), // VideoFrameBufferType is represented as i32
|
||||
}
|
||||
}
|
||||
@@ -57,6 +111,7 @@ impl VideoFrameBuffer {
|
||||
impl VideoFrameBufferTrait for VideoFrameBuffer {
|
||||
enum_dispatch!(
|
||||
[Native, I420, I420A, I422, I444, I010, NV12]
|
||||
fnc!(buffer_type, &Self, [], VideoFrameBufferType);
|
||||
fnc!(width, &Self, [], i32);
|
||||
fnc!(height, &Self, [], i32);
|
||||
fnc!(to_i420, Self, [], I420Buffer);
|
||||
@@ -81,6 +136,13 @@ macro_rules! impl_video_frame_buffer {
|
||||
// Allow unused_unsafe when we don't do any cast ( e.g. NativeBuffer )
|
||||
#[allow(unused_unsafe)]
|
||||
impl VideoFrameBufferTrait for $x {
|
||||
fn buffer_type(&self) -> VideoFrameBufferType {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
(*ptr).buffer_type().into()
|
||||
}
|
||||
}
|
||||
|
||||
fn width(&self) -> i32 {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
@@ -179,6 +241,90 @@ macro_rules! impl_yuv8_buffer {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_yuv16_buffer {
|
||||
($x:ty $(, $cast:ident)*) => {
|
||||
impl PlanarYuv16BBuffer for $x {
|
||||
fn data_y(&self) -> &[u16] {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
slice::from_raw_parts((*ptr).data_y(), (self.width() * self.height()) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn data_u(&self) -> &[u16] {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
let chroma_height = (self.height() + 1) / 2;
|
||||
slice::from_raw_parts((*ptr).data_u(), (self.stride_u() * chroma_height) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn data_v(&self) -> &[u16] {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
let chroma_height = (self.height() + 1) / 2;
|
||||
slice::from_raw_parts((*ptr).data_v(), (self.stride_v() * chroma_height) as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_biyuv_buffer {
|
||||
($x:ty $(, $cast:ident)*) => {
|
||||
impl BiplanarYuvBuffer for $x {
|
||||
fn chroma_width(&self) -> i32 {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
(*ptr).chroma_width()
|
||||
}
|
||||
}
|
||||
|
||||
fn chroma_height(&self) -> i32 {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
(*ptr).chroma_height()
|
||||
}
|
||||
}
|
||||
|
||||
fn stride_y(&self) -> i32 {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
(*ptr).stride_y()
|
||||
}
|
||||
}
|
||||
|
||||
fn stride_uv(&self) -> i32 {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
(*ptr).stride_uv()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_biyuv8_buffer {
|
||||
($x:ty $(, $cast:ident)*) => {
|
||||
impl BiplanarYuv8Buffer for $x {
|
||||
fn data_y(&self) -> &[u8] {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
slice::from_raw_parts((*ptr).data_y(), (self.width() * self.height()) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn data_uv(&self) -> &[u8] {
|
||||
let ptr = recursive_cast!(&*self.cxx_handle $(, $cast)*);
|
||||
unsafe {
|
||||
let chroma_height = (self.height() + 1) / 2;
|
||||
slice::from_raw_parts((*ptr).data_uv(), (self.stride_uv() * chroma_height) as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct NativeBuffer {
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>,
|
||||
}
|
||||
@@ -188,36 +334,49 @@ pub struct I420Buffer {
|
||||
}
|
||||
|
||||
pub struct I420ABuffer {
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>,
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::I420ABuffer>,
|
||||
}
|
||||
|
||||
pub struct I422Buffer {
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>,
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::I422Buffer>,
|
||||
}
|
||||
|
||||
pub struct I444Buffer {
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>,
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::I444Buffer>,
|
||||
}
|
||||
|
||||
pub struct I010Buffer {
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>,
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::I010Buffer>,
|
||||
}
|
||||
|
||||
pub struct NV12Buffer {
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>,
|
||||
cxx_handle: UniquePtr<vfb_sys::ffi::NV12Buffer>,
|
||||
}
|
||||
|
||||
impl_video_frame_buffer!(NativeBuffer);
|
||||
impl_video_frame_buffer!(I420Buffer, i420_to_yuv8, yuv8_to_yuv, yuv_to_vfb);
|
||||
impl_video_frame_buffer!(I420ABuffer);
|
||||
impl_video_frame_buffer!(I422Buffer);
|
||||
impl_video_frame_buffer!(I444Buffer);
|
||||
impl_video_frame_buffer!(I010Buffer);
|
||||
impl_video_frame_buffer!(NV12Buffer);
|
||||
impl_video_frame_buffer!(I420ABuffer, i420a_to_yuv8, yuv8_to_yuv, yuv_to_vfb);
|
||||
impl_video_frame_buffer!(I422Buffer, i422_to_yuv8, yuv8_to_yuv, yuv_to_vfb);
|
||||
impl_video_frame_buffer!(I444Buffer, i444_to_yuv8, yuv8_to_yuv, yuv_to_vfb);
|
||||
impl_video_frame_buffer!(I010Buffer, i010_to_yuv16b, yuv16b_to_yuv, yuv_to_vfb);
|
||||
impl_video_frame_buffer!(NV12Buffer, nv12_to_biyuv8, biyuv8_to_biyuv, biyuv_to_vfb);
|
||||
|
||||
impl_yuv_buffer!(I420Buffer, i420_to_yuv8, yuv8_to_yuv);
|
||||
impl_yuv_buffer!(I420ABuffer, i420a_to_yuv8, yuv8_to_yuv);
|
||||
impl_yuv_buffer!(I422Buffer, i422_to_yuv8, yuv8_to_yuv);
|
||||
impl_yuv_buffer!(I444Buffer, i444_to_yuv8, yuv8_to_yuv);
|
||||
impl_yuv_buffer!(I010Buffer, i010_to_yuv16b, yuv16b_to_yuv);
|
||||
|
||||
impl_yuv8_buffer!(I420Buffer, i420_to_yuv8);
|
||||
impl_yuv8_buffer!(I420ABuffer, i420a_to_yuv8);
|
||||
impl_yuv8_buffer!(I422Buffer, i422_to_yuv8);
|
||||
impl_yuv8_buffer!(I444Buffer, i444_to_yuv8);
|
||||
|
||||
impl_yuv16_buffer!(I010Buffer, i010_to_yuv16b);
|
||||
|
||||
impl_biyuv_buffer!(NV12Buffer, nv12_to_biyuv8, biyuv8_to_biyuv);
|
||||
|
||||
impl_biyuv8_buffer!(NV12Buffer, nv12_to_biyuv8);
|
||||
|
||||
impl NativeBuffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
@@ -232,31 +391,31 @@ impl I420Buffer {
|
||||
}
|
||||
|
||||
impl I420ABuffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I420ABuffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl I422Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I422Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl I444Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I444Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl I010Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I010Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl NV12Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::NV12Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user