diff --git a/xcoder/xcoder-quadra/src/encoder.rs b/xcoder/xcoder-quadra/src/encoder.rs index a9fc1db..04c13c8 100644 --- a/xcoder/xcoder-quadra/src/encoder.rs +++ b/xcoder/xcoder-quadra/src/encoder.rs @@ -5,9 +5,7 @@ use av_traits::{EncodedFrameType, EncodedVideoFrame, RawVideoFrame, VideoEncoder use scopeguard::{guard, ScopeGuard}; use snafu::Snafu; use std::{ - collections::VecDeque, - mem::{self, MaybeUninit}, - os::raw::c_void, + array, collections::VecDeque, mem::{self, MaybeUninit}, os::raw::c_void, ptr::null_mut }; use xcoder_quadra_sys::{self as sys, ni_packet_t, ni_xcoder_params_t}; @@ -233,7 +231,7 @@ impl XcoderEncoder { sys::ni_get_frame_dim( config.width as _, config.height as _, - if config.bit_depth > 8 { 2 } else { 1 }, // bit depth factor + config.pixel_format.repr(), frame_data_strides.as_mut_ptr(), frame_data_heights.as_mut_ptr(), ); @@ -462,23 +460,22 @@ impl> XcoderEncoder { } let mut dst_data = [frame.p_data[0], frame.p_data[1], frame.p_data[2]]; - - let mut src_data = [ - f.samples(0).as_ptr() as *mut u8, - f.samples(1).as_ptr() as *mut u8, - f.samples(2).as_ptr() as *mut u8, - ]; - let mut src_strides = [self.config.width as i32, self.config.width as i32 / 2, self.config.width as i32 / 2]; - let mut src_heights = [self.config.height as i32, self.config.height as i32 / 2, self.config.height as i32 / 2]; - + let mut src_data: [*mut u8; 3] = array::from_fn(|i| if i < self.config.pixel_format.plane_count() { + f.samples(i).as_ptr() as *mut u8 + } else { + null_mut() + }); + let mut src_strides = self.config.pixel_format.strides(self.config.width as i32); + let mut src_heights = self.config.pixel_format.heights(self.config.height as i32); + let factor = if self.config.pixel_format.ten_bit() { 2 } else { 1 }; unsafe { - sys::ni_copy_hw_yuv420p( + sys::ni_copy_frame_data( dst_data.as_mut_ptr(), src_data.as_mut_ptr(), self.config.width as _, self.config.height as _, - 1, - 0, + factor, + self.config.pixel_format.repr(), 0, self.frame_data_strides.as_mut_ptr(), self.frame_data_heights.as_mut_ptr(), diff --git a/xcoder/xcoder-quadra/src/lib.rs b/xcoder/xcoder-quadra/src/lib.rs index 4a64c9b..c279664 100644 --- a/xcoder/xcoder-quadra/src/lib.rs +++ b/xcoder/xcoder-quadra/src/lib.rs @@ -126,6 +126,73 @@ mod linux_impl { Uyvy422 = sys::ni_pix_fmt_t_NI_PIX_FMT_UYVY422, None = sys::ni_pix_fmt_t_NI_PIX_FMT_NONE, } + + impl XcoderPixelFormat { + pub fn ten_bit(&self) -> bool { + use XcoderPixelFormat::*; + matches!(self, Yuv420Planar10BitLittleEndian | P010LittleEndian) + } + + /// Returns how many planes are in the layout. For semi-planar formats, a plane containing multiple + /// types of data is still considered to be one plane. + pub fn plane_count(&self) -> usize { + match self { + XcoderPixelFormat::Yuv420Planar | + XcoderPixelFormat::Yuv420Planar10BitLittleEndian => 3, + XcoderPixelFormat::Nv12 | + XcoderPixelFormat::Nv16 | + XcoderPixelFormat::P010LittleEndian => 2, + XcoderPixelFormat::Rgba | + XcoderPixelFormat::Bgra | + XcoderPixelFormat::Argb | + XcoderPixelFormat::Abgr | + XcoderPixelFormat::Bgr0 | + XcoderPixelFormat::Bgrp | + XcoderPixelFormat::Yuyv422 | + XcoderPixelFormat::Uyvy422 => 1, + XcoderPixelFormat::None => 0, + } + } + + pub fn strides(&self, width: i32) -> [i32; 3] { + match self { + XcoderPixelFormat::Yuv420Planar => [width, width / 2, width / 2], + XcoderPixelFormat::Yuv420Planar10BitLittleEndian => [width * 2, width, width], + XcoderPixelFormat::Nv12 => [width, width, 0], + XcoderPixelFormat::P010LittleEndian => [width * 2, width * 2, 0], + XcoderPixelFormat::Rgba | + XcoderPixelFormat::Bgra | + XcoderPixelFormat::Argb | + XcoderPixelFormat::Abgr | + XcoderPixelFormat::Bgr0 => [width * 4, 0, 0], + XcoderPixelFormat::Bgrp => [width * 3, 0, 0], + XcoderPixelFormat::Nv16 | + XcoderPixelFormat::Yuyv422 | + XcoderPixelFormat::Uyvy422 => [width, width / 2, 0], + XcoderPixelFormat::None => [0; 3], + } + } + + pub fn heights(&self, height: i32) -> [i32; 3] { + match self { + XcoderPixelFormat::Yuv420Planar | + XcoderPixelFormat::Yuv420Planar10BitLittleEndian => [height, height / 2, height / 2], + XcoderPixelFormat::Nv12 | + XcoderPixelFormat::P010LittleEndian => [height, height / 2, 0], + XcoderPixelFormat::Rgba | + XcoderPixelFormat::Bgra | + XcoderPixelFormat::Argb | + XcoderPixelFormat::Abgr | + XcoderPixelFormat::Bgr0 | + XcoderPixelFormat::Bgrp => [height, 0, 0], + XcoderPixelFormat::Nv16 | + XcoderPixelFormat::Yuyv422 | + XcoderPixelFormat::Uyvy422 => [height, height, 0], + XcoderPixelFormat::None => [0; 3], + } + } + + } } #[cfg(target_os = "linux")]