diff --git a/Cargo.lock b/Cargo.lock index 0bee8938..1bf6b56f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,12 @@ version = "3.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" + [[package]] name = "byteorder" version = "1.4.3" @@ -462,6 +468,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-repr" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad30c9c0fa1aaf1ae5010dab11f1117b15d35faf62cda4bbbc53b9987950f18" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "enumn" version = "0.1.13" @@ -2402,8 +2419,11 @@ name = "xcoder-quadra" version = "0.1.0" dependencies = [ "av-traits", + "bytemuck", + "enum-repr", "h264", "h265", + "libc", "rayon", "scopeguard", "snafu", diff --git a/mpegts-segmenter/src/analyzer.rs b/mpegts-segmenter/src/analyzer.rs index e2c9b81b..3be9d79e 100644 --- a/mpegts-segmenter/src/analyzer.rs +++ b/mpegts-segmenter/src/analyzer.rs @@ -2,10 +2,7 @@ use mpeg2::{pes, ts}; use mpeg4::AudioDataTransportStream; use vecmap::VecMap; -use std::{ - collections::VecDeque, - error::Error, -}; +use std::{collections::VecDeque, error::Error}; pub type Result = std::result::Result>; diff --git a/xcoder/xcoder-quadra/Cargo.toml b/xcoder/xcoder-quadra/Cargo.toml index d1a219e6..83f72ca5 100644 --- a/xcoder/xcoder-quadra/Cargo.toml +++ b/xcoder/xcoder-quadra/Cargo.toml @@ -7,8 +7,11 @@ edition = "2021" av-traits = { path = "../../av-traits" } snafu = "0.8.0" scopeguard = "1.1.0" +libc = "0.2" +enum-repr = "0.2.6" [dev-dependencies] +bytemuck = "1.16.1" h264 = { path = "../../h264" } h265 = { path = "../../h265" } snafu = { version = "0.8.0", features = ["std"] } diff --git a/xcoder/xcoder-quadra/src/decoder.rs b/xcoder/xcoder-quadra/src/decoder.rs index 4773d074..e3d9abd1 100644 --- a/xcoder/xcoder-quadra/src/decoder.rs +++ b/xcoder/xcoder-quadra/src/decoder.rs @@ -1,7 +1,12 @@ -use super::{fps_to_rational, XcoderHardware, XcoderHardwareFrame}; +use super::{alloc_zeroed, fps_to_rational, XcoderHardware, XcoderHardwareFrame}; use scopeguard::{guard, ScopeGuard}; use snafu::{Error, Snafu}; -use std::{marker::PhantomData, mem, ops::Deref}; +use std::{ + marker::PhantomData, + mem::{self, MaybeUninit}, + ops::Deref, + os::raw::c_void, +}; use xcoder_quadra_sys as sys; #[derive(Clone, Copy, Debug)] @@ -205,17 +210,17 @@ impl> XcoderDecoder { let (fps_numerator, fps_denominator) = fps_to_rational(config.fps); unsafe { - let mut params: sys::ni_xcoder_params_t = mem::zeroed(); - let code = sys::ni_decoder_init_default_params(&mut params as _, fps_numerator, fps_denominator, 0, config.width, config.height); + let mut params = alloc_zeroed(); + let code = sys::ni_decoder_init_default_params(params.as_mut_ptr(), fps_numerator, fps_denominator, 0, config.width, config.height); if code != sys::ni_retcode_t_NI_RETCODE_SUCCESS { return Err(XcoderDecoderError::Unknown { code, operation: "initializing parameters", }); } + let mut params = mem::transmute::>, Box>(params); params.__bindgen_anon_1.dec_input_params.hwframes = 1; params.__bindgen_anon_1.dec_input_params.mcmode = config.multicore_joint_mode.into(); - let params = Box::new(params); let session = sys::ni_device_session_context_alloc_init(); if session.is_null() { @@ -227,7 +232,7 @@ impl> XcoderDecoder { (**session).hw_id = config.hardware_id.unwrap_or(-1); (**session).hw_action = sys::ni_codec_hw_actions_NI_CODEC_HW_ENABLE as _; - (**session).p_session_config = &*params as *const sys::ni_xcoder_params_t as _; + (**session).p_session_config = params.as_mut() as *mut sys::ni_xcoder_params_t as *mut c_void; (**session).codec_format = match config.codec { XcoderDecoderCodec::H264 => sys::_ni_codec_format_NI_CODEC_FORMAT_H264, XcoderDecoderCodec::H265 => sys::_ni_codec_format_NI_CODEC_FORMAT_H265, @@ -476,6 +481,7 @@ mod test { level_idc: None, }, bit_depth: 8, + pixel_format: XcoderPixelFormat::Yuv420Planar, hardware: Some(decoder.hardware()), multicore_joint_mode: false, }) diff --git a/xcoder/xcoder-quadra/src/encoder.rs b/xcoder/xcoder-quadra/src/encoder.rs index 96d23dec..04c13c89 100644 --- a/xcoder/xcoder-quadra/src/encoder.rs +++ b/xcoder/xcoder-quadra/src/encoder.rs @@ -1,9 +1,13 @@ -use super::{fps_to_rational, XcoderHardware, XcoderHardwareFrame}; +use crate::XcoderPixelFormat; + +use super::{alloc_zeroed, fps_to_rational, XcoderHardware, XcoderHardwareFrame}; use av_traits::{EncodedFrameType, EncodedVideoFrame, RawVideoFrame, VideoEncoder, VideoEncoderOutput}; use scopeguard::{guard, ScopeGuard}; use snafu::Snafu; -use std::{collections::VecDeque, mem}; -use xcoder_quadra_sys as sys; +use std::{ + 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}; #[derive(Debug, Snafu)] pub enum XcoderEncoderError { @@ -18,20 +22,21 @@ type Result = std::result::Result; struct EncodedFrame { data_io: sys::ni_session_data_io_t, parameter_sets: Option>, + meta_size: usize, } impl EncodedFrame { - pub fn new() -> Result { + pub fn new(meta_size: usize) -> Result { let packet = unsafe { - let mut packet = mem::zeroed(); - let code = sys::ni_packet_buffer_alloc(&mut packet as _, sys::NI_MAX_TX_SZ as _); + let mut packet = MaybeUninit::::zeroed(); + let code = sys::ni_packet_buffer_alloc(packet.as_mut_ptr(), sys::NI_MAX_TX_SZ as _); if code != sys::ni_retcode_t_NI_RETCODE_SUCCESS { return Err(XcoderEncoderError::Unknown { code, operation: "allocating packet buffer", }); } - packet + packet.assume_init() }; Ok(Self { @@ -39,12 +44,13 @@ impl EncodedFrame { data: sys::_ni_session_data_io__bindgen_ty_1 { packet }, }, parameter_sets: None, + meta_size, }) } pub fn as_slice(&self) -> &[u8] { let data = unsafe { &std::slice::from_raw_parts(self.data_io.data.packet.p_data as _, self.data_io.data.packet.data_len as _) }; - &data[sys::NI_FW_ENC_BITSTREAM_META_DATA_SIZE as usize..] + &data[self.meta_size..] } /// When parameter sets are emitted by the encoder, they're provided here. @@ -84,6 +90,7 @@ pub struct XcoderEncoder { encoded_frame: EncodedFrame, frame_data_io: sys::ni_session_data_io_t, frame_data_io_has_next_frame: bool, + _params: Box, frame_data_strides: [i32; sys::NI_MAX_NUM_DATA_POINTERS as usize], frame_data_heights: [i32; sys::NI_MAX_NUM_DATA_POINTERS as usize], input_frames: VecDeque, @@ -127,6 +134,7 @@ pub struct XcoderEncoderConfig { pub fps: f64, pub bitrate: Option, pub codec: XcoderEncoderCodec, + pub pixel_format: XcoderPixelFormat, pub bit_depth: u8, pub multicore_joint_mode: bool, @@ -139,9 +147,9 @@ impl XcoderEncoder { let (fps_numerator, fps_denominator) = fps_to_rational(config.fps); unsafe { - let mut params: sys::ni_xcoder_params_t = mem::zeroed(); + let mut params = alloc_zeroed::(); let code = sys::ni_encoder_init_default_params( - &mut params as _, + params.as_mut_ptr(), fps_numerator, fps_denominator, // There's nothing special about this default bitrate. It's not used unless @@ -160,7 +168,7 @@ impl XcoderEncoder { operation: "initializing parameters", }); } - + let mut params = mem::transmute::>, Box>(params); let cfg_enc_params = &mut params.__bindgen_anon_1.cfg_enc_params; cfg_enc_params.planar = 1; cfg_enc_params.rc.enable_rate_control = if config.bitrate.is_some() { 1 } else { 0 }; @@ -220,11 +228,10 @@ impl XcoderEncoder { let mut frame_data_strides = [0; sys::NI_MAX_NUM_DATA_POINTERS as usize]; let mut frame_data_heights = [0; sys::NI_MAX_NUM_DATA_POINTERS as usize]; - sys::ni_get_hw_yuv420p_dim( + sys::ni_get_frame_dim( config.width as _, config.height as _, - if config.bit_depth > 8 { 2 } else { 1 }, // bit depth factor - 0, // is nv12 + config.pixel_format.repr(), frame_data_strides.as_mut_ptr(), frame_data_heights.as_mut_ptr(), ); @@ -232,7 +239,7 @@ impl XcoderEncoder { params.hwframes = 1; } - let params = Box::new(params); + let pixel_format = i32::try_from(config.pixel_format.repr()).expect("cast should never fail"); let session = sys::ni_device_session_context_alloc_init(); if session.is_null() { @@ -248,11 +255,12 @@ impl XcoderEncoder { (**session).sender_handle = hw.device_handle; (**session).hw_action = sys::ni_codec_hw_actions_NI_CODEC_HW_ENABLE as _; } - (**session).p_session_config = &*params as *const sys::ni_xcoder_params_t as _; + (**session).p_session_config = params.as_mut() as *mut sys::ni_xcoder_params_t as *mut c_void; (**session).codec_format = match config.codec { XcoderEncoderCodec::H264 { .. } => sys::_ni_codec_format_NI_CODEC_FORMAT_H264, XcoderEncoderCodec::H265 { .. } => sys::_ni_codec_format_NI_CODEC_FORMAT_H265, }; + (**session).pixel_format = pixel_format; (**session).src_bit_depth = config.bit_depth as _; (**session).src_endian = sys::NI_FRAME_LITTLE_ENDIAN as _; (**session).bit_depth_factor = if config.bit_depth > 8 { 2 } else { 1 }; @@ -272,14 +280,14 @@ impl XcoderEncoder { let frame_data_io = { let mut frame: sys::ni_frame_t = mem::zeroed(); - let code = sys::ni_encoder_frame_buffer_alloc( + let code = sys::ni_frame_buffer_alloc_pixfmt( &mut frame as _, + pixel_format, config.width as _, - frame_data_heights[0], + config.height as _, frame_data_strides.as_mut_ptr(), if matches!(config.codec, XcoderEncoderCodec::H264 { .. }) { 1 } else { 0 }, sys::NI_APP_ENC_FRAME_META_DATA_SIZE as _, - false, ); if code != sys::ni_retcode_t_NI_RETCODE_SUCCESS { return Err(XcoderEncoderError::Unknown { @@ -295,7 +303,7 @@ impl XcoderEncoder { sys::ni_frame_buffer_free(&mut frame_data_io.data.frame as _); }); - let encoded_frame = EncodedFrame::new()?; + let encoded_frame = EncodedFrame::new((**session).meta_size as usize)?; Ok(Self { config, @@ -309,6 +317,7 @@ impl XcoderEncoder { frame_data_strides, frame_data_heights, frames_copied: 0, + _params: params, input_frames: VecDeque::new(), output_frames: VecDeque::new(), hardware_frames: { @@ -451,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(), @@ -524,6 +532,8 @@ impl> VideoEncoder for XcoderEncoder { #[cfg(test)] mod test { + use crate::XcoderPixelFormat; + use super::*; struct TestFrame { @@ -548,6 +558,7 @@ mod test { level_idc: Some(41), }, bit_depth: 8, + pixel_format: XcoderPixelFormat::Yuv420Planar, hardware: None, multicore_joint_mode: false, }) @@ -589,4 +600,57 @@ mod test { //use std::io::Write; //std::fs::File::create("tmp.h264").unwrap().write_all(&encoded).unwrap(); } + + #[test] + fn test_video_encoder_bgra() { + let mut encoder = XcoderEncoder::new(XcoderEncoderConfig { + width: 1920, + height: 1080, + fps: 29.97, + bitrate: None, + codec: XcoderEncoderCodec::H264 { + profile: Some(XcoderH264Profile::Main), + level_idc: Some(41), + }, + bit_depth: 8, + pixel_format: XcoderPixelFormat::Bgra, + hardware: None, + multicore_joint_mode: false, + }) + .unwrap(); + + let mut encoded = vec![]; + let mut encoded_frames = 0; + + for i in 0..90 { + let mut bgra = Vec::<[u8; 4]>::with_capacity(1920 * 1080); + for line in 0..1080 { + let sample = if line / 12 == i { + // add some motion by drawing a line that moves from top to bottom + 0 + } else { + ((line as f64 / 1080.0) * 255.0).round() as u8 + }; + bgra.resize(bgra.len() + 1920, [sample, sample, sample, 255]); + } + let frame = TestFrame { + samples: vec![bytemuck::cast_slice(&bgra).to_vec()], + }; + if let Some(output) = encoder.encode(frame, EncodedFrameType::Auto).unwrap() { + encoded.append(&mut output.encoded_frame.expect("frame was not dropped").data); + encoded_frames += 1; + } + } + while let Some(output) = encoder.flush().unwrap() { + encoded.append(&mut output.encoded_frame.expect("frame was not dropped").data); + encoded_frames += 1; + } + + assert_eq!(encoded_frames, 90); + assert!(encoded.len() > 5000); + + // To inspect the output, uncomment these lines: + //use std::io::Write; + //std::fs::File::create("tmp.h264").unwrap().write_all(&encoded).unwrap(); + } } diff --git a/xcoder/xcoder-quadra/src/lib.rs b/xcoder/xcoder-quadra/src/lib.rs index 09a58054..c2796645 100644 --- a/xcoder/xcoder-quadra/src/lib.rs +++ b/xcoder/xcoder-quadra/src/lib.rs @@ -2,7 +2,7 @@ #[path = ""] mod linux_impl { use snafu::Snafu; - use std::ops::Deref; + use std::{ffi::c_uint, ops::Deref}; use xcoder_quadra_sys as sys; pub mod cropper; @@ -90,6 +90,109 @@ mod linux_impl { let num = (fps * den as f64).round() as _; (num, den) } + + fn alloc_zeroed() -> Box> { + use std::alloc::GlobalAlloc as _; + unsafe { + let raw = std::alloc::System.alloc_zeroed(std::alloc::Layout::from_size_align_unchecked( + std::mem::size_of::(), + std::mem::align_of::(), + )); + Box::from_raw(raw as *mut std::mem::MaybeUninit) + } + } + + #[enum_repr::EnumRepr(type = "c_uint")] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub enum XcoderPixelFormat { + Yuv420Planar = sys::ni_pix_fmt_t_NI_PIX_FMT_YUV420P, + Yuv420Planar10BitLittleEndian = sys::ni_pix_fmt_t_NI_PIX_FMT_YUV420P10LE, + Nv12 = sys::ni_pix_fmt_t_NI_PIX_FMT_NV12, + P010LittleEndian = sys::ni_pix_fmt_t_NI_PIX_FMT_P010LE, + /// 32 bit packed + Rgba = sys::ni_pix_fmt_t_NI_PIX_FMT_RGBA, + /// 32 bit packed + Bgra = sys::ni_pix_fmt_t_NI_PIX_FMT_BGRA, + /// 32 bit packed + Argb = sys::ni_pix_fmt_t_NI_PIX_FMT_ARGB, + /// 32 bit packed + Abgr = sys::ni_pix_fmt_t_NI_PIX_FMT_ABGR, + /// 32 bit packed + Bgr0 = sys::ni_pix_fmt_t_NI_PIX_FMT_BGR0, + /// 24 bit packed + Bgrp = sys::ni_pix_fmt_t_NI_PIX_FMT_BGRP, + Nv16 = sys::ni_pix_fmt_t_NI_PIX_FMT_NV16, + Yuyv422 = sys::ni_pix_fmt_t_NI_PIX_FMT_YUYV422, + 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")] @@ -146,6 +249,7 @@ mod test { level_idc: None, }, bit_depth: 8, + pixel_format: XcoderPixelFormat::Yuv420Planar, hardware: Some(decoder.hardware()), multicore_joint_mode: false, }) @@ -234,6 +338,7 @@ mod test { level_idc: None, }, bit_depth: 8, + pixel_format: XcoderPixelFormat::Yuv420Planar, hardware: Some(decoder.hardware()), multicore_joint_mode: true, }) diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/build.rs b/xcoder/xcoder-quadra/xcoder-quadra-sys/build.rs index 863f65d2..ab10aae3 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/build.rs +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/build.rs @@ -24,6 +24,9 @@ fn main() { .env("XCODER_WIN_NVME_CUSTOM", "NO") .env("XCODER_SELF_KILL_ERR", "NO") .env("XCODER_LATENCY_DISPLAY", "NO") + .env("XCODER_SSIM_INFO_LEVEL_LOGGING", "NO") + .env("XCODER_LINUX_VIRT_IO_DRIVER", "NO") + .env("XCODER_DISABLE_BACKTRACE_PRINT", "NO") .args(["vendor/libxcoder/auto/auto_headers.sh"]) .status() .unwrap(); @@ -42,7 +45,6 @@ fn main() { .files(c_source_files.iter().map(|name| source_path.join(name))) .warnings(false) .flag("-fPIC") - .flag("-Werror") .flag("-Wno-unused-command-line-argument") .flag("-std=gnu99") .flag("-DLIBXCODER_OBJS_BUILD") @@ -65,7 +67,6 @@ fn main() { .files(cpp_source_files.iter().map(|name| source_path.join(name))) .warnings(false) .flag("-fPIC") - .flag("-Werror") .flag("-Wno-unused-command-line-argument") .flag("-DLIBXCODER_OBJS_BUILD") .compile("xcoder-cpp-sys"); @@ -77,9 +78,6 @@ fn main() { .allowlist_type("ni_.+") .allowlist_var("NI_.+") .allowlist_var("GC620_.+") - // bindgen 0.60.0 broke layout tests: https://github.com/rust-lang/rust-bindgen/issues/2218 - // 0.60.1 claims to have fixed the issue, but does not. - .layout_tests(false) .clang_arg(format!("-I{}", source_path.to_str().unwrap())) .generate() .expect("unable to generate bindings"); diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/Makefile b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/Makefile new file mode 100755 index 00000000..9edd508c --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/Makefile @@ -0,0 +1,166 @@ +.PHONY: all default test clean cleanall install uninstall +WINDOWS ?= FALSE +GDB ?= FALSE +WARN_AS_ERROR ?= FALSE +SECURE_COMPILE ?= FALSE +RPM_DEBUG ?= FALSE +DONT_WRITE_SONAME ?= FALSE + +INSTALL = install + +ifeq ($(SECURE_COMPILE), TRUE) + GLOBALFLAGS = -Wall -Wl,-z,now -Wl,-z,relro -Wl,-z,noexecstack -fstack-protector-strong +endif + +ifeq ($(RPM_DEBUG), TRUE) + OPTFLAG = -g -O3 +else + ifeq ($(GDB), TRUE) + OPTFLAG = -g + else + OPTFLAG = -O3 + endif +endif + +UNAME = $(shell uname) +ifeq ($(UNAME), Darwin) + WERROR_FLAGS = -Werror -Wno-unused-command-line-argument +else + ifeq ($(WARN_AS_ERROR), TRUE) + WERROR_FLAGS = -Werror -DNI_WARN_AS_ERROR + else + WERROR_FLAGS = -UNI_WARN_AS_ERROR + endif +endif + +CFLAGS = -fPIC ${WERROR_FLAGS} -DLIBXCODER_OBJS_BUILD -std=gnu99 +CXXFLAGS = -fPIC ${WERROR_FLAGS} -DLIBXCODER_OBJS_BUILD -std=c++11 +TARGETNAME = xcoder +TARGETP2P = xcoderp2p +TARGET = ${TARGETNAME} +TARGET_LIB = lib${TARGETNAME}.a +TARGET_LIB_SHARED = lib${TARGETNAME}.so +TARGET_VERSION = $(shell grep 'Version: '.* < build/xcoder.pc | cut -d ' ' -f 2) +ifeq ($(WINDOWS), FALSE) + TARGET_INCS = ni_device_api.h ni_rsrc_api.h ni_defs.h ni_av_codec.h ni_bitstream.h ni_util.h ni_log.h ni_release_info.h ni_libxcoder_dynamic_loading.h ni_p2p_ioctl.h +else + TARGET_INCS = ni_device_api.h ni_rsrc_api.h ni_defs.h ni_av_codec.h ni_bitstream.h ni_util.h ni_log.h ni_release_info.h +endif +TARGET_PC = xcoder.pc +OBJECTS = ni_nvme.o ni_device_api_priv.o ni_device_api.o ni_util.o ni_lat_meas.o ni_log.o ni_rsrc_priv.o ni_rsrc_api.o ni_av_codec.o ni_bitstream.o +LINK_OBJECTS = ${OBJS_PATH}/ni_nvme.o ${OBJS_PATH}/ni_device_api_priv.o ${OBJS_PATH}/ni_device_api.o ${OBJS_PATH}/ni_util.o ${OBJS_PATH}/ni_lat_meas.o ${OBJS_PATH}/ni_log.o ${OBJS_PATH}/ni_rsrc_priv.o ${OBJS_PATH}/ni_rsrc_api.o ${OBJS_PATH}/ni_av_codec.o ${OBJS_PATH}/ni_bitstream.o +ifeq ($(WINDOWS), FALSE) + ALL_OBJECTS = ni_device_test.o init_rsrc.o test_rsrc_api.o ni_rsrc_mon.o ni_rsrc_update.o ni_rsrc_list.o ni_rsrc_namespace.o ni_p2p_test.o ni_libxcoder_dynamic_loading_test.o ${OBJECTS} +else + ALL_OBJECTS = ni_device_test.o init_rsrc.o test_rsrc_api.o ni_rsrc_mon.o ni_rsrc_update.o ni_rsrc_list.o ni_rsrc_namespace.o ${OBJECTS} +endif +SRC_PATH = ./source +OBJS_PATH = ./build + +# Read the installation directory from path set in build/xcoder.pc +# DESTDIR ?= $(shell sed -n 's/^prefix=\(.*\)/\1/p' $(OBJS_PATH)/$(TARGET_PC)) +LIBDIR_NO_PREFIX = $(shell sed -n 's/^libdir=\(.*\)/\1/p' $(OBJS_PATH)/$(TARGET_PC)) +BINDIR_NO_PREFIX = $(shell sed -n 's/^bindir=\(.*\)/\1/p' $(OBJS_PATH)/$(TARGET_PC)) +INCLUDEDIR_NO_PREFIX = $(shell sed -n 's/^includedir=\(.*\)/\1/p' $(OBJS_PATH)/$(TARGET_PC)) +SHAREDDIR_NO_PREFIX = $(shell sed -n 's/^shareddir=\(.*\)/\1/p' $(OBJS_PATH)/$(TARGET_PC)) +ifeq ($(WINDOWS), FALSE) + ifeq ($(UNAME), Darwin) + INCLUDES= -pthread -lm + else + INCLUDES= -pthread -lrt -lm -ldl + endif +else + INCLUDES= -lws2_32 -Wl,--stack,4194304 +endif + +LIBDIR = ${LIBDIR_NO_PREFIX} +BINDIR = ${BINDIR_NO_PREFIX} +INCLUDEDIR = ${INCLUDEDIR_NO_PREFIX} +SHAREDDIR = ${SHAREDDIR_NO_PREFIX} + +ifdef DESTDIR + LIBDIR = ${DESTDIR}${LIBDIR_NO_PREFIX} + BINDIR = ${DESTDIR}${BINDIR_NO_PREFIX} + INCLUDEDIR = ${DESTDIR}${INCLUDEDIR_NO_PREFIX} + ifneq (${SHAREDDIR_NO_PREFIX},) + SHAREDDIR = ${DESTDIR}${SHAREDDIR_NO_PREFIX} + endif +endif + +# make target + +all:${ALL_OBJECTS} + ar rcs $(OBJS_PATH)/${TARGET_LIB} ${LINK_OBJECTS} +ifeq ($(UNAME), Darwin) + ${CC} -shared -o $(OBJS_PATH)/${TARGET_LIB_SHARED}.${TARGET_VERSION} $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} +else ifeq ($(DONT_WRITE_SONAME), TRUE) + ${CC} -shared -o $(OBJS_PATH)/${TARGET_LIB_SHARED}.${TARGET_VERSION} $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} +else + ${CC} -shared -Wl,-soname,${TARGET_LIB_SHARED}.${TARGET_VERSION} -o $(OBJS_PATH)/${TARGET_LIB_SHARED}.${TARGET_VERSION} $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} +endif + + ${CC} -o $(OBJS_PATH)/${TARGET} $(OBJS_PATH)/ni_device_test.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} +ifeq ($(WINDOWS), FALSE) + ${CC} -o $(OBJS_PATH)/ni_libxcoder_dynamic_loading_test $(OBJS_PATH)/ni_libxcoder_dynamic_loading_test.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + ${CC} -o $(OBJS_PATH)/${TARGETP2P} $(OBJS_PATH)/ni_p2p_test.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} +endif + ${CC} -o $(OBJS_PATH)/test_rsrc_api $(OBJS_PATH)/test_rsrc_api.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + ${CC} -o $(OBJS_PATH)/ni_rsrc_namespace $(OBJS_PATH)/ni_rsrc_namespace.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + ${CC} -o $(OBJS_PATH)/ni_rsrc_mon $(OBJS_PATH)/ni_rsrc_mon.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + ${CC} -o $(OBJS_PATH)/ni_rsrc_update $(OBJS_PATH)/ni_rsrc_update.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + ${CC} -o $(OBJS_PATH)/ni_rsrc_list $(OBJS_PATH)/ni_rsrc_list.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + ${CC} -o $(OBJS_PATH)/init_rsrc $(OBJS_PATH)/init_rsrc.o $(LINK_OBJECTS) ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + @echo info ${TARGET_LIB_SHARED} + +test:${ALL_OBJECTS} + ${CC} -o $(OBJS_PATH)/${TARGET} $(OBJS_PATH)/*.o ${INCLUDES} ${OPTFLAG} ${GLOBALFLAGS} + +install: + mkdir -p ${INCLUDEDIR}/ + mkdir -p ${LIBDIR}/ + mkdir -p ${LIBDIR}/pkgconfig/ + mkdir -p ${BINDIR}/ + for TARGET_INC in ${TARGET_INCS}; do \ + ${INSTALL} -m 644 ${SRC_PATH}/$${TARGET_INC} ${INCLUDEDIR}/.; \ + done +ifeq ($(RPM_DEBUG), TRUE) + ${INSTALL} -m 644 -s ${OBJS_PATH}/${TARGET_LIB} ${LIBDIR}/. + ${INSTALL} -m 644 -s ${OBJS_PATH}/${TARGET_LIB_SHARED}.${TARGET_VERSION} ${LIBDIR}/. +else + ${INSTALL} -m 644 ${OBJS_PATH}/${TARGET_LIB} ${LIBDIR}/. + ${INSTALL} -m 644 ${OBJS_PATH}/${TARGET_LIB_SHARED}.${TARGET_VERSION} ${LIBDIR}/. +endif + (cd ${LIBDIR}; ln -f -s ${TARGET_LIB_SHARED}.${TARGET_VERSION} ${TARGET_LIB_SHARED}; cd -) +ifneq ($(SHAREDDIR),) + mkdir -p ${SHAREDDIR}/ + ${INSTALL} -m 644 ${OBJS_PATH}/${TARGET_LIB_SHARED}.${TARGET_VERSION} ${SHAREDDIR}/. + (cd ${SHAREDDIR}; ln -f -s ${TARGET_LIB_SHARED}.${TARGET_VERSION} ${TARGET_LIB_SHARED}; cd -) +endif + ${INSTALL} -m 644 ${OBJS_PATH}/${TARGET_PC} ${LIBDIR}/pkgconfig/. + ${INSTALL} -m 755 ${OBJS_PATH}/ni_rsrc_mon ${BINDIR}/. + ${INSTALL} -m 755 ${OBJS_PATH}/ni_rsrc_namespace ${BINDIR}/. + ${INSTALL} -m 755 ${OBJS_PATH}/ni_rsrc_update ${BINDIR}/. + ${INSTALL} -m 755 ${OBJS_PATH}/ni_rsrc_list ${BINDIR}/. + ${INSTALL} -m 755 ${OBJS_PATH}/init_rsrc ${BINDIR}/. + +uninstall: + for TARGET_INC in ${TARGET_INCS}; do \ + rm -f ${INCLUDEDIR}/$${TARGET_INC}; \ + done + rm -f ${LIBDIR}/${TARGET_LIB} ${LIBDIR}/${TARGET_LIB_SHARED} ${LIBDIR}/${TARGET_LIB_SHARED}.${TARGET_VERSION} ${LIBDIR}/pkgconfig/${TARGET_PC} ${BINDIR}/ni_rsrc_mon ${BINDIR}/ni_rsrc_update ${BINDIR}/ni_rsrc_list ${BINDIR}/init_rsrc ${BINDIR}/ni_rsrc_namespace +ifneq ($(SHAREDDIR),) + rm -f ${SHAREDDIR}/${TARGET_LIB_SHARED}.${TARGET_VERSION} ${SHAREDDIR}/${TARGET_LIB_SHARED} +endif + +cleanall:clean + rm -rf ${TARGET} $(OBJS_PATH)/*${TARGET}* $(OBJS_PATH)/*.o + +clean: + rm -rf ${TARGET} $(OBJS_PATH)/*${TARGET}* $(OBJS_PATH)/*.o + +# dependence +%.o : ${SRC_PATH}/%.cpp + ${CC} ${CXXFLAGS} ${OPTFLAG} ${GLOBALFLAGS} -c $< -o ${OBJS_PATH}/$@ + +%.o : ${SRC_PATH}/%.c + ${CC} ${CFLAGS} ${OPTFLAG} ${GLOBALFLAGS} -c $< -o ${OBJS_PATH}/$@ diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/auto_headers.sh b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/auto_headers.sh index cd144c63..5ec90ec5 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/auto_headers.sh +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/auto_headers.sh @@ -39,10 +39,10 @@ else echo "#undef NI_LOG_TRACE_TIMESTAMPS" >> $XCODER_AUTO_HEADERS_H fi -if [ $XCODER_WIN_NVME_CUSTOM = YES ]; then - echo "#define WIN_NVME_CUSTOM" >> $XCODER_AUTO_HEADERS_H +if [ $XCODER_SSIM_INFO_LEVEL_LOGGING = YES ]; then + echo "#define NI_LOG_SSIM_AT_INFO" >> $XCODER_AUTO_HEADERS_H else - echo "#undef WIN_NVME_CUSTOM" >> $XCODER_AUTO_HEADERS_H + echo "#undef NI_LOG_SSIM_AT_INFO" >> $XCODER_AUTO_HEADERS_H fi if [ $XCODER_SELF_KILL_ERR = YES ]; then @@ -57,6 +57,18 @@ else echo "#undef MEASURE_LATENCY" >> $XCODER_AUTO_HEADERS_H fi +if [ $XCODER_LINUX_VIRT_IO_DRIVER = YES ]; then + echo "#define XCODER_LINUX_VIRTIO_DRIVER_ENABLED" >> $XCODER_AUTO_HEADERS_H +else + echo "#undef XCODER_LINUX_VIRTIO_DRIVER_ENABLED" >> $XCODER_AUTO_HEADERS_H +fi + +if [ $XCODER_DISABLE_BACKTRACE_PRINT = YES ]; then + echo "#define DISABLE_BACKTRACE_PRINT" >> $XCODER_AUTO_HEADERS_H +else + echo "#undef DISABLE_BACKTRACE_PRINT" >> $XCODER_AUTO_HEADERS_H +fi + echo "" >> $XCODER_AUTO_HEADERS_H diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/check_libxcoder_dynamic_loading_header.py b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/check_libxcoder_dynamic_loading_header.py new file mode 100755 index 00000000..5f52a590 --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/check_libxcoder_dynamic_loading_header.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 + +import os +import sys +import re + +default_dl_header = '../source/ni_libxcoder_dynamic_loading.h' +# libxcoder header files to check for in. These must be in same folder with +# ni_libxcoder_dynamic_loading.h +header_files = ['ni_av_codec.h', 'ni_util.h', 'ni_device_api.h'] + +# STEVENTODO: these capitalization replacements aren't used but somehow tests still pass. Investigate +function_name_to_api_function_name_keyword_replacements = {'420p': '420P', + '444p': '444P', + 'P2p': 'P2P'} + +func_proto_dict = {"return_type" : "", + "function_name" : "", + "input_args_list": []} # list elements are strings of arg type&name + # (eg. "int width") + +# ex. "ni_copy_yuv_444p_to_420p" to "PNICOPYYUV444PTO420P" +def function_name_to_api_function_pointer_name(s): + return 'P' + s.replace('_', '').upper() + +# ex. "ni_copy_yuv_444p_to_420p" to "niCopyYuv444PTo420P" +def function_name_to_api_function_name(s): + assert s.startswith('ni_'), \ + "Found '{}' labeled with 'LIB_API' but missing 'ni_' prefix".format(s) + result = '' + p = '' + for c in s: + if c != '_': + result += c.upper() if p == '_' else c + p = c + for key, value in function_name_to_api_function_name_keyword_replacements.items(): + result = result.replace(key, value) + return result + + +# read a header file, return list of func_proto_dict +def extract_function_prototypes(header_file): + def rstrip_comments(s): + re.sub(r"//.*$", "", s) + re.sub(r"/\*.*\*\/$","", s) + s.rstrip() + return s + + def func_proto_string_to_dict(fp_str): + fp_dict = func_proto_dict.copy() + + # get return_type and function_name + args_idx = fp_str.find('(') + if args_idx == -1: + raise RuntimeError("(FAILURE) Could not find first '(' for function prototype: {}"\ + .format(fp_str)) + match_obj = re.search(r"LIB_API((\s+[^ *&]+)+)([ *&]+)([^ *&]+) *$", fp_str[:args_idx]) + if not match_obj: + raise RuntimeError("(FAILURE) Could not determine return_type and function_name " + "for function prototype: {}".format(fp_str)) + fp_dict["return_type"] = match_obj.group(1).strip() if not match_obj.group(3).strip() else \ + match_obj.group(1).strip() + " " + match_obj.group(3).strip() + rt_match_obj = re.search(r"(\s*)NI_DEPRECATED(\s*)", fp_dict["return_type"]) + if rt_match_obj and (rt_match_obj.group(1) or rt_match_obj.group(2)): + fp_dict["return_type"] = re.sub(r"\s*NI_DEPRECATED\s*", " ", fp_dict["return_type"]) + fp_dict["return_type"] = fp_dict["return_type"].strip() + fp_dict["function_name"] = match_obj.group(4).strip() + + # get input args + args_list = fp_str[args_idx+1:-2].split(',') # assume fp_str ends with ');' + args_list = [x.strip() for x in args_list] + if len(args_list) == 1 and not args_list[0]: + # there are no input args for this function + # note: "func_name(void)" is special in C and will thus be put in "input_args_list" + # https://stackoverflow.com/a/5929736 + fp_dict["input_args_list"] = [] + else: + fp_dict["input_args_list"] = args_list + # Unused code to separate args into datatype and name + # for arg_str in args_list: + # match_obj = re.search(r"([^ *&]+)([ *&]+)([^ *&]+)$", arg_str.strip()) + # if not match_obj: + # raise RuntimeError("(FAILURE) Could not determine datatype and name for " + # "input arg '{}' in function prototype: {}"\ + # .format(arg_str, fp_str)) + # datatype = match_obj.group(1) + match_obj.group(2).strip() + # arg_name = match_obj.group(3) + # fp_dict["input_args_list"].append((datatype, arg_name)) + return fp_dict + + # parse function text + fp_dict_list = [] + with open(header_file) as h: + lines = h.readlines() + index = 0 + while index < len(lines): + line = rstrip_comments(lines[index].strip()) + if re.search(r"^LIB_API\s", line): + s = line + while not line.endswith(');'): + index += 1 + line = rstrip_comments(lines[index].strip()) + s = s + " " + line + fp_dict_list.append(func_proto_string_to_dict(s)) + index += 1 + return fp_dict_list + +# generate function pointer line +# ex. "typedef void (LIB_API* PNICOPYYUV444PTO420P) (uint8_t *p_dst0[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int width, int height, int factor, int mode);" +def gen_func_typedef_line(fp_dict): + return "typedef " + fp_dict["return_type"] + " (LIB_API* " + \ + function_name_to_api_function_pointer_name(fp_dict["function_name"]) + ") (" + \ + ", ".join(fp_dict["input_args_list"]) + ");\n" + +# generate function list line (NOTE: actual line will have spacing to simulate columns between +# datatype, name, and comments) +# ex. "PNICOPYYUV444PTO420P niCopyYuv444PTo420P; /** Client should access ::ni_copy_yuv_444p_to_420p API through this pointer */" +def gen_func_struct_member_line(fp_dict): + col1 = " " + function_name_to_api_function_pointer_name(fp_dict["function_name"]) + col1 = "{0: <41}".format(col1) + col2 = function_name_to_api_function_name(fp_dict["function_name"]) + ";" + col2 = "{0: <38}".format(col2) + col3 = "/** Client should access ::" + fp_dict["function_name"] + " API through this pointer */\n" + return col1 + col2 + col3 + +# generate APICreateInstance class line +# ex. "functionList->niCopyYuv444PTo420P = reinterpret_cast(dlsym(lib,"ni_copy_yuv_444p_to_420p"));" +def gen_func_struct_init_line(fp_dict): + return " functionList->" + function_name_to_api_function_name(\ + fp_dict["function_name"]) + " = reinterpret_cast(dlsym(lib,"' + fp_dict["function_name"] + '"));\n' + +def main(dl_header=default_dl_header): + rc = 0 + fp_dict_list = [] + api_header_paths = [os.path.dirname(dl_header) + "/" + x for x in header_files] + + print("Checking dynamic loading header file: " + dl_header) + print("Checking function prototypes from headers: " + " ".join(api_header_paths)) + + # check all files to be read exist + for filepath in [dl_header] + api_header_paths: + if not os.path.isfile(filepath): + print("(FAILURE) file does not exist: " + filepath) + return 1 + + for header_file in header_files: + fp_dict_list.extend(extract_function_prototypes('{}/{}'\ + .format(os.path.dirname(dl_header), header_file))) + + # Check for duplicate function names + func_names_list = [x["function_name"] for x in fp_dict_list] + seen_set = set() + dup_func_names = [x for x in func_names_list if x in seen_set or seen_set.add(x)] + if dup_func_names: + rc = 1 + print('(FAILURE) duplicated function names in libxcoder API: ' + ', '.join(dup_func_names)) + del func_names_list, seen_set, dup_func_names + if rc: return rc + + # Check all functions present in dynamic loading header + with open(dl_header) as h: + dl_header_lines = h.readlines() + for fp_dict in fp_dict_list: + try: + dl_header_lines.remove(gen_func_typedef_line(fp_dict)) + except ValueError: + print("(ERROR) could not find: " + gen_func_typedef_line(fp_dict)) + rc |= 1 + for fp_dict in fp_dict_list: + try: + dl_header_lines.remove(gen_func_struct_member_line(fp_dict)) + except ValueError: + print("(ERROR) could not find: " + gen_func_struct_member_line(fp_dict)) + rc |= 1 + for fp_dict in fp_dict_list: + try: + dl_header_lines.remove(gen_func_struct_init_line(fp_dict)) + except ValueError: + print("(ERROR) could not find: " + gen_func_struct_init_line(fp_dict)) + rc |= 1 + if rc: return rc + + # Check there are no duplicate or errant references to functions in dynamic loading header + for line in dl_header_lines: + if any(x in line for x in ["typedef", "Client should", "functionList->"]): + if "typedef struct _NETINT_LIBXCODER_API_FUNCTION_LIST" in line: + continue + print("(ERROR) unexpected line in " + dl_header + ": " + line) + print("Perhaps there is a duplicate function in dynamic loading header file; " + "or, the function is not labeled with 'LIB_API' in header file") + rc |= 1 + + if not rc: print('(SUCCESS)') + return rc + + +if __name__ == '__main__': + if len(sys.argv) > 1: + rc = main(sys.argv[1]) + else: + rc = main() + exit(rc) \ No newline at end of file diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/options.sh b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/options.sh index bbeac199..b91f560d 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/options.sh +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/auto/options.sh @@ -1,31 +1,22 @@ #!/usr/bin/env bash - -# variables, parent script must set it: - -##################################################################################### -##################################################################################### -# parse user options, do this at first -##################################################################################### -##################################################################################### - -##################################################################################### -# output variables -##################################################################################### -help=no +# Parse options for ../configure ################################################################ # feature options XCODER_WIN32=NO -XCODER_WIN_NVME_CUSTOM=NO +XCODER_ANDROID=NO XCODER_SELF_KILL_ERR=NO XCODER_LATENCY_DISPLAY=NO XCODER_TRACELOG_TIMESTAMPS=NO +XCODER_LINUX_VIRT_IO_DRIVER=NO +XCODER_DUMP_DATA=NO +XCODER_PREFIX='/usr/local' XCODER_LIBDIR=NO XCODER_BINDIR=NO XCODER_INCLUDEDIR=NO XCODER_SHAREDDIR=NO -XCODER_PREFIX='/usr/local' -XCODER_DUMP_DATA=NO +XCODER_DISABLE_BACKTRACE_PRINT=NO +XCODER_SSIM_INFO_LEVEL_LOGGING=NO ##################################################################################### # menu @@ -36,37 +27,43 @@ function show_help() { Options: -h, --help print this message - --with-sim enable simulation mode - --without-sim disable simulation mode (default) + --with-win32 configure for win32 compile + --without-win32 do not configure for win32 compile (default) - --with-dump enable video data dump - --without-dump disable video data dump (default) + --with-android configure for android compile + --without-android do not configure for android compile (default) - --with-wait enable wait polling (default) - --without-wait disable wait polling + --with-self-kill enable self-killing process during error feature + --without-self-kill disable self-killing process during error feature (default) - --with-old-nvme-driver enable old nvme driver support - --without-old-nvme-driver disable old nvme driver support (default) + --with-latency-display enable latency-display feature + --without-latency-display disable latency-display feature (default) --with-tracelog-timestamps enable tracelog-timestamps feature --without-tracelog-timestamps disable tracelog-timestamps feature (default) - --with-self-kill enable self-killing process during error feature - --without-self-kill disable self-killing process during error feature (default) + --with-info-level-ssim-log enable info-level-ssim-log feature + --without-info-level-ssim-log disable info-level-ssim-log feature (default) - --with-latency-display enable latency-display feature - --without-latency-display disable latency-display feature (default) + --with-linux-virt-io-driver with linux virt-io driver + --without-linux-virt-io-driver without linux virt-io driver (default) + + --with-data-dump enable debug dump of video data exchanged on NVMe + --without-data-dump disable debug dump of video data exchanged on NVMe (default) + + --with-backtrace-print enable print backtrace (default) + --without-backtrace-print disable print backtrace - --prefix Set custom install location preix - (default: /usr/local/) - --libdir Set custom install location for libxcoder.so and pkgconfig files - (default: /usr/local/lib/) - --bindir Set custom install location for binary utilities (ni_rsrc_mon, etc.) - (default: /usr/local/bin/) - --includedir Set custom install location for libxcoder headers - (default: /usr/local/include/) - --shareddir Set additional install location for libxcoder.so - (ex. /usr/lib/x86_64-linux-gnu/ or /usr/lib64/) (default: NONE) + --prefix Set custom install location preix + (default: /usr/local/) + --libdir Set custom install location for libxcoder.so and pkgconfig files + (default: /usr/local/lib/) + --bindir Set custom install location for binary utilities (ni_rsrc_mon, etc.) + (default: /usr/local/bin/) + --includedir Set custom install location for libxcoder headers + (default: /usr/local/include/) + --shareddir Set additional install location for libxcoder.so + (ex. /usr/lib/x86_64-linux-gnu/ or /usr/lib64/) (default: NONE) END } @@ -104,16 +101,21 @@ function parse_user_option() { -h | --help) show_help; exit 0;; --with-win32) XCODER_WIN32=YES;; --without-win32) XCODER_WIN32=NO;; - --with-custom-nvme) XCODER_WIN_NVME_CUSTOM=YES;; - --without-custom-nvme) XCODER_WIN_NVME_CUSTOM=NO;; + --with-android) XCODER_ANDROID=YES;; + --without-android) XCODER_ANDROID=NO;; --with-self-kill) XCODER_SELF_KILL_ERR=YES;; --without-self-kill) XCODER_SELF_KILL_ERR=NO;; --with-latency-display) XCODER_LATENCY_DISPLAY=YES;; --without-latency-display) XCODER_LATENCY_DISPLAY=NO;; --with-tracelog-timestamps) XCODER_TRACELOG_TIMESTAMPS=YES;; --without-tracelog-timestamps) XCODER_TRACELOG_TIMESTAMPS=NO;; + --with-linux-virt-io-driver) XCODER_LINUX_VIRT_IO_DRIVER=YES;; + --without-linux-virt-io-driver) XCODER_LINUX_VIRT_IO_DRIVER=NO;; --with-data-dump) XCODER_DUMP_DATA=YES;; --without-data-dump) XCODER_DUMP_DATA=NO;; + --without-backtrace-print) XCODER_DISABLE_BACKTRACE_PRINT=YES;; + --with-info-level-ssim-log) XCODER_SSIM_INFO_LEVEL_LOGGING=YES;; + --without-info-level-ssim-log) XCODER_SSIM_INFO_LEVEL_LOGGING=NO;; --prefix*) extract_arg "\-\-prefix" $1 $2; eprc=$?; if [ "$eprc" -eq 1 ]; then shift; @@ -138,7 +140,7 @@ function parse_user_option() { if [ "$eprc" -eq 1 ]; then shift; fi - XCODER_SHAREDDIR=$extract_arg_ret;; + XCODER_SHAREDDIR=$extract_arg_ret;; *) echo "Unknown option $1, exiting"; exit 1;; esac shift @@ -155,11 +157,14 @@ function regenerate_options() { XCODER_AUTO_CONFIGURE="--includedir=${XCODER_INCLUDEDIR}" XCODER_AUTO_CONFIGURE="--shareddir=${XCODER_SHAREDDIR}" if [ "$XCODER_WIN32" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-win32"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-win32"; fi - if [ "$XCODER_WIN_NVME_CUSTOM" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-custom-nvme"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-win32"; fi + if [ "$XCODER_ANDROID" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-android"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-android"; fi if [ "$XCODER_SELF_KILL_ERR" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-self-kill"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-self-kill"; fi if [ "$XCODER_LATENCY_DISPLAY" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-latency-display"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-latency-display"; fi if [ "$XCODER_TRACELOG_TIMESTAMPS" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-tracelog-timestamps"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-tracelog-timestamps"; fi if [ "$XCODER_DUMP_DATA" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-data-dump"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-data-dump"; fi + if [ "$XCODER_LINUX_VIRT_IO_DRIVER" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-linux-virt-io-driver"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-linux-virt-io-driver"; fi + if [ "$XCODER_DISABLE_BACKTRACE_PRINT" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-backtrace-print"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-backtrace-print"; fi + if [ "$XCODER_SSIM_INFO_LEVEL_LOGGING" = YES ]; then XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --with-info-level-ssim-log"; else XCODER_AUTO_CONFIGURE="${XCODER_AUTO_CONFIGURE} --without-info-level-ssim-log"; fi echo "regenerate config: ${XCODER_AUTO_CONFIGURE}" } @@ -170,11 +175,13 @@ function check_option_conflicts() { # check variable neccessary if [ "$XCODER_WIN32" = RESERVED ]; then echo "you must specify the OS support, see: ./configure --help"; __check_ok=NO; fi - if [ "$XCODER_WIN_NVME_CUSTOM" = RESERVED ]; then echo "you must specify the NVME CUSTOM support, see: ./configure --help"; __check_ok=NO; fi + if [ "$XCODER_ANDROID" = RESERVED ]; then echo "you must specify the OS support, see: ./configure --help"; __check_ok=NO; fi if [ "$XCODER_SELF_KILL_ERR" = RESERVED ]; then echo "you must specify whether to compile self-kill macro on error, see: ./configure --help"; __check_ok=NO; fi if [ "$XCODER_LATENCY_DISPLAY" = RESERVED ]; then echo "you must specify whether to compile latency-display macro, see: ./configure --help"; __check_ok=NO; fi if [ "$XCODER_TRACELOG_TIMESTAMPS" = RESERVED ]; then echo "you must specify whether log messages during trace level are prefixed with timestamps, see: ./configure --help"; __check_ok=NO; fi + if [ "$XCODER_LINUX_VIRT_IO_DRIVER" = RESERVED ]; then echo "you must specify for the vm linux virt-io driver, see: ./configure --help"; __check_ok=NO; fi if [ "$XCODER_DUMP_DATA" = RESERVED ]; then echo "you must specify whether to compile data-dump macro, see: ./configure --help"; __check_ok=NO; fi + if [ "$XCODER_DISABLE_BACKTRACE_PRINT" = RESERVED ]; then echo "you must specify whether to compile with print backtrace, see: ./configure --help"; __check_ok=NO; fi } ##################################################################################### diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/build.sh b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/build.sh new file mode 100755 index 00000000..ba08c9fd --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/build.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env bash + +target_windows=false; +target_android=false; +include_gdb=false; +self_kill=false; +latency_display=false; +dump_data=false; +tracelog_timestamps=false; +build_linux_virt_io_driver=false; +warn_as_errors=false; +secure_compile=false; +build_doxygen=false; +disable_backtrace_print=false; +info_level_ssim_log=false; +RC=0 + +while [ "$1" != "" ]; do + case $1 in + -h | --help) echo "Usage: ./build.sh [OPTION]"; + echo "Compile Quadra libxcoder."; + echo "Example: ./build.sh"; + echo; + echo "Options:"; + echo "-h, --help display this help and exit"; + echo "-w, windows compile for Windows"; + echo "-a, --android compile for Android"; + echo "-g, --gdb compile with gdb debugging (and without -O3 optimizations)"; + echo "-k, --with-self-kill compile with self termination on multiple repeated NVMe errors"; + echo "-p, --with-latency-display compile with per frame latency display"; + echo "-d, --with-data-dump compile with dumping video transcoding data"; + echo "-v, --with-linux-virt-io-driver compile with vm linux virt-io driver"; + echo "-l, --with-tracelog-timestamps compile with microsecond timestamps on tracelogs"; + echo "-e, --warnings-as-errors compile with '-Werror'. Deprecation macros disabled"; + echo "-b, --disable-backtrace-print complie without print backtrace" + echo "-s, --secure-compile compile with more foritication such as strong stack protection and RELRO"; + echo "-m, --with-info-level-ssim-log compile with SSIM logging at info level. Default is at debug level"; + echo "--doxygen compile Doxygen (does not compile libxcoder)"; exit 0 + ;; + -w | windows) target_windows=true + ;; + -a | --android) target_android=true + ;; + -g | --gdb) include_gdb=true + ;; + -k | --with-self-kill) self_kill=true + ;; + -p | --with-latency-display) latency_display=true + ;; + -v | --with-linux-virt-io-driver) build_linux_virt_io_driver=true + ;; + -l | --with-tracelog-timestamps) tracelog_timestamps=true + ;; + -d | --with-data-dump) dump_data=true + ;; + -e | --warnings-as-errors) warn_as_errors=true + ;; + -b | --disable-backtrace-print) disable_backtrace_print=true + ;; + -s | --secure-compile) secure_compile=true + ;; + -m | --with-info-level-ssim-log) info_level_ssim_log=true + ;; + --doxygen) build_doxygen=true + ;; + *) echo "Usage: ./build.sh [OPTION]..."; echo "Try './build.sh --help' for more information"; exit 1 + ;; + esac + shift +done + +if $build_doxygen; then + # get project number from source/ni_defs.h + PROJ_NUM="$(grep -Poh "NI_XCODER_REVISION\s+\"\K[a-zA-Z0-9]{3}(?=.{5}\")" source/ni_defs.h)" + PROJ_NUM_FMTD=${PROJ_NUM:0:1}.${PROJ_NUM:1:1}.${PROJ_NUM:2:1} + `which sed` -i "s/^\(PROJECT_NUMBER\s*=\).*$/\1 $PROJ_NUM_FMTD/" source/doxygen/Doxyfile && + doxygen source/doxygen/Doxyfile; RC=$? + `which sed` -i "s/^\(PROJECT_NUMBER\s*=\).*$/\1/" source/doxygen/Doxyfile + exit $RC +fi + +# handle command line options +extra_make_flags="" +extra_config_flags="" + +if $include_gdb; then + extra_make_flags=" GDB=TRUE" +fi + +if $target_windows; then + extra_make_flags="${extra_make_flags} WINDOWS=TRUE" + extra_config_flags="${extra_config_flags} --with-win32 --without-self-kill" + self_kill=false +fi + +if $target_android; then + extra_make_flags="${extra_make_flags} DONT_WRITE_SONAME=TRUE" + extra_config_flags="${extra_config_flags} --with-android" +fi + +if $self_kill; then + extra_config_flags="${extra_config_flags} --with-self-kill" +else + extra_config_flags="${extra_config_flags} --without-self-kill" +fi + +if $latency_display; then + extra_config_flags="${extra_config_flags} --with-latency-display" +fi + +if $tracelog_timestamps; then + extra_config_flags="${extra_config_flags} --with-tracelog-timestamps" +fi + +if $info_level_ssim_log; then + extra_config_flags="${extra_config_flags} --with-info-level-ssim-log" +fi + +if $dump_data; then + extra_config_flags="${extra_config_flags} --with-data-dump" +fi + +if $build_linux_virt_io_driver; then + extra_config_flags="${extra_config_flags} --with-linux-virt-io-driver" +fi + +if $warn_as_errors; then + extra_make_flags="${extra_make_flags} WARN_AS_ERROR=TRUE" +fi + +if $disable_backtrace_print; then + extra_config_flags="${extra_config_flags} --without-backtrace-print" +fi + +if $secure_compile; then + extra_make_flags="${extra_make_flags} SECURE_COMPILE=TRUE" +fi + +# configure, build, and install +echo bash ./configure $extra_config_flags; +bash ./configure $extra_config_flags; +RC=$? + +if [ $RC = 0 ]; then + echo make all $extra_make_flags + make all $extra_make_flags + RC=$? +else + exit $RC +fi + +if [ $RC = 0 ]; then + if $target_windows; then + echo make install $extra_make_flags + make install $extra_make_flags + RC=$? + else + echo sudo make install $extra_make_flags + sudo make install $extra_make_flags + RC=$? + fi +else + exit $RC +fi + +exit $RC diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/configure b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/configure new file mode 100755 index 00000000..1ab934e1 --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/configure @@ -0,0 +1,190 @@ +#!/usr/bin/env bash + +##################################################################################### +# the main output dir, all configure and make output are in this dir. +##################################################################################### +# create the main objs +XCODER_WORKDIR="." +XCODER_OBJS_DIR="build" +XCODER_OBJS="${XCODER_WORKDIR}/${XCODER_OBJS_DIR}" +XCODER_MAKEFILE="Makefile" +XCODER_PKG_CONF="${XCODER_WORKDIR}/${XCODER_OBJS_DIR}/xcoder.pc" + +# linux shell color support. +RED="\\033[31m" +GREEN="\\033[32m" +YELLOW="\\033[33m" +BLACK="\\033[0m" + +##################################################################################### +# parse user options, set the variables like: +##################################################################################### +# parse options, exit with error when parse options invalid. + +. auto/options.sh + +# Default install path +if [ $XCODER_PREFIX != NO ]; then + echo "XCODER_PREFIX: ${XCODER_PREFIX}" + prefix=${XCODER_PREFIX} +else +prefix='/usr/local' +fi + +if [ $XCODER_BINDIR != NO ]; then + echo "XCODER_LIBDIR: ${XCODER_BINDIR}" + bindir=${XCODER_BINDIR} +else + bindir=${prefix}/bin +fi + +if [ $XCODER_LIBDIR != NO ]; then + echo "XCODER_LIBDIR: ${XCODER_LIBDIR}" + libdir=${XCODER_LIBDIR} +else + libdir=${prefix}/lib +fi + +if [ $XCODER_INCLUDEDIR != NO ]; then + echo "XCODER_INCLUDEDIR: ${XCODER_INCLUDEDIR}" + includedir=${XCODER_INCLUDEDIR} +else + includedir=${prefix}/include +fi + +if [ $XCODER_SHAREDDIR != NO ]; then + echo "XCODER_SHAREDDIR: ${XCODER_SHAREDDIR}" + shareddir=${XCODER_SHAREDDIR} +else + shareddir='' +fi + +# Create build folder for compilation +if [ ! -d "${XCODER_WORKDIR}/${XCODER_OBJS_DIR}" ]; then + mkdir ${XCODER_WORKDIR}/${XCODER_OBJS_DIR} +fi + +# the auto generated variables. +. auto/auto_headers.sh + +rm ${XCODER_PKG_CONF} + +cat > ${XCODER_PKG_CONF} << EOF +prefix=$prefix +exec_prefix=$exec_prefix +libdir=$libdir +bindir=$bindir +includedir=$includedir +shareddir=$shareddir + +Name: xcoder +Description: Network Intelligence Xcoder Quadra Codec library +Version: $(grep 'NI_XCODER_REVISION \"' source/ni_defs.h | cut -d '"' -f 2) +Libs: -L$libdir -lxcoder +EOF + +if [ $XCODER_WIN32 = YES ]; then +cat >> ${XCODER_PKG_CONF} << EOF +Libs.private: -lwinpthread -lws2_32 +Cflags: -D_WIN32 -I$includedir +EOF +elif [ $XCODER_ANDROID = YES ]; then +cat >> ${XCODER_PKG_CONF} << EOF +Libs.private: +Cflags: -I$includedir +EOF +else +if ldconfig -p 2> /dev/null | grep -q librt.so ; then +cat >> ${XCODER_PKG_CONF} << EOF +Libs.private: -lpthread -lrt +Cflags: -I$includedir +EOF +else +cat >> ${XCODER_PKG_CONF} << EOF +Libs.private: -lpthread +Cflags: -I$includedir +EOF +fi +fi + +# Attempt to create dir without root access first +mkdir $prefix -p +if [ ! -d "$prefix" ]; then + sudo mkdir $prefix +fi + +mkdir $libdir -p +if [ ! -d "$libdir" ]; then + sudo mkdir $libdir +fi + +# Create pkgconfig folder for installation +mkdir $libdir/pkgconfig -p +if [ ! -d "$libdir/pkgconfig" ]; then + sudo mkdir $libdir/pkgconfig +fi + +echo 'configure ok! ' + +##################################################################################### +# configure summary +##################################################################################### +# summary +echo "" +echo "configure summary:" +echo " ${XCODER_AUTO_USER_CONFIGURE}" +echo " ${XCODER_AUTO_CONFIGURE}" + +if [ $XCODER_TRACELOG_TIMESTAMPS = YES ]; then + echo -e "${GREEN}NI_LOG_TRACE_TIMESTAMPS is enabled${BLACK}" +else + echo -e "${YELLOW}NI_LOG_TRACE_TIMESTAMPS is disabled${BLACK}" +fi + +if [ $XCODER_SSIM_INFO_LEVEL_LOGGING = YES ]; then + echo -e "${GREEN}NI_LOG_SSIM_AT_INFO is enabled${BLACK}" +else + echo -e "${YELLOW}NI_LOG_SSIM_AT_INFO is disabled${BLACK}" +fi + +if [ $XCODER_WIN32 = YES ]; then + echo -e "${GREEN}XCODER_WIN32 is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_WIN32 is disabled${BLACK}" +fi + +if [ $XCODER_ANDROID = YES ]; then + echo -e "${GREEN}XCODER_ANDROID is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_ANDROID is disabled${BLACK}" +fi + +if [ $XCODER_SELF_KILL_ERR = YES ]; then + echo -e "${GREEN}XCODER_SELF_KILL_ERR is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_SELF_KILL_ERR is disabled${BLACK}" +fi + +if [ $XCODER_LATENCY_DISPLAY = YES ]; then + echo -e "${GREEN}XCODER_LATENCY_DISPLAY is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_LATENCY_DISPLAY is disabled${BLACK}" +fi + +if [ $XCODER_LINUX_VIRT_IO_DRIVER = YES ]; then + echo -e "${GREEN}XCODER_LINUX_VIRT_IO_DRIVER is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_LINUX_VIRT_IO_DRIVER is disabled${BLACK}" +fi + +if [ $XCODER_DUMP_DATA = YES ]; then + echo -e "${GREEN}XCODER_DUMP_DATA is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_DUMP_DATA is disabled${BLACK}" +fi + +if [ $XCODER_DISABLE_BACKTRACE_PRINT = YES ]; then + echo -e "${GREEN}XCODER_DISABLE_BACKTRACE_PRINT is enabled${BLACK}" +else + echo -e "${YELLOW}XCODER_DISABLE_BACKTRACE_PRINT is disabled${BLACK}" +fi diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/readme.txt b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/readme.txt new file mode 100644 index 00000000..7eed223e --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/readme.txt @@ -0,0 +1,175 @@ + +Quadra Xcoder Codec Library User Guide: + + + +============================== +To configure and build library +============================== + +--------------------------- +To default install location: +--------------------------- + +cd libxcoder +./configure && make +sudo make install + + +Codec library 'libxcoder.a' is by default installed to /usr/local/lib +Codec library 'libxcoder.so' is by default installed to /usr/local/lib +Codec Pkg Config 'xcoder.pc' is by default installed to /usr/local/lib/pkgconfig +Codec API Header 'xcoder_api.h' is by default installed to /usr/local/include +Standalone test program 'xcoder' is locally generated in libxcoder/build + + +-------------------------- +To fully customize install: +-------------------------- + +./configure --libdir=/custom_lib_folder --bindir=/custom_bin_folder \ +--includedir=/custom_include_folder --shareddir=/additional_lib_folder && sudo make install + + +------------ +To uninstall: +------------ + +sudo make uninstall + +or + +sudo make uninstall LIBDIR=/custom_lib_folder BINDIR=/custom_bin_folder \ +INCLUDEDIR=/custom_include_folder SHAREDDIR=/additional_lib_folder + + +------------- +Build Options: +------------- + +To enable video data dump (default: --without-dump) +./configure --with-dump + +To enable libxcoder self termination on repeated NVMe error +./configure --with-self-kill + +To enable libxcoder latency test patch (default: --without-latency-patch) +./configure --with-latency-patch + +To set custom installation path for libxcoder.so and pkgconfig files +./configure --libdir custom_lib_folder/ + +To set custom installation path for binary utilities (ni_rsrc_mon, etc.) +./configure --bindir custom_bin_folder/ + +To set custom installation path for libxcoder headers +./configure --includedir custom_include_folder/ + +To set additional installation path for libxcoder.so +./configure --shareddir additional_lib_folder/ + +---------------- +Peer-to-peer DMA: +---------------- +Not supported on Windows + +To use peer-to-peer DMA, build the NetInt Linux kernel driver (for Linux kernel >= 5.4). +you must have the kernel headers installed prior to compiling with make. + +cd dma-buf/ +make + +============================== +To run standalone test program +============================== +Note: for now, decoding/encoding/transcoding has the following unsupported features: + - Audio + - Container, demuxer, muxer + - H.265 frame parsing + - Custom user SEI + - Encoder sequence change + - Decoder/encoder engine reset/recovery + - Dolby Vision + - HW download (TBC on later date) + - 2D engine HW frame filtering (TBC on later date) + - Decoder PPU output configuration (TBC on later date) + - Decoder multi-output receiving and splitting (TBC on later date) + +------------ +Test Decoder: +------------ + + cd libxcoder/build + ./xcoder -c 0 -i ../test/akiyo_352x288p25.264 -o aki.yuv -m a2y + +------------ +Test Encoder: +------------ + + cd libxcoder/build + ./xcoder -c 0 -i ../test/akiyo_352x288p25.yuv -o aki-xcoder.265 -s 352x288 -m y2h + +--------------- +Test Transcoder: +--------------- + + cd libxcoder/build + ./xcoder -c 0 -i ../test/akiyo_352x288p25.264 -o aki-xcoder-trans.265 -m a2h + +--------------- +Test Transcoder (HW frames): +--------------- + + cd libxcoder/build + ./xcoder -c 0 -i ../test/akiyo_352x288p25.264 -o aki-xcoder-trans.265 -m a2h -d out=hw + +--------------- +Test Uploader + Encoder: +--------------- + + cd libxcoder/build + ./xcoder -c 0 -i ../test/akiyo_352x288p25.yuv -o aki-xcoder.265 -s 352x288 -m u2h + +--------------- +Test P2P DMA +--------------- +Not supported on Windows + + cd dma-buf + sudo insmod netint.ko + sudo chmod 777 /dev/netint + cd libxcoder/build + ./xcoderp2p -c 0 -i ../test/akiyo_352x288p25.yuv -o aki-xcoder.265 -s 352x288 -m p2h + + +=================================== +To Integrate into user applications +=================================== + +------------------- +FFmpeg applications: +------------------- + +Configure and build FFmpeg with: + +./configure --enable-libxcoder && make + + +------------------ +Other applications: +------------------ + +Codec library: libxcoder.a +API header: ni_device_api.h + +1. Add libxcoder.a as one of libraries to link +2. Add ni_device_api.h in source code calling Codec API + +For C +#include "ni_device_api.h" + +For C++ + +extern "C" { +#include "ni_device_api.h" +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/readme_windows.txt b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/readme_windows.txt new file mode 100644 index 00000000..4a79ce67 --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/readme_windows.txt @@ -0,0 +1,22 @@ + + +directly install mingw + sudo apt update + sudo apt upgrade + sudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git + sudo apt-get autoremove + + sudo apt-get install mingw-w64 + sudo apt-get install gcc-mingw-w64-x86-64 + sudo apt-get install mingw-w64-tools + +Check and Verify with + apt-cache search mingw + gcc-mingw-w64-x86-64 - GNU C compiler for MinGW-w64 targeting Win64 + mingw-w64 - Development environment targeting 32- and 64-bit Windows + mingw-w64-tools - Development tools for 32- and 64-bit Windows + +cd /usr/x86_64-w64-mingw32/ && sudo mkdir bin + +ERROR : yasm/nasm not found or too old. Use --disable-yasm for a crippled build +Fix : sudo apt-get install yasm diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/Android.bp b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/Android.bp index e517e8fd..4f488123 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/Android.bp +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/Android.bp @@ -1,6 +1,6 @@ //############################################################################### -cc_library_shared { +cc_library { name: "libxcoder", srcs: [ "ni_lat_meas.c", @@ -17,7 +17,7 @@ cc_library_shared { vendor_available: true, vndk: { - enabled: true, + enabled: false, }, // proprietary: true, //PRODUCT_COPY_FILES += $(TARGET_OUT)/lib64/libxcoder.so:/usr/local/lib64/ @@ -56,15 +56,6 @@ cc_library_shared { "liblog", ], - sanitize: { - misc_undefined: [ - "signed-integer-overflow", - ], - cfi: true, - diag: { - cfi: true, - }, - }, ldflags: ["-Wl,-Bsymbolic"], clang: true, diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.cpp b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.cpp index f3489dc7..9690ec80 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.cpp +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.cpp @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ISharedBuffer.cpp -* -* \brief Exported routines related to resource management of NI Quadra devices -* -*******************************************************************************/ + * \file ISharedBuffer.cpp + * + * \brief Public definitions related to resource management of NETINT video + * processing devices on Android + *******************************************************************************/ #define LOG_TAG "ISharedBuffer" @@ -100,6 +100,7 @@ class BpSharedBuffer : public BpInterface { } }; +// NOLINTNEXTLINE IMPLEMENT_META_INTERFACE(SharedBuffer, "net.int.ISharedBuffer"); /*!***************************************************************************** diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.h index a2d7a1e0..a1de6fbd 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/common/ISharedBuffer.h @@ -20,12 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ISharedBuffer.h -* -* \brief Exported definitions related to resource management of NI Quadra devices -* -*******************************************************************************/ - + * \file ISharedBuffer.h + * + * \brief Public definitions related to resource management of NETINT video + * processing devices on Android + *******************************************************************************/ #ifndef ISHAREDBUFFER_H_ #define ISHAREDBUFFER_H_ diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/doxygen/Doxyfile b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/doxygen/Doxyfile index 26bac911..eb860eb2 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/doxygen/Doxyfile +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/doxygen/Doxyfile @@ -888,7 +888,7 @@ FILE_PATTERNS = *.c \ # be searched for input files as well. # The default value is: NO. -RECURSIVE = NO +RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a @@ -897,7 +897,7 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = source/android/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/init_rsrc.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/init_rsrc.c index 15c88e42..0da14f03 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/init_rsrc.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/init_rsrc.c @@ -20,15 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** + * \file init_rsrc.c * - * \file init_rsrc.c - * - * @date April 1, 2018 - * - * \brief - * - * @author - * + * \brief Application for registering Netint transcoding devices on system + * for use by libxcoder ******************************************************************************/ #include @@ -46,14 +41,6 @@ #include "ni_rsrc_api.h" #include "ni_rsrc_priv.h" - -/*!****************************************************************************** - * \brief - * - * \param - * - * \return - *******************************************************************************/ int main(int argc, char *argv[]) { int should_match_rev = 1; diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.c index 1aa0903d..156cd051 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.c @@ -20,12 +20,16 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_av_codec.c -* -* \brief NETINT audio/video related utility functions -* -*******************************************************************************/ + * \file ni_av_codec.c + * + * \brief Audio/video related utility definitions + ******************************************************************************/ +#ifdef _WIN32 +#include +#else +#include +#endif #include #include #include @@ -34,6 +38,7 @@ #include "ni_nvme.h" #include "ni_bitstream.h" #include "ni_av_codec.h" +#include "ni_device_api_priv.h" typedef enum { @@ -68,7 +73,7 @@ typedef enum NUM_GOP_PRESET_NUM = 17, } gop_preset_t; -static const int32_t GOP_SIZE[NUM_GOP_PRESET_NUM] = {0, 1, 1, 1, 2, 4, 4, +NI_UNUSED static const int32_t GOP_SIZE[NUM_GOP_PRESET_NUM] = {0, 1, 1, 1, 2, 4, 4, 4, 8, 1, 2, 4, 4}; static const int32_t LT_GOP_PRESET_I_1[6] = {SLICE_TYPE_I, 1, 0, 0, 0, 0}; @@ -139,7 +144,7 @@ static const int32_t LT_GOP_PRESET_BBBBBBBSP_8[48] = { SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8, }; -static const int32_t *GOP_PRESET[NUM_GOP_PRESET_NUM] = { +NI_UNUSED static const int32_t *GOP_PRESET[NUM_GOP_PRESET_NUM] = { NULL, LT_GOP_PRESET_I_1, LT_GOP_PRESET_P_1, @@ -188,15 +193,31 @@ int ni_should_send_sei_with_frame(ni_session_context_t *p_enc_ctx, if (0 == p_enc_ctx->frame_num || PIC_TYPE_IDR == pic_type || (p_param->cfg_enc_params.forced_header_enable && p_param->cfg_enc_params.intra_period && - 0 == (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period))) + 0 == + ((p_enc_ctx->frame_num + p_enc_ctx->force_idr_intra_offset) % + p_param->cfg_enc_params.intra_period))) { + if (PIC_TYPE_IDR == pic_type && + p_param->cfg_enc_params.forced_header_enable && + p_param->cfg_enc_params.intra_period && + 0 != (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period)) + { + p_enc_ctx->force_idr_intra_offset = + p_param->cfg_enc_params.intra_period - + (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period); + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, "should send sei? %" PRIu64 " %d %d %d %u\n", + p_enc_ctx->frame_num, pic_type, + p_param->cfg_enc_params.forced_header_enable, + p_param->cfg_enc_params.intra_period, + p_enc_ctx->force_idr_intra_offset); return 1; } return 0; } // create a ni_rational_t -static ni_rational_t ni_make_rational(int num, int den) +NI_UNUSED static ni_rational_t ni_make_rational(int num, int den) { ni_rational_t r = {num, den}; return r; @@ -268,8 +289,8 @@ void ni_dec_retrieve_aux_data(ni_frame_t *frame) { ni_mastering_display_metadata_t *mdm = (ni_mastering_display_metadata_t *)aux_data->data; - const int chroma_den = 50000; - const int luma_den = 10000; + const int chroma_den = MASTERING_DISP_CHROMA_DEN; + const int luma_den = MASTERING_DISP_LUMA_DEN; ni_dec_mastering_display_colour_volume_bytes_t *pColourVolume = (ni_dec_mastering_display_colour_volume_bytes_t *)((uint8_t *)frame->p_data[start_offset] + @@ -278,33 +299,33 @@ void ni_dec_retrieve_aux_data(ni_frame_t *frame) // HEVC uses a g,b,r ordering, which we convert to a more natural r, // g,b,this is so we are compatible with FFmpeg default soft decoder mdm->display_primaries[0][0].num = - ni_ntohs(pColourVolume->display_primaries[2][0]); + ntohs(pColourVolume->display_primaries[2][0]); mdm->display_primaries[0][0].den = chroma_den; mdm->display_primaries[0][1].num = - ni_ntohs(pColourVolume->display_primaries[2][1]); + ntohs(pColourVolume->display_primaries[2][1]); mdm->display_primaries[0][1].den = chroma_den; mdm->display_primaries[1][0].num = - ni_ntohs(pColourVolume->display_primaries[0][0]); + ntohs(pColourVolume->display_primaries[0][0]); mdm->display_primaries[1][0].den = chroma_den; mdm->display_primaries[1][1].num = - ni_ntohs(pColourVolume->display_primaries[0][1]); + ntohs(pColourVolume->display_primaries[0][1]); mdm->display_primaries[1][1].den = chroma_den; mdm->display_primaries[2][0].num = - ni_ntohs(pColourVolume->display_primaries[1][0]); + ntohs(pColourVolume->display_primaries[1][0]); mdm->display_primaries[2][0].den = chroma_den; mdm->display_primaries[2][1].num = - ni_ntohs(pColourVolume->display_primaries[1][1]); + ntohs(pColourVolume->display_primaries[1][1]); mdm->display_primaries[2][1].den = chroma_den; - mdm->white_point[0].num = ni_ntohs(pColourVolume->white_point_x); + mdm->white_point[0].num = ntohs(pColourVolume->white_point_x); mdm->white_point[0].den = chroma_den; - mdm->white_point[1].num = ni_ntohs(pColourVolume->white_point_y); + mdm->white_point[1].num = ntohs(pColourVolume->white_point_y); mdm->white_point[1].den = chroma_den; mdm->min_luminance.num = - ni_ntohl(pColourVolume->min_display_mastering_luminance); + ntohl(pColourVolume->min_display_mastering_luminance); mdm->min_luminance.den = luma_den; mdm->max_luminance.num = - ni_ntohl(pColourVolume->max_display_mastering_luminance); + ntohl(pColourVolume->max_display_mastering_luminance); mdm->max_luminance.den = luma_den; mdm->has_luminance = mdm->has_primaries = 1; @@ -332,8 +353,8 @@ void ni_dec_retrieve_aux_data(ni_frame_t *frame) *)((uint8_t *)frame->p_data[start_offset] + frame->sei_hdr_content_light_level_info_offset); - clm->max_cll = ni_ntohs(pLightLevel->max_content_light_level); - clm->max_fall = ni_ntohs(pLightLevel->max_pic_average_light_level); + clm->max_cll = ntohs(pLightLevel->max_content_light_level); + clm->max_fall = ntohs(pLightLevel->max_pic_average_light_level); } } @@ -621,125 +642,27 @@ void ni_dec_retrieve_aux_data(ni_frame_t *frame) if (frame->vui_offset || frame->vui_len) { sei_buf = (uint8_t *)frame->p_data[start_offset] + frame->vui_offset; + ni_extended_dec_metadata_t *p_dec_ext_meta = + (ni_extended_dec_metadata_t *)sei_buf; + frame->vui_num_units_in_tick = p_dec_ext_meta->num_units_in_tick; + frame->vui_time_scale = p_dec_ext_meta->time_scale; + frame->color_primaries = p_dec_ext_meta->color_primaries; + frame->color_trc = p_dec_ext_meta->color_trc; + frame->color_space = p_dec_ext_meta->color_space; + frame->video_full_range_flag = p_dec_ext_meta->video_full_range_flag; - if (NI_CODEC_FORMAT_H265 == frame->src_codec) - { - if (sizeof(ni_dec_h265_vui_param_t) == frame->vui_len) - { - ni_dec_h265_vui_param_t *vui = - (ni_dec_h265_vui_param_t *)sei_buf; - if (vui->colour_description_present_flag) - { - frame->color_primaries = vui->colour_primaries; - frame->color_trc = vui->transfer_characteristics; - frame->color_space = vui->matrix_coefficients; - } - frame->video_full_range_flag = vui->video_full_range_flag; - - if (vui->aspect_ratio_info_present_flag) - { - frame->aspect_ratio_idc = vui->aspect_ratio_idc; - if (255 == frame->aspect_ratio_idc) - { - frame->sar_width = vui->sar_width; - frame->sar_height = vui->sar_height; - } - } - - if (vui->vui_timing_info_present_flag) - { - frame->vui_num_units_in_tick = vui->vui_num_units_in_tick; - frame->vui_time_scale = vui->vui_time_scale; - } - - ni_log(NI_LOG_DEBUG, - "ni_dec_retrieve_aux_data H.265 VUI " - "aspect_ratio_info_present_flag %u aspect_ratio_idc %u " - "sar_width %u sar_height %u " - "video_signal_type_present_flag %u video_format %d " - "video_full_range_flag %d colour_description_present_flag " - "%u " - "color-pri %u color-trc %u color-space %u " - "vui_timing_info_present_flag %u vui_num_units_in_tick %u " - "vui_time_scale %u\n", - vui->aspect_ratio_info_present_flag, - frame->aspect_ratio_idc, frame->sar_width, - frame->sar_height, vui->video_signal_type_present_flag, - vui->video_format, frame->video_full_range_flag, - vui->colour_description_present_flag, - frame->color_primaries, frame->color_trc, - frame->color_space, vui->vui_timing_info_present_flag, - frame->vui_num_units_in_tick, frame->vui_time_scale); - } else - { - ni_log(NI_LOG_DEBUG, - "ni_dec_retrieve_aux_data VUI, expecting H.265 VUI " - "struct size %d, got %u, dropped!\n", - (int)sizeof(ni_dec_h265_vui_param_t), frame->vui_len); - } - } else if (NI_CODEC_FORMAT_H264 == frame->src_codec) - { - if (sizeof(ni_dec_h264_vui_param_t) == frame->vui_len) - { - ni_dec_h264_vui_param_t *vui = - (ni_dec_h264_vui_param_t *)sei_buf; - if (vui->colour_description_present_flag) - { - frame->color_primaries = vui->colour_primaries; - frame->color_trc = vui->transfer_characteristics; - frame->color_space = vui->matrix_coefficients; - } - frame->video_full_range_flag = vui->video_full_range_flag; - - if (vui->aspect_ratio_info_present_flag) - { - frame->aspect_ratio_idc = vui->aspect_ratio_idc; - if (255 == frame->aspect_ratio_idc) - { - frame->sar_width = vui->sar_width; - frame->sar_height = vui->sar_height; - } - } - - if (vui->vui_timing_info_present_flag) - { - frame->vui_num_units_in_tick = vui->vui_num_units_in_tick; - frame->vui_time_scale = vui->vui_time_scale; - } - - ni_log(NI_LOG_DEBUG, - "ni_dec_retrieve_aux_data H.264 VUI " - "aspect_ratio_info_present_flag %u aspect_ratio_idc %u " - "sar_width %u sar_height %u " - "video_signal_type_present_flag %u video_format %d " - "video_full_range_flag %d colour_description_present_flag " - "%u " - "color-pri %u color-trc %u color-space %u " - "vui_timing_info_present_flag %u vui_num_units_in_tick %u " - "vui_time_scale %u pic_struct_present_flag %u\n", - vui->aspect_ratio_info_present_flag, - frame->aspect_ratio_idc, frame->sar_width, - frame->sar_height, vui->video_signal_type_present_flag, - vui->video_format, frame->video_full_range_flag, - vui->colour_description_present_flag, - frame->color_primaries, frame->color_trc, - frame->color_space, vui->vui_timing_info_present_flag, - frame->vui_num_units_in_tick, frame->vui_time_scale, - vui->pic_struct_present_flag); - } else - { - ni_log(NI_LOG_DEBUG, - "ni_dec_retrieve_aux_data VUI, expecting H.264 VUI " - "struct size %d, got %u, dropped!\n", - (int)sizeof(ni_dec_h264_vui_param_t), frame->vui_len); - } - } else - { - ni_log(NI_LOG_DEBUG, - "ni_dec_retrieve_aux_data VUI, unsupported codec: %d, " - "dropped\n", - frame->src_codec); - } + ni_log(NI_LOG_DEBUG, + "ni_dec_retrieve_aux_data VUI " + "aspect_ratio_idc %u " + "sar_width %u sar_height %u " + "video_full_range_flag %d " + "color-pri %u color-trc %u color-space %u " + "vui_num_units_in_tick %u " + "vui_time_scale %u\n", + frame->aspect_ratio_idc, frame->sar_width, frame->sar_height, + frame->video_full_range_flag, frame->color_primaries, + frame->color_trc, frame->color_space, + frame->vui_num_units_in_tick, frame->vui_time_scale); } // alternative transfer characteristics SEI if available @@ -775,6 +698,13 @@ static int set_roi_map(ni_session_context_t *p_enc_ctx, uint32_t max_cu_size = (codec_format == NI_CODEC_FORMAT_H264) ? 16 : 64; + // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation + if (NI_CODEC_FORMAT_AV1 == codec_format) + { + width = (width / 8) * 8; + height = (height / 8) * 8; + } + // for H.264, select ROI Map Block Unit Size: 16x16 // for H.265, select ROI Map Block Unit Size: 64x64 uint32_t roiMapBlockUnitSize = @@ -812,10 +742,10 @@ static int set_roi_map(ni_session_context_t *p_enc_ctx, // decreasing importance. for (r = nb_roi - 1; r >= 0; r--) { - roi = (const ni_region_of_interest_t *)(aux_data->data + self_size * r); + roi = (const ni_region_of_interest_t *)((uint8_t *)aux_data->data + self_size * r); if (!roi->qoffset.den) { - ni_log(NI_LOG_DEBUG, "ni_region_of_interest_t.qoffset.den must not be " + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_region_of_interest_t.qoffset.den must not be " "zero.\n"); continue; } @@ -828,7 +758,7 @@ static int set_roi_map(ni_session_context_t *p_enc_ctx, // Theoretically the possible qp delta range is (-32 to 31) set_qp = (NI_MAX_QP_INFO + 1 - set_qp) % (NI_MAX_QP_INFO + 1); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "set_roi_map: left %d right %d top %d bottom %d num %d den" " %d set_qp %d\n", roi->left, roi->right, roi->top, roi->bottom, roi->qoffset.num, @@ -866,7 +796,7 @@ static int set_roi_map(ni_session_context_t *p_enc_ctx, .field.roiAbsQp_flag = 0; // delta QP p_enc_ctx->roi_map[k * subNumMbs + m].field.qp_info = set_qp; - // ni_log(NI_LOG_DEBUG, "## x %d y %d index %d\n", i, + // ni_log2(p_enc_ctx, NI_LOG_DEBUG, "## x %d y %d index %d\n", i, // j, k*subNumMbs+m); } } @@ -935,6 +865,65 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_frame->sei_hdr_plus_offset = p_enc_frame->sei_hdr_plus_len = 0; + // prep for NetInt intra period reconfiguration support: when intra period + // setting has been requested by both frame and API, API takes priority + int intraprd = -1; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_INTRAPRD); + if (aux_data) + { + intraprd = *((int32_t *)aux_data->data); + if (intraprd < 0 || intraprd > 1024) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid intraperiod in aux data %d\n", + __func__, intraprd); + intraprd = -1; + } + } + + if (p_enc_ctx->reconfig_intra_period >= 0) + { + intraprd = p_enc_ctx->reconfig_intra_period; + p_enc_ctx->reconfig_intra_period = -1; + ni_log(NI_LOG_DEBUG, "%s(): API set intraPeriod %d\n", __func__, + intraprd); + } + + if (intraprd >= 0) + { + if (api_params->cfg_enc_params.intra_mb_refresh_mode || + api_params->cfg_enc_params.gop_preset_index == 1) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): NOT allowed to reconfig intraPeriod %d in intra_mb_refresh_mode %d or gop_preset_index %d\n", + __func__, + intraprd, + api_params->cfg_enc_params.intra_mb_refresh_mode, + api_params->cfg_enc_params.gop_preset_index); + } + else + { + // FW forces IDR frame when reconfig intra period, so the following steps are required for repeating SEI (and required for ni_should_send_sei_with_frame) + should_send_sei_with_frame = 1; + api_params->cfg_enc_params.intra_period = intraprd; + + if (intraprd) + { + p_enc_ctx->force_idr_intra_offset = + intraprd - (p_enc_ctx->frame_num % intraprd); + } + else + { + p_enc_ctx->force_idr_intra_offset = 0; + } + + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_INTRA_PERIOD; + p_enc_ctx->enc_change_params->intraPeriod = intraprd; + ni_log(NI_LOG_INFO, "%s(): set intraPeriod %d on frame %u, update intra offset %u\n", __func__, + intraprd, p_enc_ctx->frame_num, p_enc_ctx->force_idr_intra_offset); + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } + } + // prep SEI for HDR (mastering display color volume) aux_data = ni_frame_get_aux_data( p_dec_frame, NI_FRAME_AUX_DATA_MASTERING_DISPLAY_METADATA); @@ -958,19 +947,19 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, } if (!p_enc_ctx->p_master_display_meta_data) { - ni_log(NI_LOG_ERROR, "Error mem alloc for mastering display color vol\n"); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "Error mem alloc for mastering display color vol\n"); } else { memcpy(p_enc_ctx->p_master_display_meta_data, p_src, sizeof(ni_mastering_display_metadata_t)); - const int luma_den = 10000; + const int luma_den = MASTERING_DISP_LUMA_DEN; - uint32_t uint32_t_tmp = ni_htonl( + uint32_t uint32_t_tmp = htonl( (uint32_t)(lrint(luma_den * ni_q2d(p_src->max_luminance)))); memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data, &uint32_t_tmp, sizeof(uint32_t)); - uint32_t_tmp = ni_htonl( + uint32_t_tmp = htonl( (uint32_t)(lrint(luma_den * ni_q2d(p_src->min_luminance)))); memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data + 4, &uint32_t_tmp, sizeof(uint32_t)); @@ -1013,8 +1002,8 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, (ni_mastering_display_metadata_t *) p_enc_ctx->p_master_display_meta_data; - const int chroma_den = 50000; - const int luma_den = 10000; + const int chroma_den = MASTERING_DISP_CHROMA_DEN; + const int luma_den = MASTERING_DISP_LUMA_DEN; uint16_t dp00 = 0, dp01 = 0, dp10 = 0, dp11 = 0, dp20 = 0, dp21 = 0, wpx = 0, wpy = 0; @@ -1023,29 +1012,29 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, // when sent to encoder dp00 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[1][0])); - p_mdcv->display_primaries[0][0] = ni_htons(dp00); + p_mdcv->display_primaries[0][0] = htons(dp00); dp01 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[1][1])); - p_mdcv->display_primaries[0][1] = ni_htons(dp01); + p_mdcv->display_primaries[0][1] = htons(dp01); dp10 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[2][0])); - p_mdcv->display_primaries[1][0] = ni_htons(dp10); + p_mdcv->display_primaries[1][0] = htons(dp10); dp11 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[2][1])); - p_mdcv->display_primaries[1][1] = ni_htons(dp11); + p_mdcv->display_primaries[1][1] = htons(dp11); dp20 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[0][0])); - p_mdcv->display_primaries[2][0] = ni_htons(dp20); + p_mdcv->display_primaries[2][0] = htons(dp20); dp21 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[0][1])); - p_mdcv->display_primaries[2][1] = ni_htons(dp21); + p_mdcv->display_primaries[2][1] = htons(dp21); wpx = (uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[0])); - p_mdcv->white_point_x = ni_htons(wpx); + p_mdcv->white_point_x = htons(wpx); wpy = (uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[1])); - p_mdcv->white_point_y = ni_htons(wpy); + p_mdcv->white_point_y = htons(wpy); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "mastering display color volume, primaries " "%u/%u/%u/%u/%u/%u white_point_x/y %u/%u max/min_lumi %u/%u\n", (uint16_t)dp00, (uint16_t)dp01, (uint16_t)dp10, (uint16_t)dp11, @@ -1082,11 +1071,11 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, } uint16_t max_content_light_level = - ni_htons(((ni_content_light_level_t *)aux_data->data)->max_cll); + htons(((ni_content_light_level_t *)aux_data->data)->max_cll); uint16_t max_pic_average_light_level = - ni_htons(((ni_content_light_level_t *)aux_data->data)->max_fall); + htons(((ni_content_light_level_t *)aux_data->data)->max_fall); - ni_log(NI_LOG_DEBUG, "content light level info, MaxCLL %u MaxFALL %u\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "content light level info, MaxCLL %u MaxFALL %u\n", ((ni_content_light_level_t *)aux_data->data)->max_cll, ((ni_content_light_level_t *)aux_data->data)->max_fall); @@ -1141,13 +1130,13 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_A53_CC); if (aux_data) { - ni_log(NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d\n", aux_data->size); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d\n", aux_data->size); uint8_t cc_data_emu_prevent[NI_MAX_SEI_DATA]; int cc_size = aux_data->size; if (cc_size > NI_MAX_SEI_DATA) { - ni_log(NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d > MAX %d !\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d > MAX %d !\n", aux_data->size, (int)NI_MAX_SEI_DATA); cc_size = NI_MAX_SEI_DATA; } @@ -1156,7 +1145,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ni_insert_emulation_prevent_bytes(cc_data_emu_prevent, cc_size); if (cc_size_emu_prevent != cc_size) { - ni_log(NI_LOG_DEBUG, "ni_enc_prep_aux_data: close caption " + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data: close caption " "emulation prevention bytes added: %d\n", cc_size_emu_prevent - cc_size); } @@ -1222,7 +1211,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ni_bs_writer_put(&pb, 0, 8); // u8 application version = 0x00 ni_bs_writer_put(&pb, hdrp->num_windows, 2); - ni_log(NI_LOG_DEBUG, "hdr10+ num_windows %u\n", hdrp->num_windows); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_windows %u\n", hdrp->num_windows); for (w = 1; w < hdrp->num_windows; w++) { ni_bs_writer_put( @@ -1252,10 +1241,10 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ni_bs_writer_put(&pb, ui_tmp, 27); ni_bs_writer_put( &pb, hdrp->targeted_system_display_actual_peak_luminance_flag, 1); - ni_log(NI_LOG_DEBUG, "hdr10+ targeted_system_display_maximum_luminance " + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_maximum_luminance " "%u\n", ui_tmp); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_actual_peak_luminance_" "flag %u\n", hdrp->targeted_system_display_actual_peak_luminance_flag); @@ -1270,7 +1259,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, &pb, hdrp->num_cols_targeted_system_display_actual_peak_luminance, 5); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_rows_targeted_system_display_actual_peak_luminance " "x num_cols_targeted_system_display_actual_peak_luminance %u x " "%u\n", @@ -1291,7 +1280,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, hdrp->targeted_system_display_actual_peak_luminance [i][j])); ni_bs_writer_put(&pb, ui_tmp, 4); - ni_log(NI_LOG_DEBUG, "hdr10+ targeted_system_display_actual_peak_" + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_actual_peak_" "luminance[%d][%d] %u\n", i, j, ui_tmp); } @@ -1303,15 +1292,15 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, { ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].maxscl[i])); ni_bs_writer_put(&pb, ui_tmp, 17); - ni_log(NI_LOG_DEBUG, "hdr10+ maxscl[%d][%d] %u\n", w, i, ui_tmp); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ maxscl[%d][%d] %u\n", w, i, ui_tmp); } ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].average_maxrgb)); ni_bs_writer_put(&pb, ui_tmp, 17); - ni_log(NI_LOG_DEBUG, "hdr10+ average_maxrgb[%d] %u\n", w, ui_tmp); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ average_maxrgb[%d] %u\n", w, ui_tmp); ni_bs_writer_put( &pb, hdrp->params[w].num_distribution_maxrgb_percentiles, 4); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n", w, hdrp->params[w].num_distribution_maxrgb_percentiles); @@ -1324,10 +1313,10 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, 100000 * ni_q2d(hdrp->params[w].distribution_maxrgb[i].percentile)); ni_bs_writer_put(&pb, ui_tmp, 17); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ distribution_maxrgb_percentage[%d][%d] %u\n", w, i, hdrp->params[w].distribution_maxrgb[i].percentage); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ distribution_maxrgb_percentile[%d][%d] %u\n", w, i, ui_tmp); } @@ -1335,12 +1324,12 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ui_tmp = lrint(1000 * ni_q2d(hdrp->params[w].fraction_bright_pixels)); ni_bs_writer_put(&pb, ui_tmp, 10); - ni_log(NI_LOG_DEBUG, "hdr10+ fraction_bright_pixels[%d] %u\n", w, ui_tmp); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ fraction_bright_pixels[%d] %u\n", w, ui_tmp); } ni_bs_writer_put(&pb, hdrp->mastering_display_actual_peak_luminance_flag, 1); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ mastering_display_actual_peak_luminance_flag %u\n", hdrp->mastering_display_actual_peak_luminance_flag); if (hdrp->mastering_display_actual_peak_luminance_flag) @@ -1349,7 +1338,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, &pb, hdrp->num_rows_mastering_display_actual_peak_luminance, 5); ni_bs_writer_put( &pb, hdrp->num_cols_mastering_display_actual_peak_luminance, 5); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_rows_mastering_display_actual_peak_luminance x " "num_cols_mastering_display_actual_peak_luminance %u x %u\n", hdrp->num_rows_mastering_display_actual_peak_luminance, @@ -1368,7 +1357,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, hdrp->mastering_display_actual_peak_luminance[i] [j])); ni_bs_writer_put(&pb, ui_tmp, 4); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ " "mastering_display_actual_peak_luminance[%d][%d] %u\n", i, j, ui_tmp); @@ -1378,49 +1367,49 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, for (w = 0; w < hdrp->num_windows; w++) { ni_bs_writer_put(&pb, hdrp->params[w].tone_mapping_flag, 1); - ni_log(NI_LOG_DEBUG, "hdr10+ tone_mapping_flag[%d] %u\n", w, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ tone_mapping_flag[%d] %u\n", w, hdrp->params[w].tone_mapping_flag); if (hdrp->params[w].tone_mapping_flag) { ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_x)); ni_bs_writer_put(&pb, ui_tmp, 12); - ni_log(NI_LOG_DEBUG, "hdr10+ knee_point_x[%d] %u\n", w, ui_tmp); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ knee_point_x[%d] %u\n", w, ui_tmp); ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_y)); ni_bs_writer_put(&pb, ui_tmp, 12); - ni_log(NI_LOG_DEBUG, "hdr10+ knee_point_y[%d] %u\n", w, ui_tmp); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ knee_point_y[%d] %u\n", w, ui_tmp); ni_bs_writer_put(&pb, hdrp->params[w].num_bezier_curve_anchors, 4); - ni_log(NI_LOG_DEBUG, "hdr10+ num_bezier_curve_anchors[%d] %u\n", w, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_bezier_curve_anchors[%d] %u\n", w, hdrp->params[w].num_bezier_curve_anchors); for (i = 0; i < hdrp->params[w].num_bezier_curve_anchors; i++) { ui_tmp = lrint( 1023 * ni_q2d(hdrp->params[w].bezier_curve_anchors[i])); ni_bs_writer_put(&pb, ui_tmp, 10); - ni_log(NI_LOG_DEBUG, "hdr10+ bezier_curve_anchors[%d][%d] %u\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ bezier_curve_anchors[%d][%d] %u\n", w, i, ui_tmp); } } ni_bs_writer_put(&pb, hdrp->params[w].color_saturation_mapping_flag, 1); - ni_log(NI_LOG_DEBUG, "hdr10+ color_saturation_mapping_flag[%d] %u\n", w, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ color_saturation_mapping_flag[%d] %u\n", w, hdrp->params[w].color_saturation_mapping_flag); if (hdrp->params[w].color_saturation_mapping_flag) { ui_tmp = lrint(8 * ni_q2d(hdrp->params[w].color_saturation_weight)); ni_bs_writer_put(&pb, 6, ui_tmp); - ni_log(NI_LOG_DEBUG, "hdr10+ color_saturation_weight[%d] %u\n", w, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ color_saturation_weight[%d] %u\n", w, ui_tmp); } } // num_windows uint64_t hdr10p_num_bytes = (ni_bs_writer_tell(&pb) + 7) / 8; - ni_log(NI_LOG_DEBUG, "hdr10+ total bits: %d -> bytes %" PRIu64 "\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ total bits: %d -> bytes %" PRIu64 "\n", (int)ni_bs_writer_tell(&pb), hdr10p_num_bytes); ni_bs_writer_align_zero(&pb); @@ -1472,7 +1461,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len; } else { - ni_log(NI_LOG_ERROR, + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ni_enc_prep_aux_data: codec %d not supported for HDR10+ " "SEI !\n", codec_format); @@ -1486,7 +1475,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_UDU_SEI); if (aux_data) { - ni_log(NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_user_data_unreg_len %d\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_user_data_unreg_len %d\n", aux_data->size); // emulation prevention checking: a working buffer of size in worst case @@ -1520,7 +1509,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, // discard this UDU SEI if the total SEI size exceeds the max size if (p_enc_frame->sei_total_len + sei_len > NI_ENC_MAX_SEI_BUF_SIZE) { - ni_log(NI_LOG_ERROR, + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ni_enc_prep_aux_data sei total length %u + sei_len %d " "exceeds maximum sei size %u, discarding it !\n", p_enc_frame->sei_total_len, sei_len, @@ -1584,7 +1573,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, self_size = roi->self_size; if (!self_size || aux_data->size % self_size) { - ni_log(NI_LOG_ERROR, "Invalid ni_region_of_interest_t.self_size, " + ni_log2(p_enc_ctx, NI_LOG_ERROR, "Invalid ni_region_of_interest_t.self_size, " "aux_data size %d self_size %u\n", aux_data->size, self_size); } else @@ -1604,7 +1593,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_ctx->av_rois = malloc(aux_data->size); if (!p_enc_ctx->av_rois) { - ni_log(NI_LOG_ERROR, "malloc ROI aux_data failed.\n"); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "malloc ROI aux_data failed.\n"); is_new_rois = 0; } else { @@ -1622,7 +1611,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, api_params->source_height, api_params->cfg_enc_params.rc.intra_qp)) { - ni_log(NI_LOG_ERROR, "set_roi_map failed\n"); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "set_roi_map failed\n"); } } } @@ -1658,7 +1647,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_frame->extra_data_len += p_enc_ctx->roi_len; - ni_log(NI_LOG_DEBUG, "ni_enc_prep_aux_data: supply QP map, cacheRoi %d " + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data: supply QP map, cacheRoi %d " "aux_data %d ctx->roi_map %d frame->roi_len %u ctx->roi_len %u\n", api_params->cacheRoi, aux_data != NULL, p_enc_ctx->roi_map != NULL, p_enc_frame->roi_len, p_enc_ctx->roi_len); @@ -1672,7 +1661,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (aux_data) { ltr = *((ni_long_term_ref_t *)aux_data->data); - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data LTR use_cur_src_as_ltr %u " "use_ltr %u\n", __func__, ltr.use_cur_src_as_long_term_pic, @@ -1685,7 +1674,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_ctx->ltr_to_set.use_cur_src_as_long_term_pic = p_enc_ctx->ltr_to_set.use_long_term_ref = 0; - ni_log(NI_LOG_DEBUG, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame API set LTR use_cur_src_as_ltr %u " "use_ltr %u\n", __func__, ltr.use_cur_src_as_long_term_pic, @@ -1699,6 +1688,29 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_frame->use_long_term_ref = ltr.use_long_term_ref; } + // prep for NetInt target max/min QP reconfiguration support: when max/min QP + // setting has been requested by both frame and API, API takes priority + ni_rc_min_max_qp qp_info = {0}; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_MAX_MIN_QP); + if (aux_data) + { + qp_info = *(ni_rc_min_max_qp *)aux_data->data; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, + "%s(): frame aux data qp info max/min I qp <%d %d> maxDeltaQp <%d> max/min PB qp <%d %d>", + __func__, qp_info.maxQpI, qp_info.minQpI, qp_info.maxDeltaQp, qp_info.maxQpPB, qp_info.minQpPB); + } + if (qp_info.maxQpI > 0) + { + p_enc_ctx->enc_change_params->minQpI = qp_info.minQpI; + p_enc_ctx->enc_change_params->maxQpI = qp_info.maxQpI; + p_enc_ctx->enc_change_params->maxDeltaQp = qp_info.maxDeltaQp; + p_enc_ctx->enc_change_params->minQpPB = qp_info.minQpPB; + p_enc_ctx->enc_change_params->maxQpPB = qp_info.maxQpPB; + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_RC_MIN_MAX_QP; + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } + // prep for NetInt target bitrate reconfiguration support: when bitrate // setting has been requested by both frame and API, API takes priority int32_t bitrate = -1; @@ -1706,7 +1718,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (aux_data) { bitrate = *((int32_t *)aux_data->data); - ni_log(NI_LOG_DEBUG, "%s(): frame aux data bitrate %d\n", __func__, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data bitrate %d\n", __func__, bitrate); } @@ -1714,7 +1726,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, { bitrate = p_enc_ctx->target_bitrate; p_enc_ctx->target_bitrate = -1; - ni_log(NI_LOG_DEBUG, "%s(): API set bitrate %d\n", __func__, bitrate); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set bitrate %d\n", __func__, bitrate); } if (bitrate > 0) @@ -1724,6 +1736,10 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_ctx->enc_change_params->bitRate = bitrate; p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + + // update last bitrate with reconfigured bitrate + p_enc_ctx->last_bitrate = bitrate; + ni_log2(p_enc_ctx, NI_LOG_INFO, "%s: bitrate %d updated for reconfig\n", __func__, bitrate); } // prep for NetInt API force frame type @@ -1733,7 +1749,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_frame->ni_pict_type = PIC_TYPE_IDR; p_enc_ctx->force_idr_frame = 0; - ni_log(NI_LOG_DEBUG, "%s(): API force IDR frame\n", __func__); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API force IDR frame\n", __func__); } // prep for NetInt VUI reconfiguration support: when VUI HRD @@ -1746,7 +1762,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (aux_vui_ptr->colorDescPresent < 0 || aux_vui_ptr->colorDescPresent > 1) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid colorDescPresent in aux data %d\n", + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid colorDescPresent in aux data %d\n", __func__, aux_vui_ptr->colorDescPresent); } else @@ -1756,7 +1772,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if((aux_vui_ptr->aspectRatioWidth > NI_MAX_ASPECTRATIO) || (aux_vui_ptr->aspectRatioHeight > NI_MAX_ASPECTRATIO)) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid aspect ratio in aux data %dx%d\n", + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid aspect ratio in aux data %dx%d\n", __func__, aux_vui_ptr->aspectRatioWidth, aux_vui_ptr->aspectRatioHeight); } else @@ -1771,7 +1787,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (aux_vui_ptr->videoFullRange < 0 || aux_vui_ptr->videoFullRange > 1) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid videoFullRange in aux data %d\n", + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid videoFullRange in aux data %d\n", __func__, aux_vui_ptr->videoFullRange); } else @@ -1790,7 +1806,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_ctx->vui.aspectRatioWidth = p_enc_ctx->vui.aspectRatioHeight = p_enc_ctx->vui.videoFullRange = 0; - ni_log(NI_LOG_DEBUG, "%s(): API set VUI " + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set VUI " "colorDescPresent %d colorPrimaries %d " "colorTrc %d colorSpace %d aspectRatioWidth %d " "aspectRatioHeight %d videoFullRange %d\n", @@ -1823,7 +1839,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (aux_data) { ltr_interval = *((int32_t *)aux_data->data); - ni_log(NI_LOG_DEBUG, "%s(): frame aux data LTR interval %d\n", __func__, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data LTR interval %d\n", __func__, ltr_interval); } @@ -1831,7 +1847,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, { ltr_interval = p_enc_ctx->ltr_interval; p_enc_ctx->ltr_interval = -1; - ni_log(NI_LOG_DEBUG, "%s(): API set LTR interval %d\n", __func__, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set LTR interval %d\n", __func__, ltr_interval); } @@ -1855,7 +1871,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, int32_t framerate_denom = aux_framerate_ptr->framerate_denom; if ((framerate_num <= 0) || (framerate_denom <= 0)) { - ni_log(NI_LOG_ERROR, + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid framerate in aux data (%d/%d)\n", __func__, framerate_num, framerate_denom); } else @@ -1875,7 +1891,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (((framerate_num + framerate_denom - 1) / framerate_denom) > NI_MAX_FRAMERATE) { - ni_log(NI_LOG_ERROR, + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid framerate in aux data (%d/%d)\n", __func__, aux_framerate_ptr->framerate_num, aux_framerate_ptr->framerate_denom); @@ -1883,7 +1899,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, { framerate.framerate_num = framerate_num; framerate.framerate_denom = framerate_denom; - ni_log(NI_LOG_DEBUG, "%s(): frame aux data framerate (%d/%d)\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data framerate (%d/%d)\n", __func__, framerate_num, framerate_denom); } } @@ -1894,7 +1910,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, framerate = p_enc_ctx->framerate; p_enc_ctx->framerate.framerate_num = p_enc_ctx->framerate.framerate_denom = 0; - ni_log(NI_LOG_DEBUG, "%s(): API set framerate (%d/%d)\n", __func__, + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set framerate (%d/%d)\n", __func__, framerate.framerate_num, framerate.framerate_denom); } @@ -1907,6 +1923,12 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_ctx->enc_change_params->frameRateDenom = framerate.framerate_denom; p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + + // update last framerate with reconfigured framerate + p_enc_ctx->last_framerate.framerate_num = framerate.framerate_num; + p_enc_ctx->last_framerate.framerate_denom = framerate.framerate_denom; + ni_log2(p_enc_ctx, NI_LOG_INFO, "%s: framerate num %d denom %d updated for reconfig\n", + __func__, framerate.framerate_num, framerate.framerate_denom); } // prep for NetInt frame reference invalidation support: when this setting @@ -1917,7 +1939,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, if (aux_data) { frame_num = *((int32_t *)aux_data->data); - ni_log(NI_LOG_ERROR, "%s(): frame aux data frame ref invalid %d\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data frame ref invalid %d\n", __func__, frame_num); } @@ -1925,7 +1947,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, { frame_num = p_enc_ctx->ltr_frame_ref_invalid; p_enc_ctx->ltr_frame_ref_invalid = -1; - ni_log(NI_LOG_ERROR, "%s(): API set frame ref invalid %d\n", __func__, + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): API set frame ref invalid %d\n", __func__, frame_num); } @@ -1956,6 +1978,249 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, p_enc_frame->sei_total_len += p_enc_frame->preferred_characteristics_data_len; } + + // prep for NetInt maxFrameSize reconfiguration support: when maxFrameSize + // setting has been requested by both frame aux data and API, API takes priority + int32_t max_frame_size = 0; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE); + if (aux_data) + { + max_frame_size = *((int32_t *)aux_data->data); + uint32_t maxFrameSize = (uint32_t)max_frame_size / 2000; + uint32_t min_maxFrameSize; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data max_frame_size %d\n", __func__, + max_frame_size); + + if (!api_params->low_delay_mode) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is valid only when lowDelay mode is enabled\n", + __func__, max_frame_size); + max_frame_size = 0; + } + else + { + int32_t tmp_bitrate, tmp_framerate_num, tmp_framerate_denom; + tmp_bitrate = (p_enc_ctx->enc_change_params->bitRate > 0) ? p_enc_ctx->enc_change_params->bitRate : api_params->bitrate; + + if ((p_enc_ctx->enc_change_params->frameRateNum > 0) && (p_enc_ctx->enc_change_params->frameRateDenom > 0)) + { + tmp_framerate_num = p_enc_ctx->enc_change_params->frameRateNum; + tmp_framerate_denom = p_enc_ctx->enc_change_params->frameRateDenom; + } + else + { + tmp_framerate_num = (int32_t)api_params->fps_number; + tmp_framerate_denom = (int32_t)api_params->fps_denominator; + } + + min_maxFrameSize = (((uint32_t)tmp_bitrate / tmp_framerate_num * tmp_framerate_denom) / 8) / 2000; + + if (maxFrameSize < min_maxFrameSize) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is too small (invalid)\n", + __func__, max_frame_size); + max_frame_size = 0; + } + + if (max_frame_size > NI_MAX_FRAME_SIZE) { + max_frame_size = NI_MAX_FRAME_SIZE; + } + } + } + + if (p_enc_ctx->max_frame_size > 0) + { + max_frame_size = p_enc_ctx->max_frame_size; + p_enc_ctx->max_frame_size = 0; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set max_frame_size %d\n", __func__, max_frame_size); + } + + if (max_frame_size > 0) + { + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_MAX_FRAME_SIZE; + + p_enc_ctx->enc_change_params->maxFrameSize = (uint16_t)(max_frame_size / 2000); + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } + + // prep for NetInt crf reconfiguration support: when crf + // setting has been requested by both frame aux data and API, API takes priority + float crf = -1.0f; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_CRF); + if (aux_data) + { + crf = (float)(*((int32_t *)aux_data->data)); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data crf %d\n", __func__, + crf); + + if (api_params->cfg_enc_params.crf < 0) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %d is valid only in CRF mode\n", + __func__, crf); + crf = -1; + } + else + { + if (crf < 0 || crf > 51) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %d is invalid (valid range in [0..51])\n", + __func__, crf); + crf = -1; + } + } + } + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_CRF_FLOAT); + if (aux_data) + { + crf = *((float *)aux_data->data); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data crf %f\n", __func__, + crf); + + if (api_params->cfg_enc_params.crfFloat < 0) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %f is valid only in CRF mode\n", + __func__, crf); + crf = -1; + } + else + { + if (crf < 0 || crf > 51) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %f is invalid (valid range in [0..51])\n", + __func__, crf); + crf = -1; + } + } + } + + if (p_enc_ctx->reconfig_crf >= 0 || p_enc_ctx->reconfig_crf_decimal > 0) + { + crf = (float)(p_enc_ctx->reconfig_crf + + (float)p_enc_ctx->reconfig_crf_decimal / 100.0); + p_enc_ctx->reconfig_crf = -1; + p_enc_ctx->reconfig_crf_decimal = 0; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_crf %f\n", __func__, crf); + } + + if (crf >= 0) + { + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_CRF; + + p_enc_ctx->enc_change_params->crf = (uint8_t)crf; + p_enc_ctx->enc_change_params->crfDecimal = + (float)((crf - (float)p_enc_ctx->enc_change_params->crf) * 100); + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } + + int32_t vbvMaxRate = 0; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_VBV_MAX_RATE); + if (aux_data) + { + vbvMaxRate = *((int32_t *)aux_data->data); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data vbvMaxRate %d\n", __func__, + vbvMaxRate); + } + + if (p_enc_ctx->reconfig_vbv_max_rate > 0) + { + vbvMaxRate = p_enc_ctx->reconfig_vbv_max_rate; + p_enc_ctx->reconfig_vbv_max_rate = 0; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_vbv_max_rate %d\n", __func__, vbvMaxRate); + } + + if (vbvMaxRate) + { + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_VBV; + + p_enc_ctx->enc_change_params->vbvMaxRate = vbvMaxRate; + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } + + int32_t vbvBufferSize = 0; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE); + if (aux_data) + { + vbvBufferSize = *((int32_t *)aux_data->data); + if ((vbvBufferSize < 10 && vbvBufferSize != 0) || vbvBufferSize > 3000) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): invalid frame aux data vbvBufferSize %d\n", __func__, + vbvBufferSize); + vbvBufferSize = 0; + } + else + { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data vbvBufferSize %d\n", __func__, + vbvBufferSize); + } + } + + if (p_enc_ctx->reconfig_vbv_buffer_size > 0) + { + vbvBufferSize = p_enc_ctx->reconfig_vbv_buffer_size; + p_enc_ctx->reconfig_vbv_buffer_size = 0; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_vbv_max_rate %d\n", __func__, vbvBufferSize); + } + + if (vbvBufferSize) + { + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_VBV; + + p_enc_ctx->enc_change_params->vbvBufferSize = vbvBufferSize; + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } + + int16_t sliceArg = 0; + aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_SLICE_ARG); + if (aux_data) + { + sliceArg = *((int16_t *)aux_data->data); + ni_encoder_cfg_params_t *p_enc = &api_params->cfg_enc_params; + if (p_enc->slice_mode == 0) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s():not support to reconfig slice_arg when slice_mode disable.\n", + __func__); + sliceArg = 0; + } + if (NI_CODEC_FORMAT_JPEG == p_enc_ctx->codec_format || NI_CODEC_FORMAT_AV1 == p_enc_ctx->codec_format) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s():sliceArg is only supported for H.264 or H.265.\n", + __func__); + sliceArg = 0; + } + int ctu_mb_size = (NI_CODEC_FORMAT_H264 == p_enc_ctx->codec_format) ? 16 : 64; + int max_num_ctu_mb_row = (api_params->source_height + ctu_mb_size - 1) / ctu_mb_size; + if (sliceArg < 1 || sliceArg > max_num_ctu_mb_row) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): invalid frame aux data sliceArg %d\n", __func__, + sliceArg); + sliceArg = 0; + } + else + { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data sliceArg %d\n", __func__, + sliceArg); + } + } + + if (p_enc_ctx->reconfig_slice_arg > 0) + { + sliceArg = p_enc_ctx->reconfig_slice_arg; + p_enc_ctx->reconfig_slice_arg = 0; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_slice_arg %d\n", __func__, sliceArg); + } + + if (sliceArg) + { + p_enc_ctx->enc_change_params->enable_option |= + NI_SET_CHANGE_PARAM_SLICE_ARG; + + p_enc_ctx->enc_change_params->sliceArg = sliceArg; + p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t); + } } /*!***************************************************************************** @@ -1971,7 +2236,7 @@ void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, * \param[in] udu_data SEI for User data unregistered * \param[in] hdrp_data SEI for HDR10+ * \param[in] is_hwframe, must be 0 (sw frame) or 1 (hw frame) - * \param[in] is_nv12frame, must be 1 (nv12 frame) or 0 (not) + * \param[in] is_semiplanar, must be 1 (semiplanar frame) or 0 (not) * * \return NONE ******************************************************************************/ @@ -1981,27 +2246,43 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data, int is_hwframe, - int is_nv12frame) + int is_semiplanar) { ni_xcoder_params_t *api_params = (ni_xcoder_params_t *)p_enc_ctx->p_session_config; // fill in extra data (skipping meta data header) - if (is_hwframe != 0 && is_hwframe != 1 && is_nv12frame != 0 && - is_nv12frame != 1) + if (is_hwframe != 0 && is_hwframe != 1 && is_semiplanar != 0 && + is_semiplanar != 1) { - ni_log(NI_LOG_ERROR, + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ni_enc_copy_aux_data: error, illegal hwframe or nv12frame\n"); return; } + + uint32_t frame_metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE; + if (ni_cmp_fw_api_ver((char*) &p_enc_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6Q") < 0) + { + frame_metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_Q; + } + uint8_t *dst = (uint8_t *)p_enc_frame->p_data[2 + is_hwframe] + - p_enc_frame->data_len[2 + is_hwframe] + NI_APP_ENC_FRAME_META_DATA_SIZE; + p_enc_frame->data_len[2 + is_hwframe] + frame_metadata_size; if (!is_hwframe) { - dst = (uint8_t *)p_enc_frame->p_data[2 - is_nv12frame] + - p_enc_frame->data_len[2 - is_nv12frame] + - NI_APP_ENC_FRAME_META_DATA_SIZE; + dst = (uint8_t *)p_enc_frame->p_data[2 - is_semiplanar] + + p_enc_frame->data_len[2 - is_semiplanar] + + frame_metadata_size; + } + + // Separate metadata buffer (not contiguous with YUV buffer) + if (p_enc_frame->separate_metadata) + { + dst = p_enc_frame->p_metadata_buffer + frame_metadata_size; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: p_metadata_buffer %p frame_metadata_size %u dst %p\n", + p_enc_frame->p_metadata_buffer, frame_metadata_size, dst); } // fill in reconfig data if enabled; even if it's disabled, keep the space @@ -2009,8 +2290,8 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, if (p_enc_frame->reconf_len || api_params->cfg_enc_params.roi_enable || p_enc_frame->sei_total_len) { - ni_log(NI_LOG_DEBUG, "ni_enc_copy_aux_data: keep reconfig space: %" - PRId64 "\n", sizeof(ni_encoder_change_params_t)); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: keep reconfig space: %" + PRId64 " to %p\n", sizeof(ni_encoder_change_params_t), dst); memset(dst, 0, sizeof(ni_encoder_change_params_t)); @@ -2032,16 +2313,16 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, if (p_enc_frame->roi_len && p_enc_ctx->roi_map) { memcpy(dst, p_enc_ctx->roi_map, p_enc_frame->roi_len); - ni_log(NI_LOG_DEBUG, "ni_enc_copy_aux_data: ROI size: %u\n", - p_enc_frame->roi_len); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: ROI size: %u to %p\n", + p_enc_frame->roi_len, dst); } else { memset(dst, 0, p_enc_ctx->roi_len); - ni_log(NI_LOG_DEBUG, "ni_enc_copy_aux_data: zeroed ROI size: %u\n", - p_enc_ctx->roi_len); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: zeroed ROI size: %u to %p\n", + p_enc_ctx->roi_len, dst); } - + // for QUADRA, when ROI enabled, requires ROI map included in input buffer and data transferred for every frame dst += p_enc_ctx->roi_len; // reset frame ROI len to the actual map size p_enc_frame->roi_len = p_enc_ctx->roi_len; @@ -2050,8 +2331,8 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, // HDR SEI: mastering display color volume if (p_enc_frame->sei_hdr_mastering_display_color_vol_len) { - ni_log(NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI mdcv size: %u\n", - p_enc_frame->sei_hdr_mastering_display_color_vol_len); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI mdcv size: %u to %p\n", + p_enc_frame->sei_hdr_mastering_display_color_vol_len, dst); memcpy(dst, mdcv_data, p_enc_frame->sei_hdr_mastering_display_color_vol_len); dst += p_enc_frame->sei_hdr_mastering_display_color_vol_len; @@ -2060,8 +2341,8 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, // HDR SEI: content light level info if (p_enc_frame->sei_hdr_content_light_level_info_len) { - ni_log(NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI cll size: %u\n", - p_enc_frame->sei_hdr_content_light_level_info_len); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI cll size: %u to %p\n", + p_enc_frame->sei_hdr_content_light_level_info_len, dst); memcpy(dst, cll_data, p_enc_frame->sei_hdr_content_light_level_info_len); @@ -2071,6 +2352,9 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, // HLG SEI: preferred characteristics if (p_enc_frame->preferred_characteristics_data_len) { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: preferred characteristics size: %u to %p\n", + p_enc_frame->preferred_characteristics_data_len, dst); + dst[0] = dst[1] = dst[2] = 0; dst[3] = 1; if (NI_CODEC_FORMAT_H265 == codec_format) @@ -2096,9 +2380,9 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, // close caption if (p_enc_frame->sei_cc_len) { - ni_log(NI_LOG_DEBUG, "ni_enc_copy_aux_data: close caption size: %u\n", - p_enc_frame->sei_cc_len); - + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: close caption size: %u to %p\n", + p_enc_frame->sei_cc_len, dst); + memcpy(dst, cc_data, p_enc_frame->sei_cc_len); dst += p_enc_frame->sei_cc_len; } @@ -2106,6 +2390,9 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, // HDR10+ if (p_enc_frame->sei_hdr_plus_len) { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR10+ size: %u to %p\n", + p_enc_frame->sei_hdr_plus_len, dst); + memcpy(dst, hdrp_data, p_enc_frame->sei_hdr_plus_len); dst += p_enc_frame->sei_hdr_plus_len; } @@ -2113,7 +2400,881 @@ void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, // User data unregistered SEI if (p_enc_frame->sei_user_data_unreg_len) { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: UDU size: %u to %p\n", + p_enc_frame->sei_user_data_unreg_len, dst); memcpy(dst, udu_data, p_enc_frame->sei_user_data_unreg_len); //dst += p_enc_frame->sei_user_data_unreg_len; } } + +/*!***************************************************************************** + * \brief Send an input data frame to the encoder with YUV data given in + * the inputs. + * + * For ideal performance memory should be 4k aligned. If it is not 4K aligned + * then a temporary 4k aligned memory will be used to copy data to and from + * when writing and reading. This will negatively impact performance. + * + * Any metadata to be sent with the frame should be attached to p_enc_frame + * as aux data (e.g. using ni_frame_new_aux_data()). + * + * \param[in] p_ctx Encoder session context + * \param[in] p_enc_frame Struct holding information about the frame + * to be sent to the encoder + * \param[in] p_yuv_buffer Caller allocated buffer holding YUV data + * for the frame + * + * \return On success + * Total number of bytes written + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_INVALID_SESSION + *****************************************************************************/ +int ni_enc_write_from_yuv_buffer(ni_session_context_t *p_ctx, + ni_frame_t *p_enc_frame, uint8_t *p_yuv_buffer) +{ + int frame_width; + int frame_height; + bool need_copy = true; + ni_xcoder_params_t *p_param; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + bool alignment_2pass_wa = false; + int is_hwframe; + + if (!p_ctx || !p_enc_frame) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (!p_yuv_buffer) + { + // send EOS + p_enc_frame->end_of_stream = 1; + goto send_frame; + } + + if (((uintptr_t)p_yuv_buffer) % NI_MEM_PAGE_ALIGNMENT) + { + ni_log2(p_ctx, NI_LOG_INFO, "WARNING: %s passed buffer ptr %p is not 4k aligned\n", + __func__, p_yuv_buffer); + + } + + is_hwframe = p_ctx->hw_action != NI_CODEC_HW_NONE; + frame_width = p_enc_frame->video_width; + frame_height = p_enc_frame->video_height; + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + + // extra data starts with metadata header + p_enc_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; + + if (!p_enc_frame->start_of_stream && + (p_enc_frame->video_width != p_ctx->actual_video_width || + p_enc_frame->video_height != p_ctx->active_video_height || + p_enc_frame->pixel_format != p_ctx->pixel_format)) + { + ni_log2(p_ctx, NI_LOG_INFO, + "%s: resolution change %dx%d -> %dx%d " + "or pixel format change %d -> %d\n", + __func__, p_ctx->actual_video_width, p_ctx->active_video_height, + p_enc_frame->video_width, p_enc_frame->video_height, + p_ctx->pixel_format, p_enc_frame->pixel_format); + + // change run state + p_ctx->session_run_state = SESSION_RUN_STATE_SEQ_CHANGE_DRAINING; + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: session_run_state change to %d \n", __func__, + p_ctx->session_run_state); + + // send EOS + p_enc_frame->end_of_stream = 1; + goto send_frame; + } + + // ROI demo mode takes higher priority over aux data + // Note: when ROI demo modes enabled, supply ROI map for the specified range + // frames, and 0 map for others + if (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable) + { + if (p_ctx->frame_num > 90 && p_ctx->frame_num < 300) + { + p_enc_frame->roi_len = p_ctx->roi_len; + } else + { + p_enc_frame->roi_len = 0; + } + // when ROI enabled, always have a data buffer for ROI + // Note: this is handled separately from ROI through side/aux data + p_enc_frame->extra_data_len += p_ctx->roi_len; + } + + int should_send_sei_with_frame = + ni_should_send_sei_with_frame(p_ctx, PIC_TYPE_P, p_param); + + uint8_t mdcv_data[NI_MAX_SEI_DATA]; + uint8_t cll_data[NI_MAX_SEI_DATA]; + uint8_t cc_data[NI_MAX_SEI_DATA]; + uint8_t udu_data[NI_MAX_SEI_DATA]; + uint8_t hdrp_data[NI_MAX_SEI_DATA]; + + // Convert aux data attached to input frame into required format, + // and store in local arrays + ni_enc_prep_aux_data(p_ctx, p_enc_frame, p_enc_frame, p_ctx->codec_format, + should_send_sei_with_frame, mdcv_data, cll_data, + cc_data, udu_data, hdrp_data); + + p_enc_frame->extra_data_len += p_enc_frame->sei_total_len; + + // data layout requirement: leave space for reconfig data if at least one of + // reconfig, SEI or ROI is present + // Note: ROI is present when enabled, so use encode config flag instead of + // frame's roi_len as it can be 0 indicating a 0'd ROI map setting ! + if (p_enc_frame->reconf_len || p_enc_frame->sei_total_len || + (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable)) + { + p_enc_frame->extra_data_len += sizeof(ni_encoder_change_params_t); + } + + // Check whether line-by-line copy is needed + int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; + int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0}; + int is_semiplanar = !ni_get_planar_from_pixfmt(p_ctx->pixel_format); + ni_get_hw_yuv420p_dim(frame_width, frame_height, p_ctx->bit_depth_factor, + is_semiplanar, dst_stride, dst_height_aligned); + + int src_stride[NI_MAX_NUM_DATA_POINTERS]; + int src_height[NI_MAX_NUM_DATA_POINTERS]; + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS]; + + bool isrgba = (p_ctx->pixel_format == NI_PIX_FMT_ABGR || p_ctx->pixel_format == NI_PIX_FMT_ARGB + || p_ctx->pixel_format == NI_PIX_FMT_RGBA || p_ctx->pixel_format == NI_PIX_FMT_BGRA); + + // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code + src_stride[0] = frame_width * p_ctx->bit_depth_factor; + src_height[0] = frame_height; + p_src[0] = p_yuv_buffer; + + if (isrgba) + { + src_stride[1] = 0; + src_stride[2] = 0; + + src_height[1] = 0; + src_height[2] = 0; + + p_src[1] = NULL; + p_src[2] = NULL; + } + else + { + src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2; + src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2; + + src_height[1] = src_height[0] / 2; + src_height[2] = is_semiplanar ? 0 : src_height[1]; + + p_src[1] = p_src[0] + src_stride[0] * src_height[0]; + p_src[2] = p_src[1] + src_stride[1] * src_height[1]; + } + + alignment_2pass_wa = ( + (p_param->cfg_enc_params.lookAheadDepth || + p_param->cfg_enc_params.crfFloat >= 0) && + (p_ctx->codec_format == NI_CODEC_FORMAT_H265 || + p_ctx->codec_format == NI_CODEC_FORMAT_AV1)); + + if (alignment_2pass_wa && !is_hwframe) { + if (is_semiplanar) { + // for 2-pass encode output mismatch WA, need to extend (and + // pad) CbCr plane height, because 1st pass assume input 32 + // align + dst_height_aligned[1] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2; + } else { + // for 2-pass encode output mismatch WA, need to extend (and + // pad) Cr plane height, because 1st pass assume input 32 align + dst_height_aligned[2] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2; + } + } + + // check input resolution zero copy compatible or not + if (ni_encoder_frame_zerocopy_check(p_ctx, + p_param, frame_width, frame_height, + (const int *)src_stride, false) == NI_RETCODE_SUCCESS) + { + need_copy = false; + //alloc metadata buffer etc. (if needed) + retval = ni_encoder_frame_zerocopy_buffer_alloc( + p_enc_frame, frame_width, + frame_height, (const int *)src_stride, (const uint8_t **)p_src, + (int)(p_enc_frame->extra_data_len)); + if (retval != NI_RETCODE_SUCCESS) + goto end; + } + else + { + // if linesize changes (while resolution remains the same), copy to previously configured linesizes + if (p_param->luma_linesize && p_param->chroma_linesize) + { + dst_stride[0] = p_param->luma_linesize; + dst_stride[1] = p_param->chroma_linesize; + dst_stride[2] = is_semiplanar ? 0 : p_param->chroma_linesize; + } + retval = ni_encoder_sw_frame_buffer_alloc( + p_param->cfg_enc_params.planar, p_enc_frame, frame_width, + dst_height_aligned[0], dst_stride, + p_ctx->codec_format == NI_CODEC_FORMAT_H264, + (int)(p_enc_frame->extra_data_len), alignment_2pass_wa); + if (retval != NI_RETCODE_SUCCESS) + { + return retval; + } + } + + ni_log2(p_ctx, NI_LOG_TRACE, + "%s: src_stride %d dst_stride " + "%d dst_height_aligned %d src_height %d need_copy %d\n", + __func__, src_stride[0], + dst_stride[0], dst_height_aligned[0], + src_height[0], need_copy); + + if (need_copy) + { + ni_copy_hw_yuv420p((uint8_t **)(p_enc_frame->p_data), p_src, + frame_width, frame_height, p_ctx->bit_depth_factor, + is_semiplanar, + p_param->cfg_enc_params.conf_win_right, dst_stride, + dst_height_aligned, src_stride, src_height); + p_enc_frame->separate_metadata = 0; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, + "p_dst alloc linesize = %d/%d/%d src height=%d " + "dst height aligned = %d/%d/%d force_key_frame=%d, " + "extra_data_len=%u" + " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_" + "color_vol %u hdr10+ %u hrd %d) reconf_size=%u roi_size=%u " + "force_pic_qp=%u udu_sei_size=%u " + "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n", + dst_stride[0], dst_stride[1], dst_stride[2], frame_height, + dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2], + p_enc_frame->force_key_frame, p_enc_frame->extra_data_len, + p_enc_frame->sei_total_len, + p_enc_frame->sei_hdr_content_light_level_info_len, + p_enc_frame->sei_hdr_mastering_display_color_vol_len, + p_enc_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */ + p_enc_frame->reconf_len, p_enc_frame->roi_len, + p_enc_frame->force_pic_qp, p_enc_frame->sei_user_data_unreg_len, + p_enc_frame->use_cur_src_as_long_term_pic, + p_enc_frame->use_long_term_ref); + + ni_enc_copy_aux_data(p_ctx, p_enc_frame, p_enc_frame, p_ctx->codec_format, + mdcv_data, cll_data, cc_data, udu_data, hdrp_data, + 0 /*swframe*/, is_semiplanar); + +send_frame: + retval = ni_device_session_write(p_ctx, (ni_session_data_io_t *)p_enc_frame, + NI_DEVICE_TYPE_ENCODER); +end: + if (!need_copy) + { + // Don't want to accidentally free or reuse user-allocated YUV buffer, so remove from frame + p_enc_frame->p_buffer = NULL; + p_enc_frame->buffer_size = 0; + for (int i = 0; i < NI_MAX_NUM_DATA_POINTERS; i++) + { + p_enc_frame->data_len[i] = 0; + p_enc_frame->p_data[i] = NULL; + } + } + + return retval; +} + +/*!***************************************************************************** + * \brief Find the next start code + * + * \param[in] p pointer to buffer start address. + * \param[in] end pointer to buffer end address. + * \param[state] state pointer to nalu type address + * + * \return search end address + ******************************************************************************/ +const uint8_t *ni_find_start_code (const uint8_t *p, const uint8_t *end, uint32_t *state) +{ + int i; + + if (p >= end) + return end; + + for (i = 0; i < 3; i++) { + uint32_t tmp = *state << 8; + *state = tmp + *(p++); + if (tmp == 0x100 || p == end) + return p; + } + + while (p < end) { + if (p[-1] > 1) + p += 3; + else if (p[-2]) + p += 2; + else if (p[-3] | (p[-1] - 1)) + p++; + else { + p++; + break; + } + } + + p = ((p) < (end) ? (p - 4) : (end - 4)); // min + *state = + (((uint32_t) (p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]); + + return p + 4; +} + +/*!****************************************************************************** + * \brief Extract custom sei payload data from pkt_data, + * and save it to ni_packet_t + * + * \param uint8_t *pkt_data - FFMpeg AVPacket data + * \param int pkt_size - packet size + * \param long index - pkt data index of custom sei first byte after SEI type + * \param ni_packet_t *p_packet - netint internal packet + * \param uint8_t sei_type - type of SEI + * \param int vcl_found - whether got vcl in the pkt data, 1 means got + * + * \return - 0 on success, non-0 on failure + ********************************************************************************/ +int ni_extract_custom_sei(uint8_t *pkt_data, int pkt_size, long index, + ni_packet_t *p_packet, uint8_t sei_type, int vcl_found) +{ + int i, len; + uint8_t *udata; + uint8_t *sei_data; + int sei_size; + int sei_index; + ni_custom_sei_t *p_custom_sei; + + ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__); + + if (p_packet->p_custom_sei_set == NULL) + { + /* max size */ + p_packet->p_custom_sei_set = (ni_custom_sei_set_t *)malloc(sizeof(ni_custom_sei_set_t)); + if (p_packet->p_custom_sei_set == NULL) + { + ni_log(NI_LOG_ERROR, "failed to allocate all custom sei buffer.\n"); + return NI_RETCODE_ERROR_MEM_ALOC; + } + memset(p_packet->p_custom_sei_set, 0, sizeof(ni_custom_sei_set_t)); + } + + sei_index = p_packet->p_custom_sei_set->count; + p_custom_sei = &p_packet->p_custom_sei_set->custom_sei[sei_index]; + if (sei_index >= NI_MAX_CUSTOM_SEI_CNT) + { + ni_log(NI_LOG_INFO, "number of custom sei in current frame is out of limit(%d).\n", + NI_MAX_CUSTOM_SEI_CNT); + return 0; + } + sei_data = &p_custom_sei->data[0]; + + /*! extract SEI payload size. + * the first byte after SEI type is the SEI payload size. + * if the first byte is 255(0xFF), it means the SEI payload size is more than 255. + * in this case, to get the SEI payload size is to do a summation. + * the end of SEI size is the first non-0xFF value. + * for example, 0xFF 0xFF 0x08, the SEI payload size equals to (0xFF+0xFF+0x08). + */ + sei_size = 0; + while (index < pkt_size && pkt_data[index] == 0xff) + { + sei_size += pkt_data[index++]; + } + + if (index >= pkt_size) + { + ni_log(NI_LOG_INFO, "custom sei corrupted: length truncated.\n"); + return NI_RETCODE_FAILURE; + } + sei_size += pkt_data[index++]; + + if (sei_size > NI_MAX_CUSTOM_SEI_DATA) + { + ni_log(NI_LOG_INFO, "custom sei corrupted: size(%d) out of limit(%d).\n", + sei_size, NI_MAX_CUSTOM_SEI_DATA); + return 0; + } + + udata = &pkt_data[index]; + + /* set SEI payload type at the first byte */ + sei_data[0] = sei_type; + + /* extract SEI payload data + * SEI payload data in NAL is EBSP(Encapsulated Byte Sequence Payload), + * need change EBSP to RBSP(Raw Byte Sequence Payload) for exact size + */ + for (i = 0, len = 0; (i < pkt_size - index) && len < sei_size; i++, len++) + { + /* if the latest 3-byte data pattern matchs '00 00 03' which means udata[i] is an escaping byte, + * discard udata[i]. */ + if (i >= 2 && udata[i - 2] == 0 && udata[i - 1] == 0 && udata[i] == 3) + { + len--; + continue; + } + sei_data[len] = udata[i]; + } + + if (len != sei_size) + { + ni_log(NI_LOG_INFO, "custom sei corrupted: data truncated, " + "required size:%d, actual size:%d.\n", sei_size, len); + return NI_RETCODE_FAILURE; + } + + p_custom_sei->type = sei_type; + p_custom_sei->size = sei_size; + p_custom_sei->location = vcl_found ? NI_CUSTOM_SEI_LOC_AFTER_VCL : NI_CUSTOM_SEI_LOC_BEFORE_VCL; + + p_packet->p_custom_sei_set->count++; + + ni_log(NI_LOG_TRACE, "%s() exit, custom sei size=%d type=%d\n", + __FUNCTION__, sei_size, sei_type); + + return 0; +} + +/*!****************************************************************************** + * \brief Decode parse packet + * + * \param[in] p_session_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_param Pointer to a caller allocated + * ni_xcoder_params_t struct + * \param[in] *data FFMpeg AVPacket data + * \param[in] size packet size + * \param[in] p_packet Pointer to a caller allocated + * ni_packet_t struct + * \param[in] low_delay FFmpeg lowdelay + * \param[in] codec_format enum ni_codec_format_t + * \param[in] pkt_nal_bitmap pkt_nal_bitmap + * \param[in] custom_sei_type custom_sei_type + * \param[in] *svct_skip_next_packet svct_skip_next_packet int* + * \param[in] *is_lone_sei_pkt is_lone_sei_pkt int* + * + * \return - 0 on success, non-0 on failure + ********************************************************************************/ +int ni_dec_packet_parse(ni_session_context_t *p_session_ctx, ni_xcoder_params_t *p_param, + uint8_t *data, int size, ni_packet_t *p_packet, int low_delay, + int codec_format, int pkt_nal_bitmap, int custom_sei_type, + int *svct_skip_next_packet, int *is_lone_sei_pkt) +{ + int pkt_sei_alone = 1; + int vcl_found = 0; + int tmp_low_delay = + (p_session_ctx->decoder_low_delay == -1) ? 0 : low_delay; + int svct_layer = (codec_format == NI_CODEC_FORMAT_H264) ? + p_param->dec_input_params.svct_decoding_layer : + NI_INVALID_SVCT_DECODING_LAYER; + // int pkt_nal_bitmap = ni_dec_ctx->pkt_nal_bitmap; + const uint8_t *ptr = data; + const uint8_t *end = data + size; + uint32_t stc; + int nalu_type; + uint8_t sei_type = 0; + int ret = 0; + int nalu_count = 0; + ni_bitstream_reader_t br; + uint32_t temporal_id; + + if (pkt_nal_bitmap & NI_GENERATE_ALL_NAL_HEADER_BIT) + { + ni_log2(p_session_ctx, NI_LOG_TRACE, + "ni_dec_packet_parse(): already find the header of streams.\n"); + low_delay = 0; + } + + while ( + (custom_sei_type != NI_INVALID_SEI_TYPE || + p_param->dec_input_params.custom_sei_passthru != NI_INVALID_SEI_TYPE || + svct_layer != NI_INVALID_SVCT_DECODING_LAYER || tmp_low_delay || + p_param->dec_input_params.enable_all_sei_passthru) && + ptr < end) + { + stc = -1; + ptr = ni_find_start_code(ptr, end, &stc); + if (ptr == end) + { + if (0 == nalu_count) + { + pkt_sei_alone = 0; + ni_log2(p_session_ctx, NI_LOG_TRACE, "%s(): no NAL found in pkt.\n", + __FUNCTION__); + } + break; + } + nalu_count++; + + if (NI_CODEC_FORMAT_H264 == codec_format) + { + nalu_type = (int)stc & 0x1f; + + //check whether the packet is sei alone + pkt_sei_alone = (pkt_sei_alone && 6 /*H264_NAL_SEI */ == nalu_type); + + // Enable decoder low delay mode on sequence change + if (low_delay) + { + switch (nalu_type) + { + case 7 /*H264_NAL_SPS */: + pkt_nal_bitmap |= NI_NAL_SPS_BIT; + break; + case 8 /*H264_NAL_PPS */: + pkt_nal_bitmap |= NI_NAL_PPS_BIT; + break; + default: + break; + } + + if (pkt_nal_bitmap == (NI_NAL_SPS_BIT | NI_NAL_PPS_BIT)) + { + ni_log2(p_session_ctx, NI_LOG_TRACE, + "ni_dec_packet_parse(): Detect SPS, PPS and IDR, " + "enable decoder low delay mode.\n"); + p_session_ctx->decoder_low_delay = low_delay; + pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT; + low_delay = 0; + } + } + // check whether the packet contains SEI NAL after VCL units + if (6 /*H264_NAL_SEI */ == nalu_type) + { + sei_type = *ptr; + if (vcl_found || + custom_sei_type == sei_type || + p_param->dec_input_params.custom_sei_passthru == sei_type || + p_param->dec_input_params.enable_all_sei_passthru) + { + // SEI after VCL found or SEI type indicated then extract + // the SEI unit; + // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size, + // ptr + 1 - data, p_packet, + // sei_type, vcl_found); + ret = ni_extract_custom_sei(data, size, + ptr + 1 - data, p_packet, + sei_type, vcl_found); + if (ret != 0) + { + return ret; + } + } + } else if (nalu_type >= 1 /* H264_NAL_SLICE */ && + nalu_type <= 5 /* H264_NAL_IDR_SLICE */) + { + vcl_found = 1; + } else if (14 /*H264_NAL_PREFIX */ == nalu_type) + { + ni_bitstream_reader_init(&br, ptr, + 48); // 3 * 2 bytes * 8 = 48 bits + // skip some header + ni_bs_reader_skip_bits(&br, 16); + temporal_id = ni_bs_reader_get_bits(&br, 3); + if (temporal_id > svct_layer) + { + // H264_NAL_PREFIX UNIT will be sent with the last packet. + // So, the H264_NAL_PREFIX here is used for the next packet. + *svct_skip_next_packet = 1; + ni_log2(p_session_ctx, NI_LOG_TRACE, + "ni_dec_packet_parse(): temporal_id %d" + " is bigger than decoded layer %d, skip the next " + "packet\n", + temporal_id, svct_layer); + } + } + } else if (NI_CODEC_FORMAT_H265 == codec_format) + { + nalu_type = (int)(stc >> 1) & 0x3F; + + //check whether the packet is sei alone + pkt_sei_alone = (pkt_sei_alone && + (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type || + 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type)); + + // Enable decoder low delay mode on sequence change + if (low_delay) + { + switch (nalu_type) + { + case 32 /* HEVC_NAL_VPS */: + pkt_nal_bitmap |= NI_NAL_VPS_BIT; + break; + case 33 /* HEVC_NAL_SPS */: + pkt_nal_bitmap |= NI_NAL_SPS_BIT; + break; + case 34 /* HEVC_NAL_PPS */: + pkt_nal_bitmap |= NI_NAL_PPS_BIT; + break; + default: + break; + } + + if (pkt_nal_bitmap == + (NI_NAL_VPS_BIT | NI_NAL_SPS_BIT | NI_NAL_PPS_BIT)) + { + // Packets before the header is sent cannot be decoded. + // So set packet num to zero here. + ni_log2(p_session_ctx, NI_LOG_TRACE, + "ni_dec_packet_parse(): Detect VPS, SPS, PPS and " + "IDR enable decoder low delay mode.\n"); + p_session_ctx->decoder_low_delay = low_delay; + pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT; + low_delay = 0; + } + } + // check whether the packet contains SEI NAL after VCL units + if (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type || + 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type) + { + sei_type = *(ptr + 1); + if (vcl_found || + custom_sei_type == sei_type || + p_param->dec_input_params.custom_sei_passthru == sei_type || + p_param->dec_input_params.enable_all_sei_passthru) + { + // SEI after VCL found or SEI type indicated then extract + // the SEI unit; + // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size, + // ptr + 2 - data, p_packet, + // sei_type, vcl_found); + ret = ni_extract_custom_sei(data, size, ptr + 2 - data, p_packet, + sei_type, vcl_found); + if (ret != 0) + { + return ret; + } + } + } else if (nalu_type >= 0 /* HEVC_NAL_TRAIL_N */ && + nalu_type <= 31 /* HEVC_NAL_RSV_VCL31 */) + { + vcl_found = 1; + } + } else + { + ni_log2(p_session_ctx,NI_LOG_DEBUG, "%s() wrong codec %d !\n", __FUNCTION__, codec_format); + pkt_sei_alone = 0; + break; + } + } + + if (nalu_count > 0) + { + *is_lone_sei_pkt = pkt_sei_alone; + } + + return 0; +} + +/*!****************************************************************************** + * \brief Expand frame form src frame + * + * \param[in] dst Pointer to a caller allocated ni_frame_t struct + * \param[in] src Pointer to a caller allocated ni_frame_t struct + * \param[in] dst_stride int dst_stride[] + * \param[in] raw_width frame width + * \param[in] raw_height frame height + * \param[in] ni_fmt ni_pix_fmt_t type for ni pix_fmt + * \param[in] nb_planes int nb_planes + * + * \return - 0 on success, NI_RETCODE_FAILURE on failure + ********************************************************************************/ +int ni_expand_frame(ni_frame_t *dst, ni_frame_t *src, int dst_stride[], + int raw_width, int raw_height, int ni_fmt, int nb_planes) +{ + int i, j, h, tenBit = 0; + int vpad[3], hpad[3], src_height[3], src_width[3], src_stride[3]; + uint8_t *src_line, *dst_line, *sample, *dest, YUVsample; + uint16_t lastidx; + + switch (ni_fmt) + { + case NI_PIX_FMT_YUV420P: + /* width of source frame for each plane in pixels */ + src_width[0] = NIALIGN(raw_width, 2); + src_width[1] = NIALIGN(raw_width, 2) / 2; + src_width[2] = NIALIGN(raw_width, 2) / 2; + + /* height of source frame for each plane in pixels */ + src_height[0] = NIALIGN(raw_height, 2); + src_height[1] = NIALIGN(raw_height, 2) / 2; + src_height[2] = NIALIGN(raw_height, 2) / 2; + + /* stride of source frame for each plane in bytes */ + src_stride[0] = NIALIGN(src_width[0], 128); + src_stride[1] = NIALIGN(src_width[1], 128); + src_stride[2] = NIALIGN(src_width[2], 128); + + tenBit = 0; + + /* horizontal padding needed for each plane in bytes */ + hpad[0] = dst_stride[0] - src_width[0]; + hpad[1] = dst_stride[1] - src_width[1]; + hpad[2] = dst_stride[2] - src_width[2]; + + /* vertical padding needed for each plane in pixels */ + vpad[0] = NI_MIN_HEIGHT - src_height[0]; + vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1]; + vpad[2] = NI_MIN_HEIGHT / 2 - src_height[2]; + + break; + + case NI_PIX_FMT_YUV420P10LE: + /* width of source frame for each plane in pixels */ + src_width[0] = NIALIGN(raw_width, 2); + src_width[1] = NIALIGN(raw_width, 2) / 2; + src_width[2] = NIALIGN(raw_width, 2) / 2; + + /* height of source frame for each plane in pixels */ + src_height[0] = NIALIGN(raw_height, 2); + src_height[1] = NIALIGN(raw_height, 2) / 2; + src_height[2] = NIALIGN(raw_height, 2) / 2; + + /* stride of source frame for each plane in bytes */ + src_stride[0] = NIALIGN(src_width[0] * 2, 128); + src_stride[1] = NIALIGN(src_width[1] * 2, 128); + src_stride[2] = NIALIGN(src_width[2] * 2, 128); + + tenBit = 1; + + /* horizontal padding needed for each plane in bytes */ + hpad[0] = dst_stride[0] - src_width[0] * 2; + hpad[1] = dst_stride[1] - src_width[1] * 2; + hpad[2] = dst_stride[2] - src_width[2] * 2; + + /* vertical padding needed for each plane in pixels */ + vpad[0] = NI_MIN_HEIGHT - src_height[0]; + vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1]; + vpad[2] = NI_MIN_HEIGHT / 2 - src_height[2]; + + break; + + case NI_PIX_FMT_NV12: + /* width of source frame for each plane in pixels */ + src_width[0] = NIALIGN(raw_width, 2); + src_width[1] = NIALIGN(raw_width, 2); + src_width[2] = 0; + + /* height of source frame for each plane in pixels */ + src_height[0] = NIALIGN(raw_height, 2); + src_height[1] = NIALIGN(raw_height, 2) / 2; + src_height[2] = 0; + + /* stride of source frame for each plane in bytes */ + src_stride[0] = NIALIGN(src_width[0], 128); + src_stride[1] = NIALIGN(src_width[1], 128); + src_stride[2] = 0; + + tenBit = 0; + + /* horizontal padding needed for each plane in bytes */ + hpad[0] = dst_stride[0] - src_width[0]; + hpad[1] = dst_stride[1] - src_width[1]; + hpad[2] = 0; + + /* vertical padding for each plane in pixels */ + vpad[0] = NI_MIN_HEIGHT - src_height[0]; + vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1]; + vpad[2] = 0; + + break; + + case NI_PIX_FMT_P010LE: + /* width of source frame for each plane in pixels */ + src_width[0] = NIALIGN(raw_width, 2); + src_width[1] = NIALIGN(raw_width, 2); + src_width[2] = 0; + + /* height of source frame for each plane in pixels */ + src_height[0] = NIALIGN(raw_height, 2); + src_height[1] = NIALIGN(raw_height, 2) / 2; + src_height[2] = 0; + + /* stride of source frame for each plane in bytes */ + src_stride[0] = NIALIGN(src_width[0] * 2, 128); + src_stride[1] = NIALIGN(src_width[1] * 2, 128); + src_stride[2] = 0; + + tenBit = 1; + + /* horizontal padding needed for each plane in bytes */ + hpad[0] = dst_stride[0] - src_width[0] * 2; + hpad[1] = dst_stride[1] - src_width[1] * 2; + hpad[2] = 0; + + /* vertical padding for each plane in pixels */ + vpad[0] = NI_MIN_HEIGHT - src_height[0]; + vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1]; + vpad[2] = 0; + + break; + + default: + ni_log(NI_LOG_ERROR, "Invalid pixel format %d\n",ni_fmt); + return NI_RETCODE_FAILURE; + } + + for (i = 0; i < nb_planes && nb_planes < NI_MAX_NUM_DATA_POINTERS; i++) + { + dst_line = dst->p_data[i]; + src_line = src->p_data[i]; + + for (h = 0; i < 3 && h < src_height[i]; h++) + { + memcpy(dst_line, src_line, src_width[i] * (tenBit + 1)); + + /* Add horizontal padding */ + if (hpad[i]) + { + lastidx = src_width[i]; + + if (tenBit) + { + sample = &src_line[(lastidx - 1) * 2]; + dest = &dst_line[lastidx * 2]; + + /* two bytes per sample */ + for (j = 0; j < hpad[i] / 2; j++) + { + memcpy(dest, sample, 2); + dest += 2; + } + } else + { + YUVsample = dst_line[lastidx - 1]; + memset(&dst_line[lastidx], YUVsample, hpad[i]); + } + } + + src_line += src_stride[i]; + dst_line += dst_stride[i]; + } + + /* Pad the height by duplicating the last line */ + src_line = dst_line - dst_stride[i]; + + for (h = 0; h < vpad[i]; h++) + { + memcpy(dst_line, src_line, dst_stride[i]); + dst_line += dst_stride[i]; + } + } + + return 0; +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.h index 9e5ed8a1..1b602811 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_av_codec.h @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_av_codec.h -* -* \brief NETINT audio/video related utility functions -* -*******************************************************************************/ + * \file ni_av_codec.h + * + * \brief Audio/video related utility definitions + ******************************************************************************/ #pragma once @@ -37,6 +36,10 @@ extern "C" { // libxcoder API related definitions #define NI_NUM_PIXEL_ASPECT_RATIO 17 +#define NI_NAL_VPS_BIT (0x01) +#define NI_NAL_SPS_BIT (0x01 << 1) +#define NI_NAL_PPS_BIT (0x01 << 2) +#define NI_GENERATE_ALL_NAL_HEADER_BIT (0x01 << 3) static const ni_rational_t ni_h264_pixel_aspect_list[NI_NUM_PIXEL_ASPECT_RATIO] = { {0, 1}, {1, 1}, {12, 11}, {10, 11}, {16, 11}, {40, 33}, @@ -63,55 +66,57 @@ typedef enum _ni_h264_sei_type_t NI_H264_SEI_TYPE_ALTERNATIVE_TRANSFER = 147, // alternative transfer } ni_h264_sei_type_t; -// pic_struct in picture timing SEI message +/*! pic_struct in picture timing SEI message */ typedef enum _ni_h264_sei_pic_struct_t { - NI_H264_SEI_PIC_STRUCT_FRAME = 0, // 0: %frame - NI_H264_SEI_PIC_STRUCT_TOP_FIELD = 1, // 1: top field - NI_H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2, // 2: bottom field - NI_H264_SEI_PIC_STRUCT_TOP_BOTTOM = - 3, // 3: top field, bottom field, in that order - NI_H264_SEI_PIC_STRUCT_BOTTOM_TOP = - 4, // 4: bottom field, top field, in that order - NI_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = - 5, // 5: top field, bottom field, top field repeated, in that order - NI_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = - 6, // 6: bottom field, top field, bottom field repeated, in that order - NI_H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7, // 7: %frame doubling - NI_H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8 // 8: %frame tripling + NI_H264_SEI_PIC_STRUCT_FRAME = 0, //!< %frame + NI_H264_SEI_PIC_STRUCT_TOP_FIELD = 1, //!< top field + NI_H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2, //!< bottom field + NI_H264_SEI_PIC_STRUCT_TOP_BOTTOM = 3, //!< top field, bottom + //!< field, in that order + NI_H264_SEI_PIC_STRUCT_BOTTOM_TOP = 4, //!< bottom field, top + //!< field, in that order + NI_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5, //!< top field, bottom + //!< field, top field + //!< repeated, in that + //!< order + NI_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, //!< bottom field, top + //!< field, bottom field + //!< repeated, in that + //!< order + NI_H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7, //!< %frame doubling + NI_H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8 //!< %frame tripling } ni_h264_sei_pic_struct_t; -/* Chromaticity coordinates of the source primaries. - * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.1. - */ +/*! Chromaticity coordinates of the source primaries. These values match the + ones defined by ISO/IEC 23001-8_2013 § 7.1. */ typedef enum _ni_color_primaries { NI_COL_PRI_RESERVED0 = 0, - NI_COL_PRI_BT709 = - 1, //< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + NI_COL_PRI_BT709 = 1, //!< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE + //!< RP177 Annex B NI_COL_PRI_UNSPECIFIED = 2, NI_COL_PRI_RESERVED = 3, - NI_COL_PRI_BT470M = - 4, //< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) - - NI_COL_PRI_BT470BG = - 5, //< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM - NI_COL_PRI_SMPTE170M = - 6, //< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC - NI_COL_PRI_SMPTE240M = 7, //< functionally identical to above - NI_COL_PRI_FILM = 8, //< colour filters using Illuminant C - NI_COL_PRI_BT2020 = 9, //< ITU-R BT2020 - NI_COL_PRI_SMPTE428 = 10, //< SMPTE ST 428-1 (CIE 1931 XYZ) + NI_COL_PRI_BT470M = 4, //!< also FCC Title 47 Code of Federal + //!< Regulations 73.682 (a)(20) + NI_COL_PRI_BT470BG = 5, //!< also ITU-R BT601-6 625 / ITU-R BT1358 + //!< 625 / ITU-R BT1700 625 PAL & SECAM + NI_COL_PRI_SMPTE170M = 6, //!< also ITU-R BT601-6 525 / ITU-R BT1358 + //!< 525 / ITU-R BT1700 NTSC + NI_COL_PRI_SMPTE240M = 7, //!< functionally identical to above + NI_COL_PRI_FILM = 8, //!< colour filters using Illuminant C + NI_COL_PRI_BT2020 = 9, //!< ITU-R BT2020 + NI_COL_PRI_SMPTE428 = 10, //!< SMPTE ST 428-1 (CIE 1931 XYZ) NI_COL_PRI_SMPTEST428_1 = NI_COL_PRI_SMPTE428, - NI_COL_PRI_SMPTE431 = 11, //< SMPTE ST 431-2 (2011) / DCI P3 - NI_COL_PRI_SMPTE432 = 12, //< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 - NI_COL_PRI_JEDEC_P22 = 22, //< JEDEC P22 phosphors - NI_COL_PRI_NB //< Not part of ABI + NI_COL_PRI_SMPTE431 = 11, //!< SMPTE ST 431-2 (2011) / DCI P3 + NI_COL_PRI_SMPTE432 = 12, //!< SMPTE ST 432-1 (2010) / P3 D65 / Display + //!< P3 + NI_COL_PRI_JEDEC_P22 = 22, //!< JEDEC P22 phosphors + NI_COL_PRI_NB //!< Not part of ABI } ni_color_primaries_t; -/* Color Transfer Characteristic. - * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.2. - */ +/*! Color Transfer Characteristic. These values match the ones defined by + ISO/IEC 23001-8_2013 § 7.2. */ typedef enum _ni_color_transfer_characteristic { NI_COL_TRC_RESERVED0 = 0, @@ -144,10 +149,8 @@ typedef enum _ni_color_transfer_characteristic NI_COL_TRC_NB //< Not part of ABI } ni_color_transfer_characteristic_t; -/** - * YUV colorspace type. - * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.3. - */ +/*! YUV colorspace type. These values match the ones defined by ISO/IEC + 23001-8_2013 § 7.3. */ typedef enum _ni_color_space { NI_COL_SPC_RGB = @@ -177,7 +180,7 @@ typedef enum _ni_color_space NI_COL_SPC_NB //< Not part of ABI } ni_color_space_t; -// HRD parameters +/*! HRD parameters */ typedef struct _ni_hrd_params { uint32_t au_cpb_removal_delay_length_minus1; @@ -210,6 +213,9 @@ typedef struct _ni_mastering_display_metadata int has_luminance; } ni_mastering_display_metadata_t; +#define MASTERING_DISP_CHROMA_DEN 50000 //denominator value to have 0.00002 units +#define MASTERING_DISP_LUMA_DEN 10000 //denominator value to have 0.0001 units + // struct describing HDR10 Content light level typedef struct _ni_content_light_level { @@ -502,6 +508,7 @@ ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, * \param[in] udu_data SEI for User data unregistered * \param[in] hdrp_data SEI for HDR10+ * \param[in] is_hwframe, must be 0 (sw frame) or 1 (hw frame) + * \param[in] is_semiplanar, must be 1 (semiplanar frame) or 0 (not) * * \return NONE ******************************************************************************/ @@ -511,8 +518,94 @@ ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data, int is_hwframe, - int is_nv12frame); + int is_semiplanar); +/*!***************************************************************************** + * \brief Send an input data frame to the encoder with YUV data given in + * the inputs. + * + * For ideal performance memory should be 4k aligned. If it is not 4K aligned + * then a temporary 4k aligned memory will be used to copy data to and from + * when writing and reading. This will negatively impact performance. + * + * Any metadata to be sent with the frame should be attached to p_enc_frame + * as aux data (e.g. using ni_frame_new_aux_data()). + * + * \param[in] p_ctx Encoder session context + * \param[in] p_enc_frame Struct holding information about the frame + * to be sent to the encoder + * \param[in] p_yuv_buffer Caller allocated buffer holding YUV data + * for the frame + * + * \return On success + * Total number of bytes written + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_INVALID_SESSION + *****************************************************************************/ +LIB_API int ni_enc_write_from_yuv_buffer(ni_session_context_t *p_ctx, + ni_frame_t *p_enc_frame, + uint8_t *p_yuv_buffer); + +/*!****************************************************************************** + * \brief Extract custom sei payload data from pkt_data, + * and save it to ni_packet_t + * + * \param uint8_t *pkt_data - FFMpeg AVPacket data + * \param int pkt_size - packet size + * \param long index - pkt data index of custom sei first byte after SEI type + * \param ni_packet_t *p_packet - netint internal packet + * \param uint8_t sei_type - type of SEI + * \param int vcl_found - whether got vcl in the pkt data, 1 means got + * + * \return - 0 on success, non-0 on failure + ********************************************************************************/ +LIB_API int ni_extract_custom_sei(uint8_t *pkt_data, int pkt_size, long index, + ni_packet_t *p_packet, uint8_t sei_type, int vcl_found); + +/*!****************************************************************************** + * \brief Decode parse packet + * + * \param[in] p_session_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_param Pointer to a caller allocated + * ni_xcoder_params_t struct + * \param[in] *data FFMpeg AVPacket data + * \param[in] size packet size + * \param[in] p_packet Pointer to a caller allocated + * ni_packet_t struct + * \param[in] low_delay FFmpeg lowdelay + * \param[in] codec_format enum ni_codec_format_t + * \param[in] pkt_nal_bitmap pkt_nal_bitmap + * \param[in] custom_sei_type custom_sei_type + * \param[in] *svct_skip_next_packet svct_skip_next_packet int* + * \param[in] *is_lone_sei_pkt is_lone_sei_pkt int* + * + * \return - 0 on success, non-0 on failure + ********************************************************************************/ +LIB_API int ni_dec_packet_parse(ni_session_context_t *p_session_ctx, + ni_xcoder_params_t *p_param, uint8_t *data, int size, + ni_packet_t *p_packet, int low_delay, int codec_format, + int pkt_nal_bitmap, int custom_sei_type, + int *svct_skip_next_packet, int *is_lone_sei_pkt); + +/*!****************************************************************************** + * \brief Expand frame form src frame + * + * \param[in] dst Pointer to a caller allocated ni_frame_t struct + * \param[in] src Pointer to a caller allocated ni_frame_t struct + * \param[in] dst_stride int dst_stride[] + * \param[in] raw_width frame width + * \param[in] raw_height frame height + * \param[in] ni_fmt ni_pix_fmt_t type for ni pix_fmt + * \param[in] nb_planes int nb_planes + * + * \return - 0 on success, NI_RETCODE_FAILURE on failure + ********************************************************************************/ +LIB_API int ni_expand_frame(ni_frame_t *dst, ni_frame_t *src, int dst_stride[], + int raw_width, int raw_height, int ni_fmt, int nb_planes); #ifdef __cplusplus } #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.c index e1a8928e..7380406e 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.c @@ -31,11 +31,10 @@ ****************************************************************************/ /*!***************************************************************************** -* \file ni_bitstream.c -* -* \brief Utility functions to operate on bits in a bitstream -* -*******************************************************************************/ + * \file ni_bitstream.c + * + * \brief Utility definitions to operate on bits in a bitstream + ******************************************************************************/ #include #include @@ -211,7 +210,7 @@ void ni_bs_writer_put(ni_bitstream_writer_t *stream, uint32_t data, } /*!***************************************************************************** - * \brief write unsigned Exp-Golomb bit string to bitstream + * \brief write unsigned Exp-Golomb bit string to bitstream, 2^32-2 at most. * * \param stream bitstream * \param data input data @@ -225,7 +224,23 @@ void ni_bs_writer_put_ue(ni_bitstream_writer_t *stream, uint32_t data) unsigned num_bits = data_log2 * 2 + 1; unsigned value = prefix | suffix; - ni_bs_writer_put(stream, value, num_bits); + if (data > 0xFFFFFFFE) // 2^32-2 at most + { + ni_log(NI_LOG_ERROR, "%s error: data overflow: %u\n", __func__, + data); + return; + } + + if (num_bits <= 32) + { + ni_bs_writer_put(stream, value, num_bits); + } + else + { + // big endian + ni_bs_writer_put(stream, 0, num_bits - 32); // high (num_bits - 32) bits + ni_bs_writer_put(stream, value, 32); // low 32 bits + } } /*!***************************************************************************** @@ -235,7 +250,7 @@ void ni_bs_writer_put_ue(ni_bitstream_writer_t *stream, uint32_t data) * \param data input data * \return none ******************************************************************************/ -void ni_bitstream_put_se(ni_bitstream_writer_t *stream, int32_t data) +void ni_bs_writer_put_se(ni_bitstream_writer_t *stream, int32_t data) { // map positive value to even and negative to odd value uint32_t data_num = data <= 0 ? (-data) << 1 : (data << 1) - 1; diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.h index c88eb189..aa3b2789 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_bitstream.h @@ -31,11 +31,10 @@ ****************************************************************************/ /*!***************************************************************************** -* \file ni_bitstream.h -* -* \brief Utility functions to operate on bits in a bitstream -* -*******************************************************************************/ + * \file ni_bitstream.h + * + * \brief Utility definitions to operate on bits in a bitstream + ******************************************************************************/ #pragma once @@ -101,7 +100,7 @@ uint64_t ni_bs_writer_tell(const ni_bitstream_writer_t *const stream); void ni_bs_writer_put(ni_bitstream_writer_t *stream, uint32_t data, uint8_t bits); -// write unsigned/signed Exp-Golomb bit string to bitstream +// write unsigned/signed Exp-Golomb bit string to bitstream, 2^32-2 at most void ni_bs_writer_put_ue(ni_bitstream_writer_t *stream, uint32_t data); void ni_bs_writer_put_se(ni_bitstream_writer_t *stream, int32_t data); diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_defs.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_defs.h index 69a08ad0..3735b65a 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_defs.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_defs.h @@ -23,7 +23,6 @@ * \file ni_defs.h * * \brief Common NETINT definitions used by all modules -* *******************************************************************************/ #pragma once @@ -59,6 +58,12 @@ extern "C" { #endif +#if defined(__GNUC__) || defined(__clang__) +# define NI_UNUSED __attribute__((unused)) +#else +# define NI_UNUSED +#endif + #if !defined(NI_WARN_AS_ERROR) && !defined(__clang__) && defined(__GNUC__) #define NI_DEPRECATED __attribute__((deprecated)) #define NI_DEPRECATED_MACRO \ @@ -79,21 +84,20 @@ extern "C" // read correct version numbers if updating libxcoder but not linked apps. // NI_XCODER_REVISION[0:2] = SW release version // NI_XCODER_REVISION[3] = compatible FW API semantic major version -// NI_XCODER_REVISION[4] = compatible FW API semantic minor version -// NI_XCODER_REVISION[5:7] = optional -// reference: https://netint.atlassian.net/l/c/woqFMHES -#define NI_XCODER_REVISION "40064rcB" +// NI_XCODER_REVISION[4:5] = compatible FW API semantic minor version +// NI_XCODER_REVISION[6:7] = optional +// The definition macro in ni_quadra_filter_api.h need to be synchronized with libxcoder +#define NI_XCODER_REVISION "4926rbr2" #define NI_XCODER_REVISION_API_MAJOR_VER_IDX 3 #define NI_XCODER_REVISION_API_MINOR_VER_IDX 4 // LIBXCODER_API_VERSION can be read to determine libxcoder to linked apps/APIs // compatibility. Recommend using ni_get_*_ver() functions in ni_util.h to // read correct version numbers if updating libxcoder but not linked apps. -// reference: https://netint.atlassian.net/l/c/fVEGmYEZ #define MACRO_TO_STR(s) #s #define MACROS_TO_VER_STR(a, b) MACRO_TO_STR(a.b) #define LIBXCODER_API_VERSION_MAJOR 2 // Libxcoder API semantic major version -#define LIBXCODER_API_VERSION_MINOR 4 // Libxcoder API semantic minor version +#define LIBXCODER_API_VERSION_MINOR 63 // Libxcoder API semantic minor version #define LIBXCODER_API_VERSION MACROS_TO_VER_STR(LIBXCODER_API_VERSION_MAJOR, \ LIBXCODER_API_VERSION_MINOR) @@ -206,18 +210,27 @@ typedef int32_t ni_lock_handle_t; #define NI_MAX_DEVICE_CNT 128 #define NI_MAX_DEVICE_NAME_LEN 32 +#define NI_NVME_PREFIX "nvme" #define NI_MAX_PACKET_SZ 0x20000 #define NI_POLL_INTERVAL (2 * 1000) +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_NUM_DATA_POINTERS in ni_quadra_filter_api.h #define NI_MAX_NUM_DATA_POINTERS 4 +#define NI_MAX_NUM_SW_FRAME_DATA_POINTERS 3 + #define NI_MAX_CONTEXTS_PER_HW_INSTANCE 128 #define NI_MAX_4K_FPS_QUADRA 240 #define NI_MAX_DEVICES_PER_HW_INSTANCE 4 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_NUM_OF_DECODER_OUTPUTS in ni_quadra_filter_api.h #define NI_MAX_NUM_OF_DECODER_OUTPUTS 3 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_PPU_PARAM_EXPR_CHAR in ni_quadra_filter_api.h #define NI_MAX_PPU_PARAM_EXPR_CHAR 20 #define NI_MAX_TX_SZ 0xA00000 @@ -225,25 +238,37 @@ typedef int32_t ni_lock_handle_t; #define NI_MEM_PAGE_ALIGNMENT 0x1000 #define NI_MAX_DR_HWDESC_FRAME_INDEX 5363 +#define NI_MAX_DR_HWDESC_FRAME_INDEX_2 4993 // If P2P area changes in firmware these constants must be updated #define NI_MIN_HWDESC_P2P_BUF_ID 5364 #define NI_MAX_HWDESC_P2P_BUF_ID 5525 #define NI_MAX_SR_HWDESC_FRAME_INDEX 2457 +#define NI_MAX_SR_HWDESC_FRAME_INDEX_2 2287 +#define NI_MAX_SR_HWDESC_FRAME_INDEX_3_REMOVE_P2P 2439 +#define NI_MAX_SR_HWDESC_FRAME_INDEX_4_4G 1248 + // If P2P area changes in firmware these constants must be updated #define NI_MIN_SR_HWDESC_P2P_BUF_ID 2458 #define NI_MAX_SR_HWDESC_P2P_BUF_ID 2619 +#define NI_MAX_SR_HWDESC_P2P_BUF_ID_4G 2458 //Feed this ni_session_context_t->ddr_config -#define NI_GET_MIN_HWDESC_P2P_BUF_ID(x) (x==1?NI_MIN_SR_HWDESC_P2P_BUF_ID:NI_MIN_HWDESC_P2P_BUF_ID) -#define NI_GET_MAX_HWDESC_P2P_BUF_ID(x) (x==1?NI_MAX_SR_HWDESC_P2P_BUF_ID:NI_MAX_HWDESC_P2P_BUF_ID) +#define NI_GET_MIN_HWDESC_P2P_BUF_ID(x) ((x==1 || x==3 || x==6)?NI_MIN_SR_HWDESC_P2P_BUF_ID:NI_MIN_HWDESC_P2P_BUF_ID) +#define NI_GET_MAX_HWDESC_P2P_BUF_ID(x) ((x==1 || x==3 || x==6)?((x==6)?NI_MAX_SR_HWDESC_P2P_BUF_ID_4G:NI_MAX_SR_HWDESC_P2P_BUF_ID):NI_MAX_HWDESC_P2P_BUF_ID) //use NI_MAX_DR_HWDESC_FRAME_INDEX or NI_GET_MAX_HWDESC_FRAME_INDEX -NI_DEPRECATE_MACRO(NI_MAX_HWDESC_FRAME_INDEX) +NI_DEPRECATE_MACRO(NI_MAX_HWDESC_FRAME_INDEX) #define NI_MAX_HWDESC_FRAME_INDEX NI_DEPRECATED_MACRO NI_MAX_DR_HWDESC_FRAME_INDEX //input param is DDR config of target device -#define NI_GET_MAX_HWDESC_FRAME_INDEX(x) (x==1?NI_MAX_SR_HWDESC_FRAME_INDEX:NI_MAX_DR_HWDESC_FRAME_INDEX) +#define NI_GET_MAX_HWDESC_FRAME_INDEX(x) \ + (x == 1 ? NI_MAX_SR_HWDESC_FRAME_INDEX: \ + (x == 2 ? NI_MAX_DR_HWDESC_FRAME_INDEX: \ + (x == 3 ? NI_MAX_SR_HWDESC_FRAME_INDEX_2: \ + (x == 4 ? NI_MAX_DR_HWDESC_FRAME_INDEX_2: \ + (x == 5 ? NI_MAX_SR_HWDESC_FRAME_INDEX_3_REMOVE_P2P: \ + NI_MAX_SR_HWDESC_FRAME_INDEX_4_4G))))) #define NI_MAX_UPLOAD_INSTANCE_FRAMEPOOL 100 @@ -262,17 +287,19 @@ NI_DEPRECATE_MACRO(NI_MAX_HWDESC_FRAME_INDEX) #define NI_INVALID_SEI_TYPE (-1) // max count of custom sei per packet -#define NI_MAX_CUSTOM_SEI_CNT 10 +#define NI_MAX_CUSTOM_SEI_CNT 20 //bytes size of meta data sent together with YUV: from f/w decoder to app #define NI_FW_META_DATA_SZ 104 //metadataDecFrame on dec FW (including hwdesc x3) // size of meta data sent together with YUV data: from app to f/w encoder -#define NI_APP_ENC_FRAME_META_DATA_SIZE 56 -// size of meta data sent together with bitstream: from f/w encoder to app -#define NI_FW_ENC_BITSTREAM_META_DATA_SIZE 32 //might need to edit for yuvbypass quadra +#define NI_APP_ENC_FRAME_META_DATA_SIZE 64 + +#define NI_APP_ENC_FRAME_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_Q 56 #define MAX_AV1_ENCODER_GOP_NUM 8 +#define NI_MAX_FILTER_POOL_SIZE 4 + #if defined(LRETURN) #undef LRETURN #define LRETURN goto end @@ -292,7 +319,7 @@ typedef enum _ni_xcoder_prod_line NI_XCODER_QUADRA = 2, } ni_xcoder_prod_line_t; -inline int is_supported_xcoder(int x) +static inline int is_supported_xcoder(int x) { return (NI_XCODER_QUADRA == x); } @@ -314,163 +341,251 @@ inline int is_supported_xcoder(int x) NI_DEVICE_TYPE_MAX = 5, } ni_device_type_t; +// CPU Log definitions +#define CPU_LOG_BUFFER_SIZE (1 * 1024 * 1024) +#define TOTAL_CPU_LOG_BUFFER_SIZE \ + (CPU_LOG_BUFFER_SIZE * 5) // g_np/tp/fp/ep/dp_cpu_log_buffer +#define CPU_LOG_CYCLES_PER_CHECK (10000) +typedef enum +{ + ALL_CORE = 0x00, + NVME_CORE = 0x01, + EP_CORE = 0x02, + DP_CORE = 0x03, + TP_CORE = 0x04, + FP_CORE = 0x05, + NUM_OF_CORES = 0x06, +} ni_core_type_t; + +typedef struct _ni_session_statistic_t +{ + uint32_t ui32WrBufAvailSize; // instance write buffer size available + uint32_t ui32RdBufAvailSize; // instance read buffer size available + + uint32_t ui32FramesInput; + uint32_t ui32FramesBuffered; + uint32_t ui32FramesCompleted; + uint32_t ui32FramesOutput; + uint32_t ui32FramesDropped; + uint32_t ui32InstErrors; + + uint16_t ui16SessionId; + uint16_t ui16ErrorCount; + uint32_t ui32LastTransactionId; + uint32_t ui32LastTransactionCompletionStatus; + uint32_t ui32LastErrorTransactionId; + uint32_t ui32LastErrorStatus; + uint32_t ui32Session_timestamp_high; + uint32_t ui32Session_timestamp_low; + uint32_t reserved; + + uint8_t ui8AdditionalFramesDelay; + uint8_t ui8Reserved[3]; + uint32_t ui32Reserved[7]; +} ni_session_statistic_t; + #define IS_XCODER_DEVICE_TYPE(t) \ - (t > NI_DEVICE_TYPE_MIN && t < NI_DEVICE_TYPE_XCODER_MAX) + ((ni_device_type_t)t > NI_DEVICE_TYPE_MIN && \ + (ni_device_type_t)t < NI_DEVICE_TYPE_XCODER_MAX) #define GET_XCODER_DEVICE_TYPE(t) \ - (t == NI_DEVICE_TYPE_UPLOAD ? NI_DEVICE_TYPE_ENCODER : t) - - static const char *device_type_str[] = {"decoder", "encoder", "scaler", "AI"}; - static const char device_type_chr[] = {'d', 'e', 's', 'a'}; - - typedef enum - { - NI_RETCODE_SUCCESS = 0, /*!!< successful return code */ - NI_RETCODE_FAILURE = -1, /*!!< unrecoverable failure */ - NI_RETCODE_INVALID_PARAM = - -2, /*!!< invalid/uninitialized/null pointer parameter encountered */ - NI_RETCODE_ERROR_MEM_ALOC = -3, /*!!< memory allocation failure */ - NI_RETCODE_ERROR_NVME_CMD_FAILED = -4, /*!!< nvme command failure */ - NI_RETCODE_ERROR_INVALID_SESSION = -5, /*!!< invalid session */ - NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE = - -6, /*!!< resource currently unavailable */ - NI_RETCODE_PARAM_INVALID_NAME = -7, /*!!< invalid parameter name */ - NI_RETCODE_PARAM_INVALID_VALUE = -8, /*!!< invalid parameter value */ - NI_RETCODE_PARAM_ERROR_FRATE = - -9, /*!!< invalid frame rate parameter value */ - NI_RETCODE_PARAM_ERROR_BRATE = - -10, /*!!< invalid bit rate parameter value */ - NI_RETCODE_PARAM_ERROR_TRATE = - -11, /*!!< invalid bit rate parameter value */ - NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE = -12, - NI_RETCODE_PARAM_ERROR_INTRA_PERIOD = - -13, /*!!< invalid intra period parameter value */ - NI_RETCODE_PARAM_ERROR_INTRA_QP = -14, /*!!< invalid qp parameter value */ - NI_RETCODE_PARAM_ERROR_GOP_PRESET = - -15, /*!!< invalid got preset parameter value */ - NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE = -16, - NI_RETCODE_PARAM_ERROR_MX_NUM_MERGE = -17, - NI_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN = -18, - NI_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN = -19, - NI_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN = -20, - NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN = - -21, /*!!< invalid cu level rate control parameter value */ - NI_RETCODE_PARAM_ERROR_HVS_QP_EN = -22, - NI_RETCODE_PARAM_ERROR_HVS_QP_SCL = -23, - NI_RETCODE_PARAM_ERROR_MN_QP = - -24, /*!!< invalid minimum qp parameter value */ - NI_RETCODE_PARAM_ERROR_MX_QP = - -25, /*!!< invalid maximum qp parameter value */ - NI_RETCODE_PARAM_ERROR_MX_DELTA_QP = - -26, /*!!< invalid maximum delta qp parameter value */ - NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP = - -27, /*!!< invalid top offset of conformance window parameter value */ - NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT = - -28, /*!!< invalid bottom offset of conformance window parameter value */ - NI_RETCODE_PARAM_ERROR_CONF_WIN_L = - -29, /*!!< invalid left offset of conformance window parameter value */ - NI_RETCODE_PARAM_ERROR_CONF_WIN_R = - -30, /*!!< invalid right offset of conformance window parameter value */ - NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM = - -31, /*!!< invalid user recommended parameter value */ - NI_RETCODE_PARAM_ERROR_BRATE_LT_TRATE = -32, - NI_RETCODE_PARAM_ERROR_RCENABLE = -33, - NI_RETCODE_PARAM_ERROR_MAXNUMMERGE = -34, - NI_RETCODE_PARAM_ERROR_CUSTOM_GOP = - -35, /*!!< invalid custom gop preset parameter value */ - NI_RETCODE_PARAM_ERROR_PIC_WIDTH = - -36, /*!!< invalid picture width parameter value */ - NI_RETCODE_PARAM_ERROR_PIC_HEIGHT = - -37, /*!!< invalid picture height parameter value */ - NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE = - -38, /*!!< invalid decoding refresh type parameter value */ - NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN = -39, - NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN = -40, - NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN = -41, - NI_RETCODE_PARAM_ERROR_TOO_BIG = -42, /*!!< parameter value is too big */ - NI_RETCODE_PARAM_ERROR_TOO_SMALL = - -43, /*!!< parameter value is too small */ - NI_RETCODE_PARAM_ERROR_ZERO = -44, /*!!< parameter value is zero */ - NI_RETCODE_PARAM_ERROR_OOR = -45, /*!!< parameter value is out of range */ - NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG = - -46, /*!!< parameter width value is too big */ - NI_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL = - -47, /*!!< parameter width value is too small */ - NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG = - -48, /*!!< parameter height value is too big */ - NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL = - -49, /*!!< parameter height value is too small */ - NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG = - -50, /*!!< parameter heightxwidth value is too big */ - NI_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS = - -51, /*!!< exceeding the max number of 64 sessions */ - NI_RETCODE_ERROR_GET_DEVICE_POOL = - -52, /*!!< cannot get info from device */ - NI_RETCODE_ERROR_LOCK_DOWN_DEVICE = - -53, /*!!< cannot obtain the file lock across all the process for query */ - NI_RETCODE_ERROR_UNLOCK_DEVICE = -54, /*!!< cannot unlock the lock */ - NI_RETCODE_ERROR_OPEN_DEVICE = -55, /*!!< cannot open the device */ - NI_RETCODE_ERROR_INVALID_HANDLE = - -56, /*!!< the handles that passed in is wrong */ - NI_RETCODE_ERROR_INVALID_ALLOCATION_METHOD = - -57, /*!!< the handles that passed in is wrong */ - NI_RETCODE_ERROR_VPU_RECOVERY = -58, /*!!< VPU in recovery mode */ - NI_RETCODE_PARAM_WARNING_DEPRECATED = -59, - NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH = - -60, /*!!< invalid lookahead depth */ - NI_RETCODE_PARAM_ERROR_FILLER = -61, - NI_RETCODE_PARAM_ERROR_PICSKIP = -62, - NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION = -63, - - NI_RETCODE_PARAM_WARN = - 0x100, /*!! +#else #include "ni_p2p_ioctl.h" #endif @@ -78,6 +78,14 @@ const char *const g_xcoder_log_names[NI_XCODER_LOG_NAMES_ARRAY_LEN] = { 0}; #if __linux__ || __APPLE__ static struct stat g_nvme_stat = { 0 }; + +static int close_fd_zero_atexit = 0; + +static void close_fd_zero(void) +{ + close(0); +} + #endif /*!***************************************************************************** @@ -99,6 +107,8 @@ ni_session_context_t *ni_device_session_context_alloc_init(void) __func__); } else { + memset(p_ctx, 0, sizeof(ni_session_context_t)); + if (ni_device_session_context_init(p_ctx) != NI_RETCODE_SUCCESS) { ni_log(NI_LOG_ERROR, "ERROR: %s() Failed to init session context\n", @@ -128,8 +138,7 @@ void ni_device_session_context_free(ni_session_context_t *p_ctx) ni_lat_meas_q_destroy(p_ctx->frame_time_q); } #endif - // cppcheck-suppress uselessAssignmentPtrArg - ni_aligned_free(p_ctx); + free(p_ctx); } } @@ -146,20 +155,55 @@ void ni_device_session_context_free(ni_session_context_t *p_ctx) ******************************************************************************/ ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx) { + int bitrate = 0; + int framerate_num = 0; + int framerate_denom = 0; + if (!p_ctx) { return NI_RETCODE_INVALID_PARAM; } + if (p_ctx->session_run_state == SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) + { + // session context will reset so save the last values for sequence change + bitrate = p_ctx->last_bitrate; + framerate_num = p_ctx->last_framerate.framerate_num; + framerate_denom = p_ctx->last_framerate.framerate_denom; + } + memset(p_ctx, 0, sizeof(ni_session_context_t)); + p_ctx->last_bitrate = bitrate; + p_ctx->last_framerate.framerate_num = framerate_num; + p_ctx->last_framerate.framerate_denom = framerate_denom; + // Xcoder thread mutex init - if (!ni_pthread_mutex_alloc_and_init(&p_ctx->xcoder_mutex)) + if (ni_pthread_mutex_init(&p_ctx->mutex)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): init xcoder_mutex fail, return\n", + __func__); + return NI_RETCODE_FAILURE; + } + p_ctx->pext_mutex = &p_ctx->mutex; //used exclusively for hwdl + + // low delay send/recv sync init + if (ni_pthread_mutex_init(&p_ctx->low_delay_sync_mutex)) { - ni_log(NI_LOG_ERROR, "ERROR %s(): init xcoder_mutex fail, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): init xcoder_low_delay_sync_mutex fail return\n", __func__); return NI_RETCODE_FAILURE; } + if (ni_pthread_cond_init(&p_ctx->low_delay_sync_cond, NULL)) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): init xcoder_low_delay_sync_cond fail return\n", + __func__); + return NI_RETCODE_FAILURE; + } + + p_ctx->mutex_initialized = true; // Init the max IO size to be invalid p_ctx->max_nvme_io_size = NI_INVALID_IO_SIZE; @@ -174,6 +218,13 @@ ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx) p_ctx->keep_alive_thread = (ni_pthread_t){0}; p_ctx->keep_alive_timeout = NI_DEFAULT_KEEP_ALIVE_TIMEOUT; p_ctx->decoder_low_delay = 0; + p_ctx->enable_low_delay_check = 0; + p_ctx->low_delay_sync_flag = 0; + p_ctx->async_mode = 0; + p_ctx->pixel_format = NI_PIX_FMT_YUV420P; + // by default, select the least model load card + strncpy(p_ctx->dev_xcoder_name, NI_BEST_MODEL_LOAD_STR, + MAX_CHAR_IN_DEVICE_NAME); #ifdef MY_SAVE p_ctx->debug_write_ptr = NULL; p_ctx->debug_write_index_ptr = NULL; @@ -182,8 +233,8 @@ ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx) #ifdef MEASURE_LATENCY p_ctx->frame_time_q = (void *)ni_lat_meas_q_create(2000); - p_ctx->prev_read_frame_time = 0; #endif + return NI_RETCODE_SUCCESS; } @@ -196,7 +247,13 @@ ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx) ******************************************************************************/ void ni_device_session_context_clear(ni_session_context_t *p_ctx) { - ni_pthread_mutex_free_and_destroy(&p_ctx->xcoder_mutex); + if(p_ctx->mutex_initialized) + { + p_ctx->mutex_initialized = false; + ni_pthread_mutex_destroy(&p_ctx->mutex); + ni_pthread_mutex_destroy(&p_ctx->low_delay_sync_mutex); + ni_pthread_cond_destroy(&p_ctx->low_delay_sync_cond); + } } /*!***************************************************************************** @@ -205,7 +262,7 @@ void ni_device_session_context_clear(ni_session_context_t *p_ctx) * \return On success returns a event handle * On failure returns NI_INVALID_EVENT_HANDLE ******************************************************************************/ -ni_event_handle_t ni_create_event() +ni_event_handle_t ni_create_event(void) { #ifdef _WIN32 ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; @@ -293,7 +350,8 @@ void ni_close_event(ni_event_handle_t event_handle) * \brief Open device and return device device_handle if successful * * \param[in] p_dev Device name represented as c string. ex: "/dev/nvme0" - * \param[out] p_max_io_size_out Maximum IO Transfer size supported + * \param[out] p_max_io_size_out Maximum IO Transfer size supported, could be + * NULL * * \return On success returns a device device_handle * On failure returns NI_INVALID_DEVICE_HANDLE @@ -304,13 +362,13 @@ ni_device_handle_t ni_device_open(const char * p_dev, uint32_t * p_max_io_size_o DWORD retval; HANDLE device_handle; - if (!p_dev || !p_max_io_size_out) + if (!p_dev) { ni_log(NI_LOG_ERROR, "ERROR: passed parameters are null!, return\n"); return NI_INVALID_DEVICE_HANDLE; } - if (*p_max_io_size_out == NI_INVALID_IO_SIZE) + if (p_max_io_size_out != NULL && *p_max_io_size_out == NI_INVALID_IO_SIZE) { // For now, we just use it to allocate p_leftover buffer // NI_MAX_PACKET_SZ is big enough @@ -328,7 +386,7 @@ ni_device_handle_t ni_device_open(const char * p_dev, uint32_t * p_max_io_size_o ni_log(NI_LOG_ERROR, "Failed to open %s, retval %d \n", p_dev, retval); } else { - ni_log(NI_LOG_ERROR, "Found NVME Controller at %s \n", p_dev); + ni_log(NI_LOG_DEBUG, "Found NVME Controller at %s \n", p_dev); } return device_handle; @@ -336,13 +394,13 @@ ni_device_handle_t ni_device_open(const char * p_dev, uint32_t * p_max_io_size_o int retval = -1; ni_device_handle_t fd = NI_INVALID_DEVICE_HANDLE; - if (!p_dev || !p_max_io_size_out) + if (!p_dev) { ni_log(NI_LOG_ERROR, "ERROR: passed parameters are null!, return\n"); return NI_RETCODE_INVALID_PARAM; } - if (*p_max_io_size_out == NI_INVALID_IO_SIZE) + if (p_max_io_size_out != NULL && *p_max_io_size_out == NI_INVALID_IO_SIZE) { #if __linux__ *p_max_io_size_out = ni_get_kernel_max_io_size(p_dev); @@ -364,10 +422,32 @@ ni_device_handle_t ni_device_open(const char * p_dev, uint32_t * p_max_io_size_o if (fd < 0) { - ni_log(NI_LOG_ERROR, "ERROR: open() failed on %s\n", p_dev); - ni_log(NI_LOG_ERROR, "ERROR: %s() failed!\n", __func__); - fd = NI_INVALID_DEVICE_HANDLE; - LRETURN; + ni_log(NI_LOG_ERROR, "ERROR: %d %s open() failed on %s\n", NI_ERRNO, + strerror(NI_ERRNO), p_dev); + ni_log(NI_LOG_ERROR, "ERROR: %s() failed!\n", __func__); + fd = NI_INVALID_DEVICE_HANDLE; + LRETURN; + } + else if(fd == 0) + { + //this code is just for the case that we do not initialize all fds to NI_INVALID_DEVICE_HANDLE + + //if we make sure that all the fds in libxcoder is initialized to NI_INVALID_DEVICE_HANDLE + //we should remove this check + + //we hold the fd = 0, so other threads could not visit these code + //thread safe unless other thread close fd=0 accidently + ni_log(NI_LOG_ERROR, "open fd = 0 is not as expeceted\n"); + if(close_fd_zero_atexit == 0) + { + close_fd_zero_atexit = 1; + atexit(close_fd_zero); + } + else + { + ni_log(NI_LOG_ERROR, "libxcoder has held the fd=0, but open fd=0 again, maybe fd=0 was closed accidently."); + } + fd = NI_INVALID_DEVICE_HANDLE; } #if __APPLE__ @@ -428,6 +508,16 @@ void ni_device_close(ni_device_handle_t device_handle) return; } + if(device_handle == 0) + { + //this code is just for the case that we do not initialize all fds to NI_INVALID_DEVICE_HANDLE + + //if we make sure that all the fds in libxcoder is initialized to NI_INVALID_DEVICE_HANDLE + //we should remove this check + ni_log(NI_LOG_ERROR, "%s close fd=0 is not as expected", __func__); + return; + } + ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); #ifdef _WIN32 @@ -449,14 +539,14 @@ void ni_device_close(ni_device_handle_t device_handle) } #else int err = 0; - ni_log(NI_LOG_DEBUG, "%s(): closing %d\n", __func__, device_handle); + ni_log(NI_LOG_DEBUG, "%s(): closing fd %d\n", __func__, device_handle); err = close(device_handle); - if (err) + if (err == -1) { char error_message[100] = {'\0'}; char unknown_error_message[20] = {'\0'}; sprintf(error_message, "ERROR: %s(): ", __func__); - switch (err) + switch (errno) { case EBADF: strcat(error_message, "EBADF\n"); @@ -471,6 +561,7 @@ void ni_device_close(ni_device_handle_t device_handle) sprintf(unknown_error_message, "Unknown error %d\n", err); strcat(error_message, unknown_error_message); } + ni_log(NI_LOG_ERROR, "%s\n", strerror(errno)); ni_log(NI_LOG_ERROR, "%s\n", error_message); } #endif @@ -492,7 +583,6 @@ void ni_device_close(ni_device_handle_t device_handle) ******************************************************************************/ ni_retcode_t ni_device_capability_query(ni_device_handle_t device_handle, ni_device_capability_t* p_cap) { - ni_nvme_result_t nvme_result = 0; void * p_buffer = NULL; ni_retcode_t retval = NI_RETCODE_SUCCESS; ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; @@ -558,18 +648,17 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, { ni_retcode_t retval = NI_RETCODE_SUCCESS; ni_device_pool_t *p_device_pool = NULL; - ni_nvme_result_t nvme_result = {0}; ni_device_context_t *p_device_context = NULL; ni_device_info_t *p_dev_info = NULL; - ni_session_context_t p_session_context = {0}; ni_device_info_t dev_info = { 0 }; /*! resource management context */ ni_device_context_t *rsrc_ctx = NULL; int i = 0; int rc = 0; int num_coders = 0; - int least_model_load = 0; - int least_instance = 0; + bool use_model_load = true; + int least_load = 0; + int curr_load = 0; int guid = -1; uint32_t num_sw_instances = 0; int user_handles = false; @@ -578,21 +667,32 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, ni_device_handle_t handle1 = NI_INVALID_DEVICE_HANDLE; // For none nvme block device we just need to pass in dummy uint32_t dummy_io_size = 0; + ni_session_context_t p_session_context = {0}; ni_device_type_t query_type = device_type; if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); +#ifdef _WIN32 + if (!IsUserAnAdmin()) + { + ni_log(NI_LOG_ERROR, "ERROR: %s must be in admin priviledge\n", __func__); + return NI_RETCODE_ERROR_PERMISSION_DENIED; + } +#endif + + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_OPEN_STATE; + ni_device_session_context_init(&p_session_context); + if (NI_INVALID_SESSION_ID != p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR: trying to overwrite existing session, " + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: trying to overwrite existing session, " "device_type %d, session id %d\n", device_type, p_ctx->session_id); retval = NI_RETCODE_INVALID_PARAM; @@ -605,6 +705,9 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, p_ctx->roi_side_data_size = p_ctx->nb_rois = 0; p_ctx->av_rois = NULL; p_ctx->roi_map = NULL; + p_ctx->avc_roi_map = NULL; + p_ctx->hevc_roi_map = NULL; + p_ctx->hevc_sub_ctu_roi_buf = NULL; p_ctx->p_master_display_meta_data = NULL; p_ctx->enc_change_params = NULL; @@ -618,14 +721,28 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, p_ctx->framerate.framerate_num = 0; p_ctx->framerate.framerate_denom = 0; p_ctx->vui.colorDescPresent = 0; - p_ctx->vui.colorPrimaries = 0; - p_ctx->vui.colorTrc = 0; - p_ctx->vui.colorSpace = 0; + p_ctx->vui.colorPrimaries = 2; // 2 is unspecified + p_ctx->vui.colorTrc = 2; // 2 is unspecified + p_ctx->vui.colorSpace = 2; // 2 is unspecified p_ctx->vui.aspectRatioWidth = 0; p_ctx->vui.aspectRatioHeight = 0; p_ctx->vui.videoFullRange = 0; - - p_ctx->keep_alive_thread_args = NULL; + p_ctx->max_frame_size = 0; + p_ctx->reconfig_crf = -1; + p_ctx->reconfig_crf_decimal = 0; + p_ctx->reconfig_vbv_buffer_size = 0; + p_ctx->reconfig_vbv_max_rate = 0; + p_ctx->last_gop_size = 0; + p_ctx->initial_frame_delay = 0; + p_ctx->current_frame_delay = 0; + p_ctx->max_frame_delay = 0; + p_ctx->av1_pkt_num = 0; + p_ctx->pool_type = NI_POOL_TYPE_NONE; + p_ctx->force_low_delay = false; + p_ctx->force_low_delay_cnt = 0; + p_ctx->pkt_delay_cnt = 0; + p_ctx->reconfig_intra_period = -1; + p_ctx->reconfig_slice_arg = 0; handle = p_ctx->device_handle; handle1 = p_ctx->blk_io_handle; @@ -634,13 +751,15 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, if (!p_device_pool) { - ni_log(NI_LOG_ERROR, "ERROR: Error calling ni_rsrc_get_device_pool()\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Error calling ni_rsrc_get_device_pool()\n"); retval = NI_RETCODE_ERROR_GET_DEVICE_POOL; LRETURN; } - ni_log(NI_LOG_DEBUG, "%s: device type %d hw_id %d\n", __func__, device_type, - p_ctx->hw_id); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: device type %d hw_id %d blk_dev_name: %s dev_xcoder_name: %s.\n", + __func__, device_type, p_ctx->hw_id, p_ctx->blk_dev_name, + p_ctx->dev_xcoder_name); if (device_type == NI_DEVICE_TYPE_UPLOAD) { @@ -648,6 +767,28 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, query_type = NI_DEVICE_TYPE_ENCODER; } + // if caller requested device by block device name, try to find its GUID and + // use it to override the hw_id which is the passed in device GUID + if (0 != strcmp(p_ctx->blk_dev_name, "")) + { + int tmp_guid_id; + tmp_guid_id = + ni_rsrc_get_device_by_block_name(p_ctx->blk_dev_name, device_type); + if (tmp_guid_id != NI_RETCODE_FAILURE) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: block device name %s type %d guid %d is to " + "override passed in guid %d\n", + __func__, p_ctx->blk_dev_name, device_type, tmp_guid_id, + p_ctx->hw_id); + p_ctx->hw_id = tmp_guid_id; + } else + { + ni_log(NI_LOG_INFO, "%s: block device name %s type %d NOT found ..\n", + __func__, p_ctx->blk_dev_name, device_type); + } + } + // User did not pass in any handle, so we create it for them if ((handle1 == NI_INVALID_DEVICE_HANDLE) && (handle == NI_INVALID_DEVICE_HANDLE)) { @@ -656,12 +797,12 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, if ((rsrc_ctx = ni_rsrc_allocate_simple_direct(device_type, p_ctx->hw_id)) == NULL) { - ni_log(NI_LOG_ERROR, "Error XCoder resource allocation: inst %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "Error XCoder resource allocation: inst %d\n", p_ctx->hw_id); retval = NI_RETCODE_ERROR_OPEN_DEVICE; LRETURN; } - ni_log(NI_LOG_DEBUG, "device %p\n", rsrc_ctx); + ni_log2(p_ctx, NI_LOG_DEBUG, "device %p\n", rsrc_ctx); // Now the device name is in the rsrc_ctx, we open this device to get the file handles #ifdef _WIN32 @@ -685,8 +826,8 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, #else //The original design (code below) is to open char and block device file separately. And the ffmpeg will close the device twice. //However, in I/O version, char device can't be opened. For compatibility, and to avoid errors, open the block device twice. - if (((handle = ni_device_open(rsrc_ctx->p_device_info->blk_name, &dummy_io_size)) == NI_INVALID_DEVICE_HANDLE) || - ((handle1 = ni_device_open(rsrc_ctx->p_device_info->blk_name, &p_ctx->max_nvme_io_size)) == NI_INVALID_DEVICE_HANDLE)) + if (((handle = ni_device_open(rsrc_ctx->p_device_info->dev_name, &dummy_io_size)) == NI_INVALID_DEVICE_HANDLE) || + ((handle1 = ni_device_open(rsrc_ctx->p_device_info->dev_name, &p_ctx->max_nvme_io_size)) == NI_INVALID_DEVICE_HANDLE)) { ni_rsrc_free_device_context(rsrc_ctx); retval = NI_RETCODE_ERROR_OPEN_DEVICE; @@ -705,110 +846,139 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, #endif } else { + int tmp_id = -1; + + // Decide on model load or real load to be used, based on name passed + // in from p_ctx->dev_xcoder_name; after checking it will be used to + // store device file name. + if (0 == strcmp(p_ctx->dev_xcoder_name, NI_BEST_REAL_LOAD_STR)) + { + use_model_load = false; + } else if (0 != strcmp(p_ctx->dev_xcoder_name, NI_BEST_MODEL_LOAD_STR)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s unrecognized option: %s.\n", + __func__, p_ctx->dev_xcoder_name); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + if (ni_rsrc_lock_and_open(query_type, &lock) != NI_RETCODE_SUCCESS) { retval = NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; LRETURN; } - // Then we need to query through all the board to confirm the least model load + // We need to query through all the boards to confirm the least load. + if (IS_XCODER_DEVICE_TYPE(query_type)) { num_coders = p_device_pool->p_device_queue->xcoder_cnt[query_type]; } else - { - retval = NI_RETCODE_INVALID_PARAM; - if (ni_rsrc_unlock(query_type, lock) != NI_RETCODE_SUCCESS) { - retval = NI_RETCODE_ERROR_UNLOCK_DEVICE; - LRETURN; + retval = NI_RETCODE_INVALID_PARAM; + if (ni_rsrc_unlock(query_type, lock) != NI_RETCODE_SUCCESS) + { + retval = NI_RETCODE_ERROR_UNLOCK_DEVICE; + LRETURN; + } + LRETURN; } - LRETURN; - } - int tmp_id = -1; - for (i = 0; i < num_coders; i++) - { - tmp_id = p_device_pool->p_device_queue->xcoders[query_type][i]; - p_device_context = ni_rsrc_get_device_context(query_type, tmp_id); + for (i = 0; i < num_coders; i++) + { + tmp_id = p_device_pool->p_device_queue->xcoders[query_type][i]; + p_device_context = ni_rsrc_get_device_context(query_type, tmp_id); - if (p_device_context == NULL) - { - ni_log(NI_LOG_ERROR, - "ERROR: %s() ni_rsrc_get_device_context() failed\n", - __func__); - continue; - } + if (p_device_context == NULL) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() ni_rsrc_get_device_context() failed\n", + __func__); + continue; + } - // Code is included in the for loop. In the loop, the device is - // just opened once, and it will be closed once too. - p_session_context.blk_io_handle = ni_device_open( - p_device_context->p_device_info->blk_name, &dummy_io_size); - p_session_context.device_handle = p_session_context.blk_io_handle; + // Code is included in the for loop. In the loop, the device is + // just opened once, and it will be closed once too. + p_session_context.blk_io_handle = ni_device_open( + p_device_context->p_device_info->dev_name, &dummy_io_size); + p_session_context.device_handle = p_session_context.blk_io_handle; - if (NI_INVALID_DEVICE_HANDLE == p_session_context.device_handle) - { - ni_log(NI_LOG_ERROR, "Error open device"); - ni_rsrc_free_device_context(p_device_context); - continue; - } + if (NI_INVALID_DEVICE_HANDLE == p_session_context.device_handle) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Error open device"); + ni_rsrc_free_device_context(p_device_context); + continue; + } - p_session_context.hw_id = p_device_context->p_device_info->hw_id; - rc = ni_device_session_query(&p_session_context, query_type); - if (NI_INVALID_DEVICE_HANDLE != p_session_context.device_handle) - { - ni_device_close(p_session_context.device_handle); - } + p_session_context.hw_id = p_device_context->p_device_info->hw_id; + rc = ni_device_session_query(&p_session_context, query_type); + if (NI_INVALID_DEVICE_HANDLE != p_session_context.device_handle) + { + ni_device_close(p_session_context.device_handle); + } - if (NI_RETCODE_SUCCESS != rc) - { - ni_log(NI_LOG_ERROR, "Error query %s %s.%d\n", - device_type_str[query_type], - p_device_context->p_device_info->dev_name, - p_device_context->p_device_info->hw_id); - ni_rsrc_free_device_context(p_device_context); - continue; - } - ni_rsrc_update_record(p_device_context, &p_session_context); - p_dev_info = p_device_context->p_device_info; - // here we select the best load - // for decoder/encoder: check the model_load - // for hwuploader: check directly hwupload count in query result - if (NI_DEVICE_TYPE_UPLOAD == device_type) - { - if (i == 0 || p_session_context.load_query.active_hwuploaders < - num_sw_instances) + if (NI_RETCODE_SUCCESS != rc) { - guid = tmp_id; - num_sw_instances = - p_session_context.load_query.active_hwuploaders; - memcpy(&dev_info, p_dev_info, sizeof(ni_device_info_t)); + ni_log2(p_ctx, NI_LOG_ERROR, "Error query %s %s.%d\n", + g_device_type_str[query_type], + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + ni_rsrc_free_device_context(p_device_context); + continue; } - } else if (i == 0 || p_dev_info->model_load < least_model_load || - (p_dev_info->model_load == least_model_load && - p_dev_info->active_num_inst < num_sw_instances)) - { - guid = tmp_id; - least_model_load = p_dev_info->model_load; - num_sw_instances = p_dev_info->active_num_inst; - memcpy(&dev_info, p_dev_info, sizeof(ni_device_info_t)); - } - ni_rsrc_free_device_context(p_device_context); - } + ni_rsrc_update_record(p_device_context, &p_session_context); + p_dev_info = p_device_context->p_device_info; + + // here we select the best load + // for decoder/encoder: check the model_load/real_load + // for hwuploader: check directly hwupload count in query result + if (NI_DEVICE_TYPE_UPLOAD == device_type) + { + if (i == 0 || + p_session_context.load_query.active_hwuploaders < + num_sw_instances) + { + guid = tmp_id; + num_sw_instances = + p_session_context.load_query.active_hwuploaders; + memcpy(&dev_info, p_dev_info, sizeof(ni_device_info_t)); + } + } else + { + if (use_model_load) + { + curr_load = p_dev_info->model_load; + } else + { + curr_load = p_dev_info->load; + } + + if (i == 0 || curr_load < least_load || + (curr_load == least_load && + p_dev_info->active_num_inst < num_sw_instances)) + { + guid = tmp_id; + least_load = curr_load; + num_sw_instances = p_dev_info->active_num_inst; + memcpy(&dev_info, p_dev_info, sizeof(ni_device_info_t)); + } + } + ni_rsrc_free_device_context(p_device_context); + } #ifdef _WIN32 - // Now we have the device info that has the least model load of the FW - // we open this device and assign the FD - if ((handle = ni_device_open(dev_info.blk_name, &dummy_io_size)) == - NI_INVALID_DEVICE_HANDLE) - { - retval = NI_RETCODE_ERROR_OPEN_DEVICE; - if (ni_rsrc_unlock(device_type, lock) != NI_RETCODE_SUCCESS) + // Now we have the device info that has the least load of the FW + // we open this device and assign the FD + if ((handle = ni_device_open(dev_info.blk_name, &dummy_io_size)) == + NI_INVALID_DEVICE_HANDLE) { - retval = NI_RETCODE_ERROR_UNLOCK_DEVICE; + retval = NI_RETCODE_ERROR_OPEN_DEVICE; + if (ni_rsrc_unlock(device_type, lock) != NI_RETCODE_SUCCESS) + { + retval = NI_RETCODE_ERROR_UNLOCK_DEVICE; + LRETURN; + } LRETURN; - } - LRETURN; } else { p_ctx->device_handle = handle; @@ -822,8 +992,8 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, #else //The original design (code below) is to open char and block device file separately. And the ffmpeg will close the device twice. //However, in I/O version, char device can't be opened. For compatibility, and to avoid errors, open the block device twice. - if (((handle = ni_device_open(dev_info.blk_name, &dummy_io_size)) == NI_INVALID_DEVICE_HANDLE) || - ((handle1 = ni_device_open(dev_info.blk_name, &p_ctx->max_nvme_io_size)) == NI_INVALID_DEVICE_HANDLE)) + if (((handle = ni_device_open(dev_info.dev_name, &dummy_io_size)) == NI_INVALID_DEVICE_HANDLE) || + ((handle1 = ni_device_open(dev_info.dev_name, &p_ctx->max_nvme_io_size)) == NI_INVALID_DEVICE_HANDLE)) { retval = NI_RETCODE_ERROR_OPEN_DEVICE; if (ni_rsrc_unlock(query_type, lock) != NI_RETCODE_SUCCESS) @@ -856,32 +1026,49 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, user_handles = true; } - ni_log(NI_LOG_DEBUG, - "Finish open the session dev:%s blk:%s guid:%d handle:%p handle1:%p\n", - p_ctx->dev_xcoder_name, p_ctx->blk_xcoder_name, p_ctx->hw_id, + ni_log2(p_ctx, NI_LOG_DEBUG, + "Finish open the session dev:%s guid:%d handle:%p handle1:%p\n", + p_ctx->dev_xcoder_name, p_ctx->hw_id, p_ctx->device_handle, p_ctx->blk_io_handle); // get FW API version p_device_context = ni_rsrc_get_device_context(device_type, p_ctx->hw_id); if (p_device_context == NULL) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() ni_rsrc_get_device_context() failed\n", __func__); retval = NI_RETCODE_ERROR_OPEN_DEVICE; LRETURN; } + + if (!(strcmp(p_ctx->dev_xcoder_name, "")) || !(strcmp(p_ctx->dev_xcoder_name, NI_BEST_MODEL_LOAD_STR)) || + !(strcmp(p_ctx->dev_xcoder_name, NI_BEST_REAL_LOAD_STR))) + { + strcpy(p_ctx->dev_xcoder_name, p_device_context->p_device_info->dev_name); + } + memcpy(p_ctx->fw_rev , p_device_context->p_device_info->fw_rev, 8); + ni_rsrc_free_device_context(p_device_context); + retval = ni_device_get_ddr_configuration(p_ctx); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() cannot retrieve DDR configuration\n", __func__); LRETURN; } + if (p_ctx->keep_alive_timeout == 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() keep_alive_timeout was 0, should be between 1-100. " + "Setting to default of %u\n", + __func__, NI_DEFAULT_KEEP_ALIVE_TIMEOUT); + p_ctx->keep_alive_timeout = NI_DEFAULT_KEEP_ALIVE_TIMEOUT; + } switch (device_type) { case NI_DEVICE_TYPE_DECODER: @@ -920,7 +1107,7 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, (ni_device_handle_t)(int64_t)pSurface->device_handle; p_enc_params->rootBufId = pSurface->ui16FrameIdx; - ni_log(NI_LOG_DEBUG, "%s: sender_handle and rootBufId %d set\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: sender_handle and rootBufId %d set\n", __func__, p_enc_params->rootBufId); } #endif @@ -1006,16 +1193,16 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, } } retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); LRETURN; } } - p_ctx->keep_alive_thread_args = (ni_thread_arg_struct_t *) malloc (sizeof(ni_thread_arg_struct_t)); + p_ctx->keep_alive_thread_args = (ni_thread_arg_struct_t *) malloc(sizeof(ni_thread_arg_struct_t)); if (!p_ctx->keep_alive_thread_args) { - ni_log(NI_LOG_ERROR, "ERROR: thread_args allocation failed!\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: thread_args allocation failed!\n"); ni_device_session_close(p_ctx, 0, device_type); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -1028,11 +1215,15 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, p_ctx->keep_alive_thread_args->thread_event_handle = p_ctx->event_handle; p_ctx->keep_alive_thread_args->close_thread = false; p_ctx->keep_alive_thread_args->keep_alive_timeout = p_ctx->keep_alive_timeout; - - if (ni_posix_memalign(&(p_ctx->keep_alive_thread_args->p_buffer), + p_ctx->keep_alive_thread_args->plast_access_time = &p_ctx->last_access_time; + p_ctx->keep_alive_thread_args->p_mutex = &p_ctx->mutex; + p_ctx->keep_alive_thread_args->hw_id = p_ctx->hw_id; + p_ctx->last_access_time = ni_gettime_ns(); + + if (ni_posix_memalign(&p_ctx->keep_alive_thread_args->p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR: keep alive p_buffer allocation failed!\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: keep alive p_buffer allocation failed!\n"); ni_device_session_close(p_ctx, 0, device_type); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -1044,28 +1235,27 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, ni_session_keep_alive_thread, (void *)p_ctx->keep_alive_thread_args)) { - ni_log(NI_LOG_ERROR, "ERROR: failed to create keep alive thread\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: failed to create keep alive thread\n"); p_ctx->keep_alive_thread = (ni_pthread_t){0}; ni_aligned_free(p_ctx->keep_alive_thread_args->p_buffer); - ni_aligned_free(p_ctx->keep_alive_thread_args); + ni_memfree(p_ctx->keep_alive_thread_args); ni_device_session_close(p_ctx, 0, device_type); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } - ni_log(NI_LOG_DEBUG, "Enabled keep alive thread\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "Enabled keep alive thread\n"); // allocate memory for encoder change data to be reused p_ctx->enc_change_params = calloc(1, sizeof(ni_encoder_change_params_t)); if (!p_ctx->enc_change_params) { - ni_log(NI_LOG_ERROR, "ERROR: enc_change_params allocation failed!\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: enc_change_params allocation failed!\n"); ni_device_session_close(p_ctx, 0, device_type); retval = NI_RETCODE_ERROR_MEM_ALOC; } END: - - ni_rsrc_free_device_context(p_device_context); + ni_device_session_context_clear(&p_session_context); if (p_device_pool) { @@ -1074,7 +1264,8 @@ ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, } p_ctx->xcoder_state &= ~NI_XCODER_OPEN_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -1108,13 +1299,14 @@ ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_CLOSE_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); #ifdef _WIN32 if (p_ctx->keep_alive_thread.handle && p_ctx->keep_alive_thread_args) @@ -1126,15 +1318,15 @@ ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, ret = ni_pthread_join(p_ctx->keep_alive_thread, NULL); if (ret) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "join keep alive thread fail! : sid %u ret %d\n", p_ctx->session_id, ret); } ni_aligned_free(p_ctx->keep_alive_thread_args->p_buffer); - ni_aligned_free(p_ctx->keep_alive_thread_args); + ni_memfree(p_ctx->keep_alive_thread_args); } else { - ni_log(NI_LOG_ERROR, "invalid keep alive thread: %u\n", + ni_log2(p_ctx, NI_LOG_ERROR, "invalid keep alive thread: %u\n", p_ctx->session_id); } @@ -1168,20 +1360,24 @@ ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, default: { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); break; } } + ni_pthread_mutex_lock(&p_ctx->mutex); // need set invalid after closed. May cause open invalid parameters. p_ctx->session_id = NI_INVALID_SESSION_ID; - ni_aligned_free(p_ctx->p_hdr_buf); - ni_aligned_free(p_ctx->av_rois); - ni_aligned_free(p_ctx->roi_map); - ni_aligned_free(p_ctx->p_master_display_meta_data); - ni_aligned_free(p_ctx->enc_change_params); + ni_memfree(p_ctx->p_hdr_buf); + ni_memfree(p_ctx->av_rois); + ni_memfree(p_ctx->roi_map); + ni_memfree(p_ctx->avc_roi_map); + ni_memfree(p_ctx->hevc_roi_map); + ni_memfree(p_ctx->hevc_sub_ctu_roi_buf); + ni_memfree(p_ctx->p_master_display_meta_data); + ni_memfree(p_ctx->enc_change_params); p_ctx->hdr_buf_size = 0; p_ctx->roi_side_data_size = 0; p_ctx->nb_rois = 0; @@ -1191,18 +1387,30 @@ ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, p_ctx->ltr_to_set.use_long_term_ref = 0; p_ctx->ltr_interval = -1; p_ctx->ltr_frame_ref_invalid = -1; + p_ctx->max_frame_size = 0; + p_ctx->reconfig_crf = -1; + p_ctx->reconfig_crf_decimal = 0; + p_ctx->reconfig_vbv_buffer_size = 0; + p_ctx->reconfig_vbv_max_rate = 0; + p_ctx->last_gop_size = 0; + p_ctx->initial_frame_delay = 0; + p_ctx->current_frame_delay = 0; + p_ctx->max_frame_delay = 0; + p_ctx->av1_pkt_num = 0; + p_ctx->reconfig_intra_period = -1; + p_ctx->reconfig_slice_arg = 0; p_ctx->xcoder_state &= ~NI_XCODER_CLOSE_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } /*!***************************************************************************** * \brief Send a flush command to the device - * If device_type is NI_DEVICE_TYPE_DECODER sends flush command to + * If device_type is NI_DEVICE_TYPE_DECODER sends EOS command to * decoder - * If device_type is NI_DEVICE_TYPE_ENCODER sends flush command to + * If device_type is NI_DEVICE_TYPE_ENCODER sends EOS command to * encoder * * \param[in] p_ctx Pointer to a caller allocated @@ -1220,37 +1428,37 @@ ni_retcode_t ni_device_session_flush(ni_session_context_t* p_ctx, ni_device_type ni_retcode_t retval = NI_RETCODE_SUCCESS; if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_FLUSH_STATE; switch (device_type) { case NI_DEVICE_TYPE_DECODER: { - retval = ni_decoder_session_flush(p_ctx); + retval = ni_decoder_session_send_eos(p_ctx); break; } case NI_DEVICE_TYPE_ENCODER: { - retval = ni_encoder_session_flush(p_ctx); + retval = ni_encoder_session_send_eos(p_ctx); break; } default: { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); break; } } p_ctx->ready_to_close = (NI_RETCODE_SUCCESS == retval); p_ctx->xcoder_state &= ~NI_XCODER_FLUSH_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -1277,13 +1485,13 @@ ni_retcode_t ni_device_dec_session_save_hdrs(ni_session_context_t *p_ctx, if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s p_ctx null, return\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s p_ctx null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } if (!hdr_data) { - ni_log(NI_LOG_ERROR, "ERROR: %s hdr_data null, return\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s hdr_data null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } else if (p_ctx->p_hdr_buf && p_ctx->hdr_buf_size == hdr_size && 0 == memcmp(p_ctx->p_hdr_buf, hdr_data, hdr_size)) @@ -1293,19 +1501,19 @@ ni_retcode_t ni_device_dec_session_save_hdrs(ni_session_context_t *p_ctx, } // update the saved header data - ni_aligned_free(p_ctx->p_hdr_buf); + free(p_ctx->p_hdr_buf); p_ctx->hdr_buf_size = 0; p_ctx->p_hdr_buf = malloc(hdr_size); if (p_ctx->p_hdr_buf) { memcpy(p_ctx->p_hdr_buf, hdr_data, hdr_size); p_ctx->hdr_buf_size = hdr_size; - ni_log(NI_LOG_DEBUG, "%s saved hdr size %u\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s saved hdr size %u\n", __func__, p_ctx->hdr_buf_size); } else { retval = NI_RETCODE_ERROR_INVALID_SESSION; - ni_log(NI_LOG_ERROR, "ERROR: %s no memory.\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s no memory.\n", __func__); } return retval; } @@ -1324,55 +1532,21 @@ ni_retcode_t ni_device_dec_session_save_hdrs(ni_session_context_t *p_ctx, * NI_RETCODE_ERROR_NVME_CMD_FAILED * NI_RETCODE_ERROR_INVALID_SESSION ******************************************************************************/ -LIB_API ni_retcode_t ni_device_dec_session_flush(ni_session_context_t *p_ctx) +ni_retcode_t ni_device_dec_session_flush(ni_session_context_t *p_ctx) { ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint8_t *p_tmp_data = NULL; - uint8_t tmp_data_size = 0; if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s ctx null, return\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s ctx null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); - p_ctx->xcoder_state |= NI_XCODER_INTER_FLUSH_STATE; - // save the stream header data for the new session to be opened - if (p_ctx->p_hdr_buf && p_ctx->hdr_buf_size) - { - p_tmp_data = malloc(p_ctx->hdr_buf_size); - if (p_tmp_data) - { - memcpy(p_tmp_data, p_ctx->p_hdr_buf, p_ctx->hdr_buf_size); - tmp_data_size = p_ctx->hdr_buf_size; - } else - { - return NI_RETCODE_ERROR_INVALID_SESSION; - } - } - - // close the current session and open a new one - ni_device_session_close(p_ctx, 0, NI_DEVICE_TYPE_DECODER); - - if ((retval = ni_device_session_open(p_ctx, NI_DEVICE_TYPE_DECODER)) == - NI_RETCODE_SUCCESS) - { - // copy over the saved stream header to be sent as part of the first - // data to decoder - if (p_tmp_data && tmp_data_size && p_ctx->p_leftover) - { - ni_device_dec_session_save_hdrs(p_ctx, p_tmp_data, tmp_data_size); - memcpy(p_ctx->p_leftover, p_ctx->p_hdr_buf, p_ctx->hdr_buf_size); - p_ctx->prev_size = p_ctx->hdr_buf_size; - } - ni_log(NI_LOG_DEBUG, "%s completed, hdr size %u saved.\n", __func__, - p_ctx->hdr_buf_size); + ni_pthread_mutex_lock(&p_ctx->mutex); + retval = ni_decoder_session_flush(p_ctx); + if (NI_RETCODE_SUCCESS == retval) { + p_ctx->ready_to_close = 0; } - - ni_aligned_free(p_tmp_data); - p_ctx->xcoder_state &= ~NI_XCODER_INTER_FLUSH_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -1411,7 +1585,7 @@ int ni_device_session_write(ni_session_context_t *p_ctx, ni_session_data_io_t *p if (!p_ctx || !p_data) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -1423,29 +1597,24 @@ int ni_device_session_write(ni_session_context_t *p_ctx, ni_session_data_io_t *p if (p_ctx->keep_alive_thread && p_ctx->keep_alive_thread_args->close_thread) #endif { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() keep alive thread has been closed, " "hw:%d, session:%d\n", __func__, p_ctx->hw_id, p_ctx->session_id); return NI_RETCODE_ERROR_INVALID_SESSION; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); // In close state, let the close process execute first. - if (p_ctx->xcoder_state & NI_XCODER_CLOSE_STATE || - #ifdef _WIN32 - (p_ctx->keep_alive_thread.handle && - #else - (p_ctx->keep_alive_thread && - #endif - p_ctx->keep_alive_thread_args->close_thread)) - { - ni_log(NI_LOG_DEBUG, "%s close state, return\n", __func__); - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + if (p_ctx->xcoder_state & NI_XCODER_CLOSE_STATE) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s close state, return\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); ni_usleep(100); - return NI_RETCODE_SUCCESS; + return NI_RETCODE_ERROR_INVALID_SESSION; } p_ctx->xcoder_state |= NI_XCODER_WRITE_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); switch (device_type) { @@ -1467,13 +1636,15 @@ int ni_device_session_write(ni_session_context_t *p_ctx, ni_session_data_io_t *p default: { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); break; } } + + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state &= ~NI_XCODER_WRITE_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -1513,7 +1684,7 @@ int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_ ni_retcode_t retval = NI_RETCODE_SUCCESS; if ((!p_ctx) || (!p_data)) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -1526,35 +1697,31 @@ int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_ if (p_ctx->keep_alive_thread && p_ctx->keep_alive_thread_args->close_thread) #endif { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() keep alive thread has been closed, " "hw:%d, session:%d\n", __func__, p_ctx->hw_id, p_ctx->session_id); return NI_RETCODE_ERROR_INVALID_SESSION; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); // In close state, let the close process execute first. - if (p_ctx->xcoder_state & NI_XCODER_CLOSE_STATE || - #ifdef _WIN32 - (p_ctx->keep_alive_thread.handle && - #else - (p_ctx->keep_alive_thread && - #endif - p_ctx->keep_alive_thread_args->close_thread)) - { - ni_log(NI_LOG_DEBUG, "%s close state, return\n", __func__); - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + if (p_ctx->xcoder_state & NI_XCODER_CLOSE_STATE) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s close state, return\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); ni_usleep(100); - return NI_RETCODE_SUCCESS; + return NI_RETCODE_ERROR_INVALID_SESSION; } p_ctx->xcoder_state |= NI_XCODER_READ_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); switch (device_type) { case NI_DEVICE_TYPE_DECODER: { int seq_change_read_count = 0; + p_data->data.frame.src_codec = p_ctx->codec_format; for (;;) { retval = ni_decoder_session_read(p_ctx, &(p_data->data.frame)); @@ -1575,7 +1742,7 @@ int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_ if (0 == retval && seq_change_read_count) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s (decoder): seq change NO data, next time.\n", __func__); p_ctx->active_video_width = 0; p_ctx->active_video_height = 0; @@ -1584,22 +1751,26 @@ int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_ } else if (retval < 0) { - ni_log(NI_LOG_ERROR, "%s (decoder): failure ret %d, return ..\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s (decoder): failure ret %d, return ..\n", __func__, retval); break; } - else if (p_ctx->frame_num && p_data->data.frame.video_width && - p_data->data.frame.video_height && - (aligned_width != p_ctx->active_video_width || - p_data->data.frame.video_height != p_ctx->active_video_height)) + // aligned_width may equal to active_video_width if bit depth and width + // are changed at the same time. So, check video_width != actual_video_width. + else if (p_ctx->frame_num && (p_ctx->pixel_format_changed || + (p_data->data.frame.video_width && + p_data->data.frame.video_height && + (aligned_width != p_ctx->active_video_width || + p_data->data.frame.video_height != p_ctx->active_video_height)))) { - ni_log( - NI_LOG_DEBUG, + ni_log2( + p_ctx, NI_LOG_DEBUG, "%s (decoder): resolution change, frame size %ux%u -> %ux%u, " - "width %u bit %d, continue read ...\n", + "width %u bit %d, pix_fromat_changed %d, actual_video_width %d, continue read ...\n", __func__, p_ctx->active_video_width, p_ctx->active_video_height, aligned_width, p_data->data.frame.video_height, - p_data->data.frame.video_width, p_ctx->bit_depth_factor); + p_data->data.frame.video_width, p_ctx->bit_depth_factor, + p_ctx->pixel_format_changed, p_ctx->actual_video_width); // reset active video resolution to 0 so it can be queried in the re-read p_ctx->active_video_width = 0; p_ctx->active_video_height = 0; @@ -1626,13 +1797,15 @@ int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_ default: { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); break; } } + + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state &= ~NI_XCODER_READ_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -1661,7 +1834,7 @@ ni_retcode_t ni_device_session_query(ni_session_context_t* p_ctx, ni_device_type ni_retcode_t retval = NI_RETCODE_SUCCESS; if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -1672,7 +1845,7 @@ ni_retcode_t ni_device_session_query(ni_session_context_t* p_ctx, ni_device_type } else { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); } @@ -1680,75 +1853,229 @@ ni_retcode_t ni_device_session_query(ni_session_context_t* p_ctx, ni_device_type } /*!***************************************************************************** - * \brief Allocate preliminary memory for the frame buffer based on provided - * parameters. Applicable to YUV420 Planar pixel (8 or 10 bit/pixel) - * format or 32-bit RGBA. + * \brief Query detail session data from the device - + * If device_type is valid, will query session data + * from specified device type * - * \param[in] p_frame Pointer to a caller allocated - * ni_frame_t struct - * \param[in] video_width Width of the video frame - * \param[in] video_height Height of the video frame - * \param[in] alignment Allignment requirement - * \param[in] metadata_flag Flag indicating if space for additional metadata - * should be allocated - * \param[in] factor 1 for 8 bits/pixel format, 2 for 10 bits/pixel, - * 4 for 32 bits/pixel (RGBA) - * \param[in] hw_frame_count Number of hw descriptors stored - * \param[in] is_planar 0 if semiplanar else planar + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] device_type NI_DEVICE_TYPE_DECODER or + * NI_DEVICE_TYPE_ENCODER or * * \return On success * NI_RETCODE_SUCCESS * On failure * NI_RETCODE_INVALID_PARAM - * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_INVALID_SESSION ******************************************************************************/ -ni_retcode_t ni_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, - int video_height, int alignment, - int metadata_flag, int factor, - int hw_frame_count, int is_planar) { - void* p_buffer = NULL; - int metadata_size = 0; - int retval = NI_RETCODE_SUCCESS; - // TBD for sequence change (non-regular resolution video sample): - // width has to be 16-aligned to prevent f/w assertion - int width_aligned = video_width; - int height_aligned = video_height; - - if ((!p_frame) || ((factor!=1) && (factor!=2) && (factor !=4)) - || (video_width>NI_MAX_RESOLUTION_WIDTH) || (video_width<=0) - || (video_height>NI_MAX_RESOLUTION_HEIGHT) || (video_height<=0)) +ni_retcode_t ni_device_session_query_detail(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_detail_status_t *detail_data) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null or not supported, " - "factor %d, video_width %d, video_height %d\n", - __func__, factor, video_width, video_height); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + __func__); return NI_RETCODE_INVALID_PARAM; } - if (metadata_flag) + if (IS_XCODER_DEVICE_TYPE(device_type)) { - metadata_size = NI_FW_META_DATA_SZ + NI_MAX_SEI_DATA; + retval = ni_xcoder_session_query_detail(p_ctx, device_type, detail_data, 0); + } else + { + retval = NI_RETCODE_INVALID_PARAM; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + __func__, device_type); } - if (QUADRA) + return retval; +} + +/*!***************************************************************************** + * \brief Query detail session data from the device - + * If device_type is valid, will query session data + * from specified device type + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] device_type NI_DEVICE_TYPE_DECODER or + * NI_DEVICE_TYPE_ENCODER or + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_INVALID_SESSION + ******************************************************************************/ +ni_retcode_t ni_device_session_query_detail_v1(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_detail_status_v1_t *detail_data) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + if (!p_ctx) { - switch (factor) - { - case 1: /* 8-bit YUV420 */ - case 2: /* 10-bit YUV420 */ - width_aligned = ((((video_width * factor) + 127) / 128) * 128) / factor; - height_aligned = ((video_height + 1) / 2) * 2; - break; - case 4: /* 32-bit RGBA */ - /* 2D engine has no height/width alignment requirements for RGBA */ - width_aligned = video_width; - height_aligned = video_height; - break; - default: - return NI_RETCODE_INVALID_PARAM; - } + ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; } - else - { + + if (IS_XCODER_DEVICE_TYPE(device_type)) + { + retval = ni_xcoder_session_query_detail(p_ctx, device_type, detail_data, 1); + } else + { + retval = NI_RETCODE_INVALID_PARAM; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + __func__, device_type); + } + + return retval; +} + +/*!***************************************************************************** + * \brief Send namespace num and SRIOv index to the device with specified logic block + * address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] namespace_num Set the namespace number with designated sriov + * \param[in] sriov_index Identify which sriov need to be set + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_config_namespace_num(ni_device_handle_t device_handle, + uint32_t namespace_num, uint32_t sriov_index) +{ + ni_log(NI_LOG_DEBUG, "%s namespace_num %u sriov_index %u\n", + __func__, namespace_num, sriov_index); + return ni_device_config_ns_qos(device_handle, namespace_num, sriov_index); +} + +/*!***************************************************************************** + * \brief Send qos mode to the device with specified logic block + * address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] mode The requested qos mode + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_config_qos(ni_device_handle_t device_handle, + uint32_t mode) +{ + ni_log(NI_LOG_DEBUG, "%s device_handle %p mode %u\n", + __func__, device_handle, mode); + return ni_device_config_ns_qos(device_handle, QOS_NAMESPACE_CODE, mode); +} + +/*!***************************************************************************** + * \brief Send qos over provisioning mode to target namespace with specified logic + * block address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] device_handle_t Target device handle of namespace required for OP + * \param[in] over_provision The request overprovision percent + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_config_qos_op(ni_device_handle_t device_handle, + ni_device_handle_t device_handle_t, + uint32_t over_provision) +{ + ni_retcode_t retval; + ni_log(NI_LOG_DEBUG, "%s device_handle %p target %p over_provision %u\n", + __func__, device_handle, device_handle_t, over_provision); + retval = ni_device_config_ns_qos(device_handle, QOS_OP_CONFIG_REC_OP_CODE, + over_provision); + if (NI_RETCODE_SUCCESS != retval) + { + return retval; + } + retval = ni_device_config_ns_qos(device_handle_t, QOS_OP_CONFIG_CODE, + 0); + return retval; +} + +/*!***************************************************************************** + * \brief Allocate preliminary memory for the frame buffer based on provided + * parameters. Applicable to YUV420 Planar pixel (8 or 10 bit/pixel) + * format or 32-bit RGBA. + * + * \param[in] p_frame Pointer to a caller allocated + * ni_frame_t struct + * \param[in] video_width Width of the video frame + * \param[in] video_height Height of the video frame + * \param[in] alignment Allignment requirement + * \param[in] metadata_flag Flag indicating if space for additional metadata + * should be allocated + * \param[in] factor 1 for 8 bits/pixel format, 2 for 10 bits/pixel, + * 4 for 32 bits/pixel (RGBA) + * \param[in] hw_frame_count Number of hw descriptors stored + * \param[in] is_planar 0 if semiplanar else planar + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +ni_retcode_t ni_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, + int video_height, int alignment, + int metadata_flag, int factor, + int hw_frame_count, int is_planar) +{ + void* p_buffer = NULL; + int metadata_size = 0; + int retval = NI_RETCODE_SUCCESS; + int width_aligned = video_width; + int height_aligned = video_height; + + if ((!p_frame) || ((factor!=1) && (factor!=2) && (factor !=4)) + || (video_width>NI_MAX_RESOLUTION_WIDTH) || (video_width<=0) + || (video_height>NI_MAX_RESOLUTION_HEIGHT) || (video_height<=0)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null or not supported, " + "factor %d, video_width %d, video_height %d\n", + __func__, factor, video_width, video_height); + return NI_RETCODE_INVALID_PARAM; + } + + if (metadata_flag) + { + metadata_size = NI_FW_META_DATA_SZ + NI_MAX_SEI_DATA; + } + + if (QUADRA) + { + switch (factor) + { + case 1: /* 8-bit YUV420 */ + case 2: /* 10-bit YUV420 */ + width_aligned = ((((video_width * factor) + 127) / 128) * 128) / factor; + height_aligned = ((video_height + 1) / 2) * 2; + break; + case 4: /* 32-bit RGBA */ + //64byte aligned => 16 rgba pixels + width_aligned = NI_VPU_ALIGN16(video_width); + height_aligned = ((video_height + 1) / 2) * 2; + break; + default: + return NI_RETCODE_INVALID_PARAM; + } + } + else + { width_aligned = ((video_width + 31) / 32) * 32; height_aligned = ((video_height + 7) / 8) * 8; if (alignment) @@ -1763,17 +2090,23 @@ ni_retcode_t ni_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, if (QUADRA) { int chroma_width_aligned = ((((video_width / 2 * factor) + 127) / 128) * 128) / factor; - if (!is_planar) + if (is_planar == NI_PIXEL_PLANAR_FORMAT_TILED4X4 || + is_planar == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) { chroma_width_aligned = ((((video_width * factor) + 127) / 128) * 128) / factor; } int chroma_height_aligned = height_aligned / 2; chroma_b_size = chroma_r_size = chroma_width_aligned * chroma_height_aligned * factor; - if (!is_planar) + if (is_planar == NI_PIXEL_PLANAR_FORMAT_TILED4X4 || + is_planar == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) { chroma_r_size = 0; } + if (4 == factor) + { + chroma_b_size = chroma_r_size = 0; + } //ni_log(NI_LOG_DEBUG, "%s: factor %d chroma_aligned=%dx%d org=%dx%d\n", __func__, factor, chroma_width_aligned, chroma_height_aligned, video_width, video_height); } else @@ -1857,7 +2190,7 @@ ni_retcode_t ni_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, p_frame->video_width = width_aligned; p_frame->video_height = height_aligned; - //ni_log(NI_LOG_DEBUG, "ni_frame_buffer_alloc: p_buffer %p p_data [%p %p %p %p] data_len [%d %d %d %d] video_width %d video_height %d\n", p_frame->p_buffer, p_frame->p_data[0], p_frame->p_data[1], p_frame->p_data[2], p_frame->p_data[3], p_frame->data_len[0], p_frame->data_len[1], p_frame->data_len[2], p_frame->data_len[3], p_frame->video_width, p_frame->video_height); + ni_log(NI_LOG_DEBUG, "ni_frame_buffer_alloc: p_buffer %p p_data [%p %p %p %p] data_len [%d %d %d %d] video_width %d video_height %d\n", p_frame->p_buffer, p_frame->p_data[0], p_frame->p_data[1], p_frame->p_data[2], p_frame->p_data[3], p_frame->data_len[0], p_frame->data_len[1], p_frame->data_len[2], p_frame->data_len[3], p_frame->video_width, p_frame->video_height); ni_log(NI_LOG_DEBUG, "%s: success: p_frame->buffer_size=%u\n", __func__, p_frame->buffer_size); @@ -1871,6 +2204,85 @@ ni_retcode_t ni_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, return retval; } +/*!***************************************************************************** + * \brief Wrapper function for ni_frame_buffer_alloc. Meant to handle RGBA min. + * resoulution considerations for encoder. + * + * \param[in] p_frame Pointer to a caller allocated + * ni_frame_t struct + * \param[in] video_width Width of the video frame + * \param[in] video_height Height of the video frame + * \param[in] alignment Allignment requirement + * \param[in] metadata_flag Flag indicating if space for additional metadata + * should be allocated + * \param[in] factor 1 for 8 bits/pixel format, 2 for 10 bits/pixel, + * 4 for 32 bits/pixel (RGBA) + * \param[in] hw_frame_count Number of hw descriptors stored + * \param[in] is_planar 0 if semiplanar else planar + * \param[in] pix_fmt pixel format to distinguish between planar types + * and/or components + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +ni_retcode_t ni_enc_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, + int video_height, int alignment, + int metadata_flag, int factor, + int hw_frame_count, int is_planar, + ni_pix_fmt_t pix_fmt) +{ + int extra_len = 0; + int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; + int height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0}; + + if (((factor!=1) && (factor!=2) && (factor !=4)) + || (video_width>NI_MAX_RESOLUTION_WIDTH) || (video_width<=0) + || (video_height>NI_MAX_RESOLUTION_HEIGHT) || (video_height<=0)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null or not supported, " + "factor %d, video_width %d, video_height %d\n", + __func__, factor, video_width, video_height); + return NI_RETCODE_INVALID_PARAM; + } + + switch (pix_fmt) + { + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_YUV420P10LE: + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + case NI_PIX_FMT_NV16: + case NI_PIX_FMT_YUYV422: + case NI_PIX_FMT_UYVY422: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_BGR0: + break; + default: + ni_log(NI_LOG_ERROR, "ERROR: %s pix_fmt %d not supported \n", + __func__, pix_fmt); + return NI_RETCODE_INVALID_PARAM; + } + //Get stride info for original resolution + ni_get_frame_dim(video_width, video_height, + pix_fmt, + dst_stride, height_aligned); + + if (metadata_flag) + { + extra_len = NI_FW_META_DATA_SZ + NI_MAX_SEI_DATA; + } + + return ni_frame_buffer_alloc_pixfmt(p_frame, pix_fmt, video_width, + video_height, dst_stride, alignment, + extra_len); +} + /*!***************************************************************************** * \brief Allocate preliminary memory for the frame buffer based on provided * parameters. @@ -1947,10 +2359,10 @@ ni_retcode_t ni_frame_buffer_alloc_dl(ni_frame_t *p_frame, int video_width, chroma_r_size = 0; break; case NI_PIX_FMT_NV16: - width_aligned = video_width; + width_aligned = NI_VPU_ALIGN64(video_width); height_aligned = video_height; - luma_size = video_width * video_height; + luma_size = width_aligned * height_aligned; chroma_b_size = luma_size; chroma_r_size = 0; break; @@ -1976,10 +2388,10 @@ ni_retcode_t ni_frame_buffer_alloc_dl(ni_frame_t *p_frame, int video_width, chroma_r_size = 0; break; case NI_PIX_FMT_BGRP: - width_aligned = video_width; + width_aligned = NI_VPU_ALIGN32(video_width); height_aligned = video_height; - luma_size = NI_VPU_ALIGN32(width_aligned * height_aligned); + luma_size = width_aligned * height_aligned; chroma_b_size = luma_size; chroma_r_size = luma_size; break; @@ -2021,6 +2433,7 @@ ni_retcode_t ni_frame_buffer_alloc_dl(ni_frame_t *p_frame, int video_width, } else { ni_log(NI_LOG_DEBUG, "%s: reuse p_frame buffer\n", __func__); + p_buffer = p_frame->p_buffer; } // init once after allocation @@ -2086,7 +2499,6 @@ ni_retcode_t ni_decoder_frame_buffer_alloc(ni_buf_pool_t *p_pool, int alignment, int factor, int is_planar) { - void* p_buffer = NULL; int retval = NI_RETCODE_SUCCESS; int width_aligned; @@ -2210,20 +2622,163 @@ ni_retcode_t ni_decoder_frame_buffer_alloc(ni_buf_pool_t *p_pool, } /*!***************************************************************************** - * \brief Allocate memory for the frame buffer for encoding based on given - * parameters, taking into account pic line size and extra data. - * Applicable to YUV420p AVFrame only. 8 or 10 bit/pixel. - * Cb/Cr size matches that of Y. + * \brief Check if incoming frame is encoder zero copy compatible or not + * + * \param[in] p_enc_ctx pointer to encoder context + * [in] p_enc_params pointer to encoder parameters + * [in] width input width + * [in] height input height + * [in] linesize input linesizes (pointer to array) + * [in] set_linesize setup linesizes 0 means not setup linesizes, 1 means setup linesizes (before encoder open) + * + * \return on success and can do zero copy + * NI_RETCODE_SUCCESS + * + * cannot do zero copy + * NI_RETCODE_ERROR_UNSUPPORTED_FEATURE + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_INVALID_PARAM + * +*******************************************************************************/ +ni_retcode_t ni_encoder_frame_zerocopy_check(ni_session_context_t *p_enc_ctx, + ni_xcoder_params_t *p_enc_params, + int width, int height, + const int linesize[], + bool set_linesize) +{ + // check pixel format / width / height / linesize can be supported + if ((!p_enc_ctx) || (!p_enc_params) || (!linesize) + || (linesize[0]<=0) + || (width>NI_MAX_RESOLUTION_WIDTH) || (width<=0) + || (height>NI_MAX_RESOLUTION_HEIGHT) || (height<=0)) + { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s passed parameters are null or not supported, " + "p_enc_ctx %p, p_enc_params %p, linesize %p, " + "width %d, height %d linesize[0] %d\n", + __func__, p_enc_ctx, p_enc_params, linesize, + width, height, (linesize) ? linesize[0] : 0); + return NI_RETCODE_INVALID_PARAM; + } + + // check fw revision (if fw_rev has been populated in open session) + if (p_enc_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] && + (ni_cmp_fw_api_ver((char*) &p_enc_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6Q") < 0)) + { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s: not supported on device with FW API version < 6.Q\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + bool isrgba = false; + bool isplanar = false; + bool issemiplanar = false; + + switch (p_enc_ctx->pixel_format) + { + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_YUV420P10LE: + isplanar = true; + break; + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + issemiplanar = true; + break; + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + isrgba = true; + break; + default: + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s: pixel_format %d not supported\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + // check fw revision (if fw_rev has been populated in open session) + if (issemiplanar && + p_enc_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] && + (ni_cmp_fw_api_ver((char*) &p_enc_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6q") < 0)) + { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s: semi-planar not supported on device with FW API version < 6.q\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + // check zero copy compatibilty and set linesize + if (p_enc_params->zerocopy_mode) // always allow zero copy for RGBA, because RGBA pixel format data copy currently not supported + { + if (set_linesize) + { + bool ishwframe = (p_enc_params->hwframes) ? true : false; + int max_linesize = isrgba ? (NI_MAX_RESOLUTION_RGBA_WIDTH*4) : NI_MAX_RESOLUTION_LINESIZE; + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s isrgba %u issemiplanar %u, ishwframe %u, " + "p_enc_ctx %p, p_enc_params %p, linesize %p, " + "width %d, height %d, linesize[0] %d linesize[1] %d\n", + __func__, isrgba, issemiplanar, ishwframe, p_enc_ctx, p_enc_params, linesize, + width, height, linesize[0], linesize[1]); + + if (linesize[0] <= max_linesize && + linesize[0] % 2 == 0 && //even stride + linesize[1] % 2 == 0 && //even stride + width % 2 == 0 && //even width + height % 2 == 0 && //even height + width >= NI_MIN_WIDTH && + height >= NI_MIN_HEIGHT && + !ishwframe && + (!isplanar || linesize[2] == linesize[1]) // for planar, make sure cb linesize equal to cr linesize + ) + { + // send luma / chorma linesize to device (device is also aware frame will not be padded for 2-pass workaround) + p_enc_params->luma_linesize = linesize[0]; + p_enc_params->chroma_linesize = (isrgba) ? 0 : linesize[1]; // gstreamer assigns stride length to linesize[0] linesize[1] linesize[2] for RGBA pixel format + return NI_RETCODE_SUCCESS; + } + else + { + p_enc_params->luma_linesize = 0; + p_enc_params->chroma_linesize = 0; + } + } + else if (p_enc_params->luma_linesize || + p_enc_params->chroma_linesize) + { + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s " + "luma_linesize %d, chroma_linesize %d, " + "linesize[0] %d, linesize[1] %d\n", + __func__, p_enc_params->luma_linesize, p_enc_params->chroma_linesize, + linesize[0], linesize[1]); + if (p_enc_params->luma_linesize != linesize[0] || + (p_enc_params->chroma_linesize && p_enc_params->chroma_linesize != linesize[1]) // gstreamer assigns stride length to linesize[0] linesize[1] linesize[2] for RGBA pixel format + ) + { +#ifndef XCODER_311 + // linesizes can change during SW frame seqeunce change transcoding when FFmpeg noautoscale option is not set + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s: linesize changed from %u %u to %u %u - resolution change?\n", __func__, + p_enc_params->luma_linesize, p_enc_params->chroma_linesize, + linesize[0], linesize[1]); +#endif + } + else + return NI_RETCODE_SUCCESS; + } + } + + return NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; +} + +/*!***************************************************************************** + * \brief Allocate memory for encoder zero copy (metadata, etc.) + * for encoding based on given + * parameters, taking into account pic linesize and extra data. + * Applicable to YUV planr / semi-planar 8 or 10 bit and RGBA pixel formats. * - * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct * + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct * \param[in] video_width Width of the video frame * \param[in] video_height Height of the video frame * \param[in] linesize Picture line size - * \param[in] alignment Allignment requirement - * \param[in] extra_len Extra data size (incl. meta data). < 0 means not - * to allocate any buffer (zero-copy from existing) - * \param[in] alignment_2pass_wa set alignment to work with 2pass encode + * \param[in] data Picture data pointers (for each of YUV planes) + * \param[in] extra_len Extra data size (incl. meta data) * * \return On success * NI_RETCODE_SUCCESS @@ -2231,33 +2786,312 @@ ni_retcode_t ni_decoder_frame_buffer_alloc(ni_buf_pool_t *p_pool, * NI_RETCODE_INVALID_PARAM * NI_RETCODE_ERROR_MEM_ALOC *****************************************************************************/ -ni_retcode_t ni_encoder_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, - int video_height, int linesize[], - int alignment, int extra_len, - bool alignment_2pass_wa) +ni_retcode_t ni_encoder_frame_zerocopy_buffer_alloc(ni_frame_t *p_frame, + int video_width, int video_height, + const int linesize[], const uint8_t *data[], + int extra_len) { - void* p_buffer = NULL; - int height_aligned; int retval = NI_RETCODE_SUCCESS; - if ((!p_frame) || (!linesize) || (linesize[0]<=0) || (linesize[0]>NI_MAX_RESOLUTION_LINESIZE) - || (video_width>NI_MAX_RESOLUTION_WIDTH) || (video_width<=0) - || (video_height>NI_MAX_RESOLUTION_HEIGHT) || (video_height<=0)) + if ((!p_frame) || (!linesize) || (!data)) { ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null or not supported, " - "p_frame %p, linesize %p, video_width %d, video_height %d\n", - __func__, p_frame, linesize, video_width, video_height); + "p_frame %p, linesize %p, data %p\n", + __func__, p_frame, linesize, data); return NI_RETCODE_INVALID_PARAM; } - if (QUADRA) + ni_log(NI_LOG_DEBUG, + "%s: resolution=%dx%d linesize=%d/%d/%d " + "data=%p %p %p extra_len=%d\n", + __func__, video_width, video_height, + linesize[0], linesize[1], linesize[2], + data[0], data[1], data[2], extra_len); + + if (p_frame->buffer_size) { - height_aligned = ((video_height + 1) / 2) * 2; + p_frame->buffer_size = 0; //notify p_frame->p_buffer is not allocated + ni_aligned_free(p_frame->p_buffer); // also free the temp p_buffer allocated for niFrameSurface1_t in encoder init stage + } + + p_frame->p_buffer = (uint8_t *)data[0]; + p_frame->p_data[0] = (uint8_t *)data[0]; + p_frame->p_data[1] = (uint8_t *)data[1]; + p_frame->p_data[2] = (uint8_t *)data[2]; + + int luma_size = linesize[0] * video_height; + int chroma_b_size = 0; + int chroma_r_size = 0; + + // gstreamer assigns stride length to linesize[0] linesize[1] linesize[2] for RGBA pixel format, but only data[0] pointer is populated + if (data[1]) // cb size is 0 for RGBA pixel format + chroma_b_size = linesize[1] * (video_height / 2); + + if (data[2]) // cr size is 0 for semi-planar or RGBA pixel format + chroma_r_size = linesize[2] * (video_height / 2); + + //ni_log(NI_LOG_DEBUG, "%s: luma_size=%d chroma_b_size=%d chroma_r_size=%d\n", __func__, luma_size, chroma_b_size, chroma_r_size); + + uint32_t start_offset; + uint32_t total_start_len = 0; + int i; + + p_frame->inconsecutive_transfer = 0; + + // rgba has one data pointer, semi-planar has two data pointers + if ((data[1] && (data[0] + luma_size != data[1])) + || (data[2] && (data[1] + chroma_b_size != data[2]))) + { + p_frame->inconsecutive_transfer = 1; + } + + if (p_frame->inconsecutive_transfer) + { + for (i = 0; i < NI_MAX_NUM_SW_FRAME_DATA_POINTERS; i++) + { + start_offset = (uintptr_t)p_frame->p_data[i] % NI_MEM_PAGE_ALIGNMENT; + p_frame->start_len[i] = start_offset ? (NI_MEM_PAGE_ALIGNMENT - start_offset) : 0; + total_start_len += p_frame->start_len[i]; + } + } + else + { + start_offset = (uintptr_t)p_frame->p_data[0] % NI_MEM_PAGE_ALIGNMENT; + p_frame->start_len[0] = start_offset ? (NI_MEM_PAGE_ALIGNMENT - start_offset) : 0; + p_frame->start_len[1] = p_frame->start_len[2] = 0; + total_start_len = p_frame->start_len[0]; + } + p_frame->total_start_len = total_start_len; + + if (ni_encoder_metadata_buffer_alloc(p_frame, extra_len)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate p_metadata_buffer buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + p_frame->separate_metadata = 1; + + if (total_start_len) + { + if (ni_encoder_start_buffer_alloc(p_frame)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate p_start_buffer buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + p_frame->separate_start = 1; + + // copy non-4k-aligned part at the start of YUV data + int start_buffer_offset = 0; + for (i = 0; i < NI_MAX_NUM_SW_FRAME_DATA_POINTERS; i++) + { + if (p_frame->p_data[i]) + { + memcpy(p_frame->p_start_buffer+start_buffer_offset, p_frame->p_data[i], + p_frame->start_len[i]); + start_buffer_offset += p_frame->start_len[i]; + } + } + } + + p_frame->data_len[0] = luma_size; + p_frame->data_len[1] = chroma_b_size; + p_frame->data_len[2] = chroma_r_size; + p_frame->data_len[3] = 0;//unused by hwdesc + + p_frame->video_width = video_width; + p_frame->video_height = video_height; + + ni_log(NI_LOG_DEBUG, + "%s: success: p_metadata_buffer %p metadata_buffer_size %u " + "p_start_buffer %p start_buffer_size %u data_len %u %u %u\n", + __func__, p_frame->p_metadata_buffer, p_frame->metadata_buffer_size, + p_frame->p_start_buffer, p_frame->start_buffer_size, + p_frame->data_len[0], p_frame->data_len[1], p_frame->data_len[2]); + +END: + + return retval; +} + + +/*!***************************************************************************** + * \brief Check if incoming frame is hwupload zero copy compatible or not + * + * \param[in] p_upl_ctx pointer to uploader context + * [in] width input width + * [in] height input height + * [in] linesize input linesizes (pointer to array) + * [in] pixel_format input pixel format + * + * \return on success and can do zero copy + * NI_RETCODE_SUCCESS + * + * cannot do zero copy + * NI_RETCODE_ERROR_UNSUPPORTED_FEATURE + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_INVALID_PARAM + * +*******************************************************************************/ +ni_retcode_t ni_uploader_frame_zerocopy_check(ni_session_context_t *p_upl_ctx, + int width, int height, + const int linesize[], int pixel_format) +{ + // check pixel format / width / height / linesize can be supported + if ((!p_upl_ctx) || (!linesize) + || (linesize[0]<=0) || (linesize[0]>NI_MAX_RESOLUTION_LINESIZE) + || (width>NI_MAX_RESOLUTION_WIDTH) || (width<=0) + || (height>NI_MAX_RESOLUTION_HEIGHT) || (height<=0)) + { + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "%s passed parameters are null or not supported, " + "p_enc_ctx %p, linesize %p, " + "width %d, height %d linesize[0] %d\n", + __func__, p_upl_ctx, linesize, + width, height, (linesize) ? linesize[0] : 0); + return NI_RETCODE_INVALID_PARAM; + } + + // check fw revision (if fw_rev has been populated in open session) + if (p_upl_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] && + (ni_cmp_fw_api_ver((char*) &p_upl_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6S") < 0)) + { + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "%s: not supported on device with FW API version < 6.S\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + // upload does not have zeroCopyMode parameter, currently only allows resolution >= 1080p + if ((width * height) < NI_NUM_OF_PIXELS_1080P) + return NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + + // check zero copy compatibilty + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "%s pixel_format %d " + "p_upl_ctx %p, linesize %p, " + "width %d, height %d, linesize[0] %d\n", + __func__, pixel_format, p_upl_ctx, linesize, + width, height, linesize[0]); + + int bit_depth_factor; + bool isrgba = false; + bool isplanar = false; + bool issemiplanar = false; + + switch (pixel_format) + { + case NI_PIX_FMT_YUV420P: + isplanar = true; + bit_depth_factor = 1; + break; + case NI_PIX_FMT_YUV420P10LE: + isplanar = true; + bit_depth_factor = 2; + break; + case NI_PIX_FMT_NV12: + issemiplanar = true; + bit_depth_factor = 1; + break; + case NI_PIX_FMT_P010LE: + issemiplanar = true; + bit_depth_factor = 2; + break; + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + isrgba = true; + bit_depth_factor = 4; // not accurate, only for linesize check + break; + default: + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "%s: pixel_format %d not supported\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + } + + // check fw revision (if fw_rev has been populated in open session) + if (issemiplanar && + p_upl_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] && + (ni_cmp_fw_api_ver((char*) &p_upl_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6q") < 0)) + { + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "%s: semi-planar not supported on device with FW API version < 6.q\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + int max_linesize = isrgba ? (NI_MAX_RESOLUTION_RGBA_WIDTH*4) : NI_MAX_RESOLUTION_LINESIZE; + if (linesize[0] <= max_linesize && + width % 2 == 0 && //even width + height % 2 == 0 && //even height + width >= NI_MIN_WIDTH && height >= NI_MIN_HEIGHT) + { + // yuv only support default 128 bytes aligned linesize, because downstream filter or encoder expect HW frame 128 bytes aligned + if (isplanar && + linesize[0] == NI_VPU_ALIGN128(width * bit_depth_factor) && + linesize[1] == NI_VPU_ALIGN128(width * bit_depth_factor / 2) && + linesize[2] == linesize[1]) + return NI_RETCODE_SUCCESS; + + // yuv only support default 128 bytes aligned linesize, because downstream filter or encoder expect HW frame 128 bytes aligned + if (issemiplanar && + linesize[0] == NI_VPU_ALIGN128(width * bit_depth_factor) && + linesize[1] == linesize[0]) + return NI_RETCODE_SUCCESS; + + // rgba only support 64 bytes aligned for 2D + if (isrgba && + linesize[0] == NI_VPU_ALIGN64(width * bit_depth_factor)) + return NI_RETCODE_SUCCESS; + } + + return NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; +} + +/*!***************************************************************************** + * \brief Allocate memory for the frame buffer for encoding based on given + * parameters, taking into account pic line size and extra data. + * Applicable to YUV420p AVFrame only. 8 or 10 bit/pixel. + * Cb/Cr size matches that of Y. + * + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct + * + * \param[in] video_width Width of the video frame + * \param[in] video_height Height of the video frame + * \param[in] linesize Picture line size + * \param[in] alignment Allignment requirement + * \param[in] extra_len Extra data size (incl. meta data). < 0 means not + * to allocate any buffer (zero-copy from existing) + * \param[in] alignment_2pass_wa set alignment to work with 2pass encode + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + *****************************************************************************/ +ni_retcode_t ni_encoder_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, + int video_height, int linesize[], + int alignment, int extra_len, + bool alignment_2pass_wa) +{ + void* p_buffer = NULL; + int height_aligned; + int retval = NI_RETCODE_SUCCESS; + + if ((!p_frame) || (!linesize) || (linesize[0]<=0) || (linesize[0]>NI_MAX_RESOLUTION_LINESIZE) + || (video_width>NI_MAX_RESOLUTION_WIDTH) || (video_width<=0) + || (video_height>NI_MAX_RESOLUTION_HEIGHT) || (video_height<=0)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s passed parameters are null or not supported, " + "p_frame %p, linesize %p, video_width %d, video_height %d\n", + __func__, p_frame, linesize, video_width, video_height); + return NI_RETCODE_INVALID_PARAM; + } + + if (QUADRA) + { + height_aligned = ((video_height + 1) / 2) * 2; } else { - // TBD height has to be 8-aligned; had a checking at codec opening, but - // if still getting non-8-aligned here, that could only be the case of - // resolution change mid-stream: device_handle it by making them 8-aligned height_aligned = ((video_height + 7) / 8) * 8; if (alignment) @@ -2337,7 +3171,7 @@ ni_retcode_t ni_encoder_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, p_frame->p_data[2] = (uint8_t*)p_frame->p_data[1] + chroma_b_size; } else - { + { p_frame->buffer_size = 0; //no ownership } @@ -2376,7 +3210,7 @@ ni_retcode_t ni_scaler_dest_frame_alloc(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface) { int ret = 0; - if (scaler_params.op != NI_SCALER_OPCODE_OVERLAY) + if (scaler_params.op != NI_SCALER_OPCODE_OVERLAY && scaler_params.op != NI_SCALER_OPCODE_WATERMARK) { ret = ni_device_alloc_frame( p_ctx, scaler_params.output_width, scaler_params.output_height, @@ -2431,8 +3265,6 @@ ni_retcode_t ni_scaler_input_frame_alloc(ni_session_context_t *p_ctx, ni_retcode_t ni_scaler_frame_pool_alloc(ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params) { - int pool_size = 1; // set to 1 for this demo - int rc = 0; int options = NI_SCALER_FLAG_IO | NI_SCALER_FLAG_PC; if (p_ctx->isP2P) @@ -2446,7 +3278,7 @@ ni_retcode_t ni_scaler_frame_pool_alloc(ni_session_context_t *p_ctx, 0, // rec height 0, // rec X pos 0, // rec Y pos - pool_size, // rgba color/pool size + NI_MAX_FILTER_POOL_SIZE, // rgba color/pool size 0, // frame index NI_DEVICE_TYPE_SCALER); return rc; @@ -2672,14 +3504,36 @@ ni_retcode_t ni_frame_buffer_free(ni_frame_t* p_frame) } #endif - ni_aligned_free(p_frame->p_buffer); - p_frame->buffer_size = 0; + if (p_frame->buffer_size) + { + p_frame->buffer_size = 0; + ni_aligned_free(p_frame->p_buffer); + } + for (i = 0; i < NI_MAX_NUM_DATA_POINTERS; i++) { p_frame->data_len[i] = 0; p_frame->p_data[i] = NULL; } + ni_frame_wipe_aux_data(p_frame); + + if (p_frame->metadata_buffer_size) + { + p_frame->metadata_buffer_size = 0; + ni_aligned_free(p_frame->p_metadata_buffer); + } + p_frame->separate_metadata = 0; + + if (p_frame->start_buffer_size) + { + p_frame->start_buffer_size = 0; + ni_aligned_free(p_frame->p_start_buffer); + } + p_frame->separate_start = 0; + memset(p_frame->start_len, 0, sizeof(p_frame->start_len)); + p_frame->total_start_len = 0; + p_frame->inconsecutive_transfer = 0; END: @@ -3078,7 +3932,8 @@ ni_aux_data_t *ni_frame_new_aux_data(ni_frame_t *frame, ni_aux_data_type_t type, if (!ret->data) { ni_log(NI_LOG_ERROR, "ERROR: %s No memory for aux data !\n", __func__); - ni_aligned_free(ret); + free(ret); + ret = NULL; } else { frame->aux_data[frame->nb_aux_data++] = ret; @@ -3154,8 +4009,8 @@ void ni_frame_free_aux_data(ni_frame_t *frame, ni_aux_data_type_t type) frame->aux_data[i] = frame->aux_data[frame->nb_aux_data - 1]; frame->aux_data[frame->nb_aux_data - 1] = NULL; frame->nb_aux_data--; - ni_aligned_free(aux->data); - ni_aligned_free(aux); + free(aux->data); + free(aux); } } } @@ -3175,8 +4030,8 @@ void ni_frame_wipe_aux_data(ni_frame_t *frame) for (i = 0; i < frame->nb_aux_data; i++) { aux = frame->aux_data[i]; - ni_aligned_free(aux->data); - ni_aligned_free(aux); + free(aux->data); + free(aux); } frame->nb_aux_data = 0; } @@ -3235,8 +4090,7 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, else p_enc->gop_preset_index = GOP_PRESET_IDX_IBBBP; - p_enc->use_recommend_enc_params = - 0; // TBD: remove this param from API as it is revA specific + p_enc->use_recommend_enc_params = 0; p_enc->cu_size_mode = 7; p_enc->max_num_merge = 2; p_enc->enable_dynamic_8x8_merge = 1; @@ -3258,13 +4112,20 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_enc->rc.max_delta_qp = 10; // hrd is disabled if vbv_buffer_size=0, hrd is enabled if vbv_buffer_size is [10, 3000] - p_enc->rc.vbv_buffer_size = 3000; + p_enc->rc.vbv_buffer_size = -1; p_enc->rc.enable_filler = 0; p_enc->rc.enable_pic_skip = 0; + p_enc->rc.vbv_max_rate = 0; p_enc->roi_enable = 0; p_enc->forced_header_enable = NI_ENC_REPEAT_HEADERS_ALL_I_FRAMES; + // feature not supported on JPEG/AV1 - disable by default + if (codec_format == NI_CODEC_FORMAT_JPEG || + codec_format == NI_CODEC_FORMAT_AV1) + { + p_enc->forced_header_enable = NI_ENC_REPEAT_HEADERS_FIRST_IDR; + } p_enc->long_term_ref_enable = 0; p_enc->long_term_ref_interval = 0; @@ -3278,7 +4139,6 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_enc->intra_period = 120; p_enc->rc.intra_qp = 22; p_enc->rc.intra_qp_delta = -2; - // TBD Rev. B: could be shared for HEVC and H.264 ? if (QUADRA) p_enc->rc.enable_mb_level_rc = 0; else @@ -3286,14 +4146,16 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_enc->decoding_refresh_type = 1; + p_enc->slice_mode = 0; + p_enc->slice_arg = 0; + // Rev. B: H.264 only parameters. p_enc->enable_transform_8x8 = 1; - p_enc->avc_slice_mode = 0; - p_enc->avc_slice_arg = 0; p_enc->entropy_coding_mode = 1; p_enc->intra_mb_refresh_mode = 0; p_enc->intra_mb_refresh_arg = 0; + p_enc->intra_reset_refresh = 0; p_enc->custom_gop_params.custom_gop_size = 0; #ifndef QUADRA @@ -3326,7 +4188,7 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, for (j = 0; j < NI_MAX_REF_PIC; j++) { p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic = 0; - p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic_used = 0; + p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic_used = -1; } } } @@ -3358,6 +4220,10 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_param->generate_enc_hdrs = 0; p_param->use_low_delay_poc_type = 0; p_param->rootBufId = 0; + p_param->staticMmapThreshold = 0; + p_param->zerocopy_mode = 1; + p_param->luma_linesize = 0; + p_param->chroma_linesize = 0; p_enc->preferred_transfer_characteristics = -1; @@ -3371,10 +4237,14 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_param->sar_denom = 1; // default SAR denominator 1 p_param->video_full_range_flag = -1; + p_param->enable2PassGop = 0; + p_param->ddr_priority_mode = NI_DDR_PRIORITY_NONE; + p_param->minFramesDelay = 0; + //QUADRA p_enc->EnableAUD = 0; p_enc->lookAheadDepth = 0; - p_enc->rdoLevel = 1; + p_enc->rdoLevel = (codec_format == NI_CODEC_FORMAT_JPEG) ? 0 : 1; p_enc->crf = -1; p_enc->HDR10MaxLight = 0; p_enc->HDR10AveLight = 0; @@ -3392,6 +4262,7 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_enc->multicoreJointMode = 0; p_enc->qlevel = -1; p_enc->maxFrameSize = 0; + p_enc->maxFrameSizeRatio = 0; p_enc->chromaQpOffset = 0; p_enc->tolCtbRcInter = (float)0.1; p_enc->tolCtbRcIntra = (float)0.1; @@ -3399,10 +4270,61 @@ ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, p_enc->inLoopDSRatio = 1; p_enc->blockRCSize = 0; p_enc->rcQpDeltaRange = 10; + p_enc->ctbRowQpStep = 0; + p_enc->newRcEnable = -1; + p_enc->colorDescPresent = 0; + p_enc->colorPrimaries = 2; + p_enc->colorTrc = 2; + p_enc->colorSpace = 2; p_enc->aspectRatioWidth = 0; p_enc->aspectRatioHeight = 1; + p_enc->videoFullRange = 0; p_enc->keep_alive_timeout = NI_DEFAULT_KEEP_ALIVE_TIMEOUT; p_enc->enable_ssim = 0; + p_enc->HDR10Enable = 0; + p_enc->HDR10dx0 = 0; + p_enc->HDR10dy0 = 0; + p_enc->HDR10dx1 = 0; + p_enc->HDR10dy1 = 0; + p_enc->HDR10dx2 = 0; + p_enc->HDR10dy2 = 0; + p_enc->HDR10wx = 0; + p_enc->HDR10wy = 0; + p_enc->HDR10maxluma = 0; + p_enc->HDR10minluma = 0; + p_enc->av1_error_resilient_mode = 0; + p_enc->temporal_layers_enable = 0; + p_enc->crop_width = 0; + p_enc->crop_height = 0; + p_enc->hor_offset = 0; + p_enc->ver_offset = 0; + p_enc->crfMax = -1; + p_enc->qcomp = (float)0.6; + p_enc->noMbtree = 0; + p_enc->noHWMultiPassSupport = 0; + p_enc->cuTreeFactor = 5; + p_enc->ipRatio = (float)1.4; + p_enc->pbRatio = (float)1.3; + p_enc->cplxDecay = (float)0.5; + p_enc->pps_init_qp = -1; + p_enc->bitrateMode = -1; // -1 = not set, bitrateMode 0 = max bitrate (actual bitrate can be lower than bitrate), bitrateMode 1 = average bitrate (actual bitrate approximately equal to bitrate) + p_enc->pass1_qp = -1; + p_enc->crfFloat = -1.0f; + p_enc->hvsBaseMbComplexity = 15; + p_enc->statistic_output_level = 0; + p_enc->skip_frame_enable = 0; + p_enc->max_consecutive_skip_num = 1; + p_enc->skip_frame_interval = 0; + p_enc->enableipRatio = 0; + p_enc->enable_all_sei_passthru = 0; + p_enc->iframe_size_ratio = 100; + p_enc->crf_max_iframe_enable = 0; + p_enc->vbv_min_rate = 0; + p_enc->disable_adaptive_buffers = 0; + p_enc->disableBframeRdoq = 0; + p_enc->forceBframeQpfactor = (float)-1.0; + p_enc->tune_bframe_visual = 0; + p_enc->enable_acq_limit = 0; if (codec_format == NI_CODEC_FORMAT_AV1) { @@ -3536,6 +4458,13 @@ ni_retcode_t ni_decoder_init_default_params(ni_xcoder_params_t *p_param, p_param->source_width = width; p_param->source_height = height; + if(fps_num <= 0 || fps_denom <= 0) + { + fps_num = 30; + fps_denom = 1; + ni_log(NI_LOG_INFO, "%s(): FPS is not set, setting the default FPS to 30\n", __func__); + } + p_param->fps_number = fps_num; p_param->fps_denominator = fps_denom; @@ -3555,10 +4484,28 @@ ni_retcode_t ni_decoder_init_default_params(ni_xcoder_params_t *p_param, p_dec->crop_whxy[i][3] = 0; p_dec->scale_wh[i][0] = 0; p_dec->scale_wh[i][1] = 0; - + p_dec->scale_long_short_edge[i] = 0; + p_dec->scale_resolution_ceil[i] = 2; + p_dec->scale_round[i] = -1; } p_dec->keep_alive_timeout = NI_DEFAULT_KEEP_ALIVE_TIMEOUT; p_dec->decoder_low_delay = 0; + p_dec->force_low_delay = false; + p_dec->enable_low_delay_check = 0; + p_dec->enable_user_data_sei_passthru = 0; + p_dec->custom_sei_passthru = -1; + p_dec->svct_decoding_layer = NI_INVALID_SVCT_DECODING_LAYER; + p_dec->ec_policy = NI_EC_POLICY_DEFAULT; + p_dec->enable_advanced_ec = 1; + p_dec->enable_ppu_scale_adapt = 0; + p_dec->enable_ppu_scale_limit = 0; + p_dec->max_extra_hwframe_cnt = 255; //uint8_max + p_dec->pkt_pts_unchange = 0; + p_dec->enable_all_sei_passthru = 0; + p_dec->min_packets_delay = false; + p_dec->enable_follow_iframe = 0; + p_param->ddr_priority_mode = NI_DDR_PRIORITY_NONE; + p_dec->disable_adaptive_buffers = 0; //-------init unused param start---------- @@ -3591,7 +4538,8 @@ ni_retcode_t ni_decoder_init_default_params(ni_xcoder_params_t *p_param, // read demo reconfig data file and parse out reconfig key/values in the format: // key:val1,val2,val3,...val9 (max 9 values); only digit/:/,/newline is allowed -ni_retcode_t ni_parse_reconf_file(const char* reconf_file, int hash_map[100][10]) +ni_retcode_t ni_parse_reconf_file(const char *reconf_file, + int hash_map[][NI_BITRATE_RECONFIG_FILE_MAX_ENTRIES_PER_LINE]) { char keyChar[10] = ""; int key; @@ -3617,6 +4565,7 @@ ni_retcode_t ni_parse_reconf_file(const char* reconf_file, int hash_map[100][10] NI_ERRNO, __func__, reconf_file); return NI_RETCODE_PARAM_INVALID_VALUE; } + ni_retcode_t retval = NI_RETCODE_SUCCESS; while ((readc = fgetc(reconf)) != EOF) { @@ -3640,6 +4589,15 @@ ni_retcode_t ni_parse_reconf_file(const char* reconf_file, int hash_map[100][10] } else if (readc == ',') { + if (valIdx >= NI_BITRATE_RECONFIG_FILE_MAX_ENTRIES_PER_LINE) + { + ni_log(NI_LOG_ERROR, + "ERROR: Number of entries per line in reconfig file is greater then the " + "limit of %d\n", + NI_BITRATE_RECONFIG_FILE_MAX_ENTRIES_PER_LINE); + retval = NI_RETCODE_INVALID_PARAM; + break; + } val = atoi(valChar); hash_map[idx][valIdx] = val; valIdx++; @@ -3647,6 +4605,15 @@ ni_retcode_t ni_parse_reconf_file(const char* reconf_file, int hash_map[100][10] } else if (readc == '\n') { + if (idx >= NI_BITRATE_RECONFIG_FILE_MAX_LINES) + { + ni_log(NI_LOG_ERROR, + "ERROR: Number of lines in reconfig file is greater then the " + "limit of %d\n", + NI_BITRATE_RECONFIG_FILE_MAX_LINES); + retval = NI_RETCODE_INVALID_PARAM; + break; + } parseKey = 1; val = atoi (valChar); hash_map[idx][valIdx] = val; @@ -3663,7 +4630,7 @@ ni_retcode_t ni_parse_reconf_file(const char* reconf_file, int hash_map[100][10] fclose(reconf); - if (parseKey != 1) + if (NI_RETCODE_SUCCESS == retval && parseKey != 1) { ni_log(NI_LOG_ERROR, "ERROR %d: %s(): Incorrect format / " @@ -3672,7 +4639,7 @@ ni_retcode_t ni_parse_reconf_file(const char* reconf_file, int hash_map[100][10] return NI_RETCODE_PARAM_ERROR_ZERO; } - return NI_RETCODE_SUCCESS; + return retval; } @@ -3702,7 +4669,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, bool b_error = false; bool bNameWasBool = false; bool bValueWasNull = !value; - ni_decoder_input_params_t* p_dec = &p_params->dec_input_params; + ni_decoder_input_params_t* p_dec = NULL; char nameBuf[64] = { 0 }; const char delim[2] = ","; const char xdelim[2] = "x"; @@ -3713,54 +4680,44 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, if (!p_params) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Null pointer parameters passed\n", - __func__); - return NI_RETCODE_INVALID_PARAM; + ni_log(NI_LOG_ERROR, "ERROR: %s(): Null pointer parameters passed\n", + __func__); + return NI_RETCODE_INVALID_PARAM; } if (!name) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Null name pointer parameters passed\n", - __func__); - return NI_RETCODE_PARAM_INVALID_NAME; + ni_log(NI_LOG_ERROR, "ERROR: %s(): Null name pointer parameters passed\n", + __func__); + return NI_RETCODE_PARAM_INVALID_NAME; } + p_dec = &p_params->dec_input_params; // skip -- prefix if provided if (name[0] == '-' && name[1] == '-') { - name += 2; + name += 2; } // s/_/-/g if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name, '_')) { - char* c; - strcpy(nameBuf, name); - while ((c = strchr(nameBuf, '_')) != 0) - { - *c = '-'; - } - - name = nameBuf; + char* c; + strcpy(nameBuf, name); + while ((c = strchr(nameBuf, '_')) != 0) + { + *c = '-'; + } + name = nameBuf; } - if (!strncmp(name, "no-", 3)) - { - name += 3; - value = !value || ni_atobool(value, &b_error) ? "false" : "true"; - } - else if (!strncmp(name, "no", 2)) - { - name += 2; - value = !value || ni_atobool(value, &b_error) ? "false" : "true"; - } - else if (!value) + if (!value) { - value = "true"; + value = "true"; } else if (value[0] == '=') { - value++; + value++; } #if defined(_MSC_VER) @@ -3771,14 +4728,13 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, #define OPT(STR) else if (!strcasecmp(name, STR)) #define OPT2(STR1, STR2) else if (!strcasecmp(name, STR1) || !strcasecmp(name, STR2)) #endif - if (0) - ; + if (0); // suppress cppcheck OPT(NI_DEC_PARAM_OUT) { - if (!strncmp(value, "hw", 2)){ + if (!strncmp(value, "hw", sizeof("hw"))){ p_dec->hwframes = 1; } - else if (!strncmp(value, "sw", 2)) { + else if (!strncmp(value, "sw", sizeof("sw"))) { p_dec->hwframes = 0; } else{ @@ -3814,32 +4770,27 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_SEMI_PLANAR_0) { - if (atoi(value) == 1) - p_dec->semi_planar[0] = 1; + if (atoi(value) == 1 || atoi(value) == 2) + p_dec->semi_planar[0] = atoi(value); } OPT(NI_DEC_PARAM_SEMI_PLANAR_1) { - if (atoi(value) == 1) - p_dec->semi_planar[1] = 1; + if (atoi(value) == 1 || atoi(value) == 2) + p_dec->semi_planar[1] = atoi(value); } OPT(NI_DEC_PARAM_SEMI_PLANAR_2) { - if (atoi(value) == 1) - p_dec->semi_planar[2] = 1; + if (atoi(value) == 1 || atoi(value) == 2) + p_dec->semi_planar[2] = atoi(value); } OPT(NI_DEC_PARAM_CROP_MODE_0) { - if (!strncmp(value, "manual", 6)) { + if (!strncmp(value, "manual", sizeof("manual"))) { p_dec->crop_mode[0] = NI_DEC_CROP_MODE_MANUAL; } - else if (!strncmp(value, "auto", 4)) { + else if (!strncmp(value, "auto", sizeof("auto"))) { p_dec->crop_mode[0] = NI_DEC_CROP_MODE_AUTO; } -#if 0 - else if (!strncmp(value, "disabled", 8)) { - p_dec->crop_mode[0] = NI_DEC_CROP_MODE_DISABLE; - } -#endif else{ ni_log(NI_LOG_ERROR, "ERROR: %s():cropMode0 input can only be got %s\n", @@ -3849,17 +4800,12 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_CROP_MODE_1) { - if (!strncmp(value, "manual", 6)) { + if (!strncmp(value, "manual", sizeof("manual"))) { p_dec->crop_mode[1] = NI_DEC_CROP_MODE_MANUAL; } - else if (!strncmp(value, "auto", 4)) { + else if (!strncmp(value, "auto", sizeof("auto"))) { p_dec->crop_mode[1] = NI_DEC_CROP_MODE_AUTO; } -#if 0 - else if (!strncmp(value, "disabled", 8)) { - p_dec->crop_mode[1] = NI_DEC_CROP_MODE_DISABLE; - } -#endif else { ni_log(NI_LOG_ERROR, "ERROR: %s():cropMode1 input can only be got %s\n", @@ -3869,17 +4815,12 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_CROP_MODE_2) { - if (!strncmp(value, "manual", 6)) { + if (!strncmp(value, "manual", sizeof("manual"))) { p_dec->crop_mode[2] = NI_DEC_CROP_MODE_MANUAL; } - else if (!strncmp(value, "auto", 4)) { + else if (!strncmp(value, "auto", sizeof("auto"))) { p_dec->crop_mode[2] = NI_DEC_CROP_MODE_AUTO; } -#if 0 - else if (!strncmp(value, "disabled", 8)) { - p_dec->crop_mode[2] = NI_DEC_CROP_MODE_DISABLE; - } -#endif else { ni_log(NI_LOG_ERROR, "ERROR: %s():cropMode2 input can only be got %s\n", @@ -3889,7 +4830,8 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_CROP_PARAM_0) { - chunk = strtok(value, delim); + char *saveptr = NULL; + chunk = ni_strtok(value, delim, &saveptr); for (i = 0; i < 4; i++) { if (chunk != NULL) @@ -3907,7 +4849,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_TOO_BIG; } } - chunk = strtok(NULL, delim); + chunk = ni_strtok(NULL, delim, &saveptr); } else if (i == 2 ) //default offsets to centered image if not specified, may need recalc { @@ -3924,7 +4866,8 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_CROP_PARAM_1) { - chunk = strtok(value, delim); + char *saveptr = NULL; + chunk = ni_strtok(value, delim, &saveptr); for (i = 0; i < 4; i++) { if (chunk != NULL) @@ -3942,7 +4885,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_TOO_BIG; } } - chunk = strtok(NULL, delim); + chunk = ni_strtok(NULL, delim, &saveptr); } else if (i == 2) //default offsets to centered image if not specified, may need recalc { @@ -3961,7 +4904,8 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_CROP_PARAM_2) { - chunk = strtok(value, delim); + char *saveptr = NULL; + chunk = ni_strtok(value, delim, &saveptr); for (i = 0; i < 4; i++) { if (chunk != NULL) @@ -3979,7 +4923,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_TOO_BIG; } } - chunk = strtok(NULL, delim); + chunk = ni_strtok(NULL, delim, &saveptr); } else if (i == 2) //default offsets to centered image if not specified, may need recalc { @@ -4010,7 +4954,8 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } chunk = NULL; - chunk = strtok(value, xdelim); + char *saveptr = NULL; + chunk = ni_strtok(value, xdelim, &saveptr); for (i = 0; i < 2; i++) { if (chunk != NULL) @@ -4028,7 +4973,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_TOO_BIG; } } - chunk = strtok(NULL, xdelim); + chunk = ni_strtok(NULL, xdelim, &saveptr); } else { @@ -4050,7 +4995,8 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } chunk = NULL; - chunk = strtok(value, xdelim); + char *saveptr = NULL; + chunk = ni_strtok(value, xdelim, &saveptr); for (i = 0; i < 2; i++) { if (chunk != NULL) @@ -4068,7 +5014,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_TOO_BIG; } } - chunk = strtok(NULL, xdelim); + chunk = ni_strtok(NULL, xdelim, &saveptr); } else { @@ -4090,7 +5036,8 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } chunk = NULL; - chunk = strtok(value, xdelim); + char *saveptr = NULL; + chunk = ni_strtok(value, xdelim, &saveptr); for (i = 0; i < 2; i++) { if (chunk != NULL) @@ -4108,7 +5055,7 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_TOO_BIG; } } - chunk = strtok(NULL, xdelim); + chunk = ni_strtok(NULL, xdelim, &saveptr); } else { @@ -4116,6 +5063,106 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } } } + OPT(NI_DEC_PARAM_SCALE_0_LONG_SHORT_ADAPT) + { + if ((atoi(value) < 0) || (atoi(value) > 2)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->scale_long_short_edge[0] = atoi(value); + } + OPT(NI_DEC_PARAM_SCALE_1_LONG_SHORT_ADAPT) + { + if ((atoi(value) < 0) || (atoi(value) > 2)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->scale_long_short_edge[1] = atoi(value); + } + OPT(NI_DEC_PARAM_SCALE_2_LONG_SHORT_ADAPT) + { + if ((atoi(value) < 0) || (atoi(value) > 2)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->scale_long_short_edge[2] = atoi(value); + } + OPT(NI_DEC_PARAM_SCALE_0_RES_CEIL) + { + if (atoi(value) < 2 || atoi(value) % 2 != 0 || atoi(value) > 128) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): %s must be greater than or equal to 2 " + "and must be even number and less than or equal to 128. Got: %s\n", + __func__, NI_DEC_PARAM_SCALE_0_RES_CEIL, value); + + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->scale_resolution_ceil[0] = atoi(value); + } + OPT(NI_DEC_PARAM_SCALE_1_RES_CEIL) + { + if (atoi(value) < 2 || atoi(value) % 2 != 0 || atoi(value) > 128) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): %s must be greater than or equal to 2 " + "and must be even number and less than or equal to 128. Got: %s\n", + __func__, NI_DEC_PARAM_SCALE_1_RES_CEIL, value); + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->scale_resolution_ceil[1] = atoi(value); + } + OPT(NI_DEC_PARAM_SCALE_2_RES_CEIL) + { + if (atoi(value) < 2 || atoi(value) % 2 != 0 || atoi(value) > 128) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): %s must be greater than or equal to 2 " + "and must be even number and less than or equal to 128. Got: %s\n", + __func__, NI_DEC_PARAM_SCALE_2_RES_CEIL, value); + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->scale_resolution_ceil[2] = atoi(value); + } + OPT(NI_DEC_PARAM_SCALE_0_ROUND) + { + if (!strncmp(value, "up", sizeof("up"))){ + p_dec->scale_round[0] = 0; + } + else if (!strncmp(value, "down", sizeof("down"))) { + p_dec->scale_round[0] = 1; + } + else{ + ni_log(NI_LOG_ERROR, "ERROR: %s(): %s can only be {up, down}. Got: %s\n", + __func__, NI_DEC_PARAM_SCALE_0_ROUND, value); + return NI_RETCODE_PARAM_INVALID_VALUE; + } + } + OPT(NI_DEC_PARAM_SCALE_1_ROUND) + { + if (!strncmp(value, "up", sizeof("up"))){ + p_dec->scale_round[1] = 0; + } + else if (!strncmp(value, "down", sizeof("down"))) { + p_dec->scale_round[1] = 1; + } + else{ + ni_log(NI_LOG_ERROR, "ERROR: %s(): %s can only be {up, down}. Got: %s\n", + __func__, NI_DEC_PARAM_SCALE_1_ROUND, value); + return NI_RETCODE_PARAM_INVALID_VALUE; + } + } + OPT(NI_DEC_PARAM_SCALE_2_ROUND) + { + if (!strncmp(value, "up", sizeof("up"))){ + p_dec->scale_round[2] = 0; + } + else if (!strncmp(value, "down", sizeof("down"))) { + p_dec->scale_round[2] = 1; + } + else{ + ni_log(NI_LOG_ERROR, "ERROR: %s(): %s can only be {up, down}. Got: %s\n", + __func__, NI_DEC_PARAM_SCALE_2_ROUND, value); + return NI_RETCODE_PARAM_INVALID_VALUE; + } + } OPT(NI_DEC_PARAM_MULTICORE_JOINT_MODE) { if ((atoi(value) != 0) && (atoi(value) != 1)) @@ -4143,26 +5190,174 @@ ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_DEC_PARAM_LOW_DELAY) { - if ((atoi(value) != 0) && - (atoi(value) != 1)) + if (atoi(value) < 0) { return NI_RETCODE_PARAM_ERROR_OOR; } p_dec->decoder_low_delay = atoi(value); } - else + OPT(NI_DEC_PARAM_FORCE_LOW_DELAY) { - return NI_RETCODE_PARAM_INVALID_NAME; + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->force_low_delay = atoi(value); } - -#undef OPT -#undef atobool -#undef atoi -#undef atof - b_error |= bValueWasNull && !bNameWasBool; - - ni_log(NI_LOG_TRACE, "%s: exit, b_error=%d\n", __func__, b_error); - + OPT(NI_DEC_PARAM_ENABLE_LOW_DELAY_CHECK) + { + if (atoi(value) < 0) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_low_delay_check = atoi(value); + } + OPT(NI_DEC_PARAM_MIN_PACKETS_DELAY) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->min_packets_delay = atoi(value); + } + OPT(NI_DEC_PARAM_ENABLE_USR_DATA_SEI_PASSTHRU) + { + if (atoi(value) != NI_ENABLE_USR_DATA_SEI_PASSTHRU && + atoi(value) != NI_DISABLE_USR_DATA_SEI_PASSTHRU) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_user_data_sei_passthru = atoi(value); + } + OPT(NI_DEC_PARAM_ENABLE_CUSTOM_SEI_PASSTHRU) + { + if (atoi(value) < NI_MIN_CUSTOM_SEI_PASSTHRU || + atoi(value) > NI_MAX_CUSTOM_SEI_PASSTHRU) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->custom_sei_passthru = atoi(value); + } + OPT(NI_DEC_PARAM_SVC_T_DECODING_LAYER) + { + if (atoi(value) < NI_INVALID_SVCT_DECODING_LAYER) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->svct_decoding_layer = atoi(value); + } + OPT(NI_DEC_PARAM_DDR_PRIORITY_MODE) + { + if (atoi(value) >= NI_DDR_PRIORITY_MAX || + atoi(value) <= NI_DDR_PRIORITY_NONE) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->ddr_priority_mode = atoi(value); + } + OPT(NI_DEC_PARAM_EC_POLICY) + { + if (strncmp(value, "tolerant", sizeof("tolerant")) == 0) { + p_dec->ec_policy = NI_EC_POLICY_TOLERANT; + } else if (strncmp(value, "ignore", sizeof("ignore")) == 0) { + p_dec->ec_policy = NI_EC_POLICY_IGNORE; + } else if (strncmp(value, "skip", sizeof("skip")) == 0) { + p_dec->ec_policy = NI_EC_POLICY_SKIP; + } else if (strncmp(value, "best_effort", sizeof("best_effort")) == 0) { + p_dec->ec_policy = NI_EC_POLICY_BEST_EFFORT; + } else { + return NI_RETCODE_PARAM_INVALID_VALUE; + } + } + OPT(NI_DEC_PARAM_ENABLE_ADVANCED_EC) + { + if (atoi(value) != 0 && + atoi(value) != 1 && + atoi(value) != 2) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_advanced_ec = atoi(value); + } + OPT(NI_DEC_PARAM_ENABLE_PPU_SCALE_ADAPT) + { + if (atoi(value) < 0 || (atoi(value) > 2)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_ppu_scale_adapt = atoi(value); + } + OPT(NI_DEC_PARAM_ENABLE_PPU_SCALE_LIMIT) + { + if (atoi(value) < 0 || (atoi(value) > 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_ppu_scale_limit = atoi(value); + } + OPT(NI_DEC_PARAM_MAX_EXTRA_HW_FRAME_CNT) + { + if (atoi(value) < 0 || atoi(value) > 255) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->max_extra_hwframe_cnt = atoi(value); + } + OPT(NI_DEC_PARAM_SKIP_PTS_GUESS) + { + if (atoi(value) < 0 || atoi(value) > 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->skip_pts_guess = atoi(value); + } + OPT(NI_DEC_PARAM_PKT_PTS_UNCHANGE) + { + if (atoi(value) != 0 && atoi(value) != 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->pkt_pts_unchange = atoi(value); + } + OPT(NI_DEC_PARAM_ENABLE_ALL_SEI_PASSTHRU) + { + if (atoi(value) < 0 || + atoi(value) > 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_all_sei_passthru = atoi(value); + } + OPT(NI_DEC_PARAM_ENABLE_FOLLOW_IFRAME) + { + if (atoi(value) != 0 && atoi(value) != 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->enable_follow_iframe = atoi(value); + } + OPT(NI_DEC_PARAM_DISABLE_ADAPTIVE_BUFFERS) + { + if (atoi(value) < 0 || + atoi(value) > 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_dec->disable_adaptive_buffers = atoi(value); + } + else + { + return NI_RETCODE_PARAM_INVALID_NAME; + } + +#undef OPT +#undef atobool +#undef atoi +#undef atof + b_error |= bValueWasNull && !bNameWasBool; + + ni_log(NI_LOG_TRACE, "%s: exit, b_error=%d\n", __func__, b_error); + return b_error ? NI_RETCODE_PARAM_INVALID_VALUE : NI_RETCODE_SUCCESS; } @@ -4192,61 +5387,51 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, bool b_error = false; bool bNameWasBool = false; bool bValueWasNull = !value; - ni_encoder_cfg_params_t *p_enc = &p_params->cfg_enc_params; + ni_encoder_cfg_params_t *p_enc = NULL; char nameBuf[64] = { 0 }; + int i,j,k; ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_params) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Null pointer parameters passed\n", - __func__); - return NI_RETCODE_INVALID_PARAM; + ni_log(NI_LOG_ERROR, "ERROR: %s(): Null pointer parameters passed\n", + __func__); + return NI_RETCODE_INVALID_PARAM; } if ( !name ) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Null name pointer parameters passed\n", - __func__); - return NI_RETCODE_PARAM_INVALID_NAME; + ni_log(NI_LOG_ERROR, "ERROR: %s(): Null name pointer parameters passed\n", + __func__); + return NI_RETCODE_PARAM_INVALID_NAME; } - + p_enc = &p_params->cfg_enc_params; // skip -- prefix if provided if (name[0] == '-' && name[1] == '-') { - name += 2; + name += 2; } // s/_/-/g if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name, '_')) { - char* c; - strcpy(nameBuf, name); - while ((c = strchr(nameBuf, '_')) != 0) - { - *c = '-'; - } - - name = nameBuf; + char* c; + strcpy(nameBuf, name); + while ((c = strchr(nameBuf, '_')) != 0) + { + *c = '-'; + } + name = nameBuf; } - if (!strncmp(name, "no-", 3)) - { - name += 3; - value = !value || ni_atobool(value, &b_error) ? "false" : "true"; - } - else if (!strncmp(name, "no", 2)) - { - name += 2; - value = !value || ni_atobool(value, &b_error) ? "false" : "true"; - } - else if (!value) + if (!value) { - value = "true"; + value = "true"; } else if (value[0] == '=') { - value++; + value++; } #if defined(_MSC_VER) @@ -4262,8 +5447,7 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, { \ return NI_RETCODE_PARAM_ERROR_OOR; \ } - if (0) - ; + if (0); // suppress cppcheck OPT( NI_ENC_PARAM_BITRATE ) { if (AV_CODEC_DEFAULT_BITRATE == p_params->bitrate) @@ -4302,12 +5486,20 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } OPT( NI_ENC_PARAM_LOW_DELAY ) { - if (0 != atoi(value) && 1 != atoi(value)) + if (0 > atoi(value)) { return NI_RETCODE_PARAM_ERROR_OOR; } p_params->low_delay_mode = atoi(value); } + OPT (NI_ENC_PARAM_MIN_FRAMES_DELAY) + { + if (0 != atoi(value) && 1 != atoi(value)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->minFramesDelay = atoi(value); + } OPT( NI_ENC_PARAM_PADDING ) { p_params->padding = atoi(value); @@ -4503,6 +5695,14 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } p_enc->rc.max_delta_qp = atoi(value); } + OPT(NI_ENC_PARAM_CONSTANT_RATE_FACTOR) + { + if ((atoi(value) > 51) || (atoi(value) < -1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->crf = atoi(value); + } OPT( NI_ENC_PARAM_RC_INIT_DELAY ) { p_enc->rc.vbv_buffer_size = atoi(value); @@ -4516,6 +5716,10 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, { p_enc->rc.vbv_buffer_size = atoi(value); } + OPT( NI_ENC_PARAM_VBV_MAXRAE) + { + p_enc->rc.vbv_max_rate = atoi(value); + } OPT( NI_ENC_PARAM_CBR ) { p_enc->rc.enable_filler = atoi(value); @@ -4538,13 +5742,73 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, // Currenly pic skip is supported for low delay gops only - pic skip issues tracked by QDFW-1785/1958 p_enc->rc.enable_pic_skip = atoi(value); } - OPT(NI_ENC_PARAM_MAX_FRAME_SIZE_LOW_DELAY) + OPT2(NI_ENC_PARAM_MAX_FRAME_SIZE_LOW_DELAY, NI_ENC_PARAM_MAX_FRAME_SIZE_BYTES_LOW_DELAY) + { +#ifdef _MSC_VER + if (!_strnicmp(value, "ratio", 5)) +#else + if (!strncasecmp(value, "ratio", 5)) +#endif + { + char value_buf[32] = {0}; + for (i = 0; i < sizeof(value_buf); i++) + { + if (value[i+6] == ']') + { + break; + } + value_buf[i] = value[i+6]; + } + if (i == sizeof(value_buf) || atoi(value_buf) < 0) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + + p_enc->maxFrameSizeRatio = atoi(value_buf); + } + else + { + int size = atoi(value); + if (size < NI_MIN_FRAME_SIZE) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->maxFrameSize = (size > NI_MAX_FRAME_SIZE) ? NI_MAX_FRAME_SIZE : size; + } + } + OPT(NI_ENC_PARAM_MAX_FRAME_SIZE_BITS_LOW_DELAY) { - if (atoi(value) < NI_MIN_FRAME_SIZE) +#ifdef _MSC_VER + if (!_strnicmp(value, "ratio", 5)) +#else + if (!strncasecmp(value, "ratio", 5)) +#endif { - return NI_RETCODE_PARAM_ERROR_OOR; + char value_buf[32] = {0}; + for (i = 0; i < sizeof(value_buf); i++) + { + if (value[i+6] == ']') + { + break; + } + value_buf[i] = value[i+6]; + } + if (i == sizeof(value_buf) || atoi(value_buf) < 0) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + + p_enc->maxFrameSizeRatio = atoi(value_buf); + } + else + { + int size = atoi(value) / 8; + if (size < NI_MIN_FRAME_SIZE) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->maxFrameSize = (size > NI_MAX_FRAME_SIZE) ? NI_MAX_FRAME_SIZE : size; } - p_enc->maxFrameSize = (atoi(value) > NI_MAX_FRAME_SIZE) ? NI_MAX_FRAME_SIZE : atoi(value); } OPT ( NI_ENC_PARAM_FORCED_HEADER_ENABLE ) { @@ -4649,6 +5913,14 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } p_enc->decoding_refresh_type = atoi(value); } + OPT(NI_ENC_PARAM_INTRA_REFRESH_RESET) + { + if (0 != atoi(value) && 1 != atoi(value)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->intra_reset_refresh = atoi(value); + } // Rev. B: H.264 only parameters. OPT( NI_ENC_PARAM_ENABLE_8X8_TRANSFORM ) { @@ -4658,17 +5930,17 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } p_enc->enable_transform_8x8 = atoi(value); } - OPT( NI_ENC_PARAM_AVC_SLICE_MODE ) + OPT( NI_ENC_PARAM_SLICE_MODE ) { - if (QUADRA) + if ((atoi(value) > NI_MAX_BIN) || (atoi(value) < NI_MIN_BIN)) { - return NI_RETCODE_PARAM_WARNING_DEPRECATED; + return NI_RETCODE_PARAM_ERROR_OOR; } - p_enc->avc_slice_mode = atoi(value); + p_enc->slice_mode = atoi(value); } - OPT( NI_ENC_PARAM_AVC_SLICE_ARG ) + OPT( NI_ENC_PARAM_SLICE_ARG ) { - p_enc->avc_slice_arg = atoi(value); + p_enc->slice_arg = atoi(value); } OPT(NI_ENC_PARAM_ENTROPY_CODING_MODE) { @@ -4687,7 +5959,6 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, { p_enc->intra_mb_refresh_arg = atoi(value); } -// TBD Rev. B: could be shared for HEVC and H.264 OPT( NI_ENC_PARAM_ENABLE_MB_LEVEL_RC ) { if ((atoi(value) > NI_MAX_BIN) || (atoi(value) < NI_MIN_BIN)) @@ -4717,14 +5988,6 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } p_params->dolby_vision_profile = atoi(value); } - OPT(NI_ENC_PARAM_CONSTANT_RATE_FACTOR) - { - if ((atoi(value) > 51) || (atoi(value) < -1)) - { - return NI_RETCODE_PARAM_ERROR_OOR; - } - p_enc->crf = atoi(value); - } OPT(NI_ENC_PARAM_RDO_LEVEL) { if ((atoi(value) > 3) || (atoi(value) < 1)) @@ -4742,7 +6005,8 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, #else char *v = strdup(value); #endif - chunk = strtok(v, delim); + char *saveptr = NULL; + chunk = ni_strtok(v, delim, &saveptr); if (chunk != NULL) { if ((atoi(chunk) > 65535) || (atoi(chunk) < 0)) @@ -4751,7 +6015,7 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_ERROR_OOR; } p_enc->HDR10MaxLight = atoi(chunk); - chunk = strtok(NULL, delim); + chunk = ni_strtok(NULL, delim, &saveptr); if (chunk != NULL) { if ((atoi(chunk) > 65535) || (atoi(chunk) < 0)) @@ -4775,6 +6039,160 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, return NI_RETCODE_PARAM_INVALID_VALUE; } } + + OPT(NI_ENC_PARAM_MASTER_DISPLAY) + { +#ifdef _MSC_VER +#define STRDUP(value) _strdup(value); +#else +#define STRDUP(value) strdup(value); +#endif + const char G[2] = "G"; + const char B[2] = "B"; + const char R[2] = "R"; + const char W[2] = "W"; + const char L[2] = "L"; + const char P[2] = "P"; + const char parL[2] = "("; + const char comma[2] = ","; + const char parR[2] = ")"; + int synCheck_GBRWLPCP[8]; + int posCheck_GBRWL[5] = {0}; + char *chunk;//for parsing out more complex inputs + char *subchunk; + char *v = STRDUP(value); + //basic check syntax correct + for (i = 0; i<8; i++) + { + synCheck_GBRWLPCP[i] = 0; + } + chunk = v; + i = 0; // character index + + //count keys and punctuation, save indicies to be parsed + while (*chunk) { + if (*chunk == G[0]) + { + synCheck_GBRWLPCP[0]++; + posCheck_GBRWL[0] = i; + } + else if (*chunk == B[0]) + { + synCheck_GBRWLPCP[1]++; + posCheck_GBRWL[1] = i; + } + else if (*chunk == R[0]) + { + synCheck_GBRWLPCP[2]++; + posCheck_GBRWL[2] = i; + } + else if (*chunk == W[0]) + { + synCheck_GBRWLPCP[3]++; + posCheck_GBRWL[3] = i; + } + else if (*chunk == L[0]) + { + synCheck_GBRWLPCP[4]++; + posCheck_GBRWL[4] = i; + } + else if (*chunk == parL[0]) + { + synCheck_GBRWLPCP[5]++; + } + else if (*chunk == comma[0]) + { + synCheck_GBRWLPCP[6]++; + } + else if (*chunk == parR[0]) + { + synCheck_GBRWLPCP[7]++; + } + chunk++; + i++; + } + free(v); + if (synCheck_GBRWLPCP[0] != 1 || synCheck_GBRWLPCP[1] != 1 || synCheck_GBRWLPCP[2] != 1 || + synCheck_GBRWLPCP[3] != 1 || synCheck_GBRWLPCP[4] != 1 || synCheck_GBRWLPCP[5] != 5 || + synCheck_GBRWLPCP[6] != 5 || synCheck_GBRWLPCP[7] != 5) + { + return NI_RETCODE_PARAM_INVALID_VALUE; + } + + //Parse a key-value set like G(%hu, %hu) +#define GBRWLPARSE(OUT1,OUT2,OFF,IDX) \ +{ \ + char *v = STRDUP(value); \ + chunk = v + posCheck_GBRWL[IDX]; \ + i = j = k = 0; \ + while (chunk != NULL) \ + { \ + if (*chunk == parL[0] && i == 1+(OFF)) \ + { \ + j = 1; \ + } \ + if((OFF) == 1 && *chunk != P[0] && i == 1) \ + { \ + break; \ + } \ + if (*chunk == parR[0]) \ + { \ + k = 1; \ + break; \ + } \ + i++; \ + chunk++; \ + } \ + if (!j || !k) \ + { \ + free(v); \ + return NI_RETCODE_PARAM_INVALID_VALUE; \ + } \ + subchunk = malloc(i - 1 - (OFF)); \ + if (subchunk == NULL) \ + { \ + free(v); \ + return NI_RETCODE_ERROR_MEM_ALOC; \ + } \ + memcpy(subchunk, v + posCheck_GBRWL[IDX] + 2 + (OFF), i - 2 - (OFF)); \ + subchunk[i - 2 - (OFF)] = '\0'; \ + char *saveptr = NULL; \ + chunk = ni_strtok(subchunk, comma, &saveptr); \ + if (chunk != NULL) \ + { \ + if(atoi(chunk) < 0) \ + { \ + free(v); \ + if(subchunk != NULL){ \ + free(subchunk); \ + } \ + return NI_RETCODE_PARAM_INVALID_VALUE; \ + } \ + *(OUT1) = atoi(chunk); \ + } \ + chunk = ni_strtok(NULL, comma, &saveptr); \ + if (chunk != NULL) \ + { \ + if(atoi(chunk) < 0) \ + { \ + free(v); \ + if(subchunk != NULL){ \ + free(subchunk); \ + } \ + return NI_RETCODE_PARAM_INVALID_VALUE; \ + } \ + *(OUT2) = atoi(chunk); \ + } \ + free(subchunk); \ + free(v); \ +} + GBRWLPARSE(&p_enc->HDR10dx0, &p_enc->HDR10dy0, 0, 0); + GBRWLPARSE(&p_enc->HDR10dx1, &p_enc->HDR10dy1, 0, 1); + GBRWLPARSE(&p_enc->HDR10dx2, &p_enc->HDR10dy2, 0, 2); + GBRWLPARSE(&p_enc->HDR10wx, &p_enc->HDR10wy, 1, 3); + GBRWLPARSE(&p_enc->HDR10maxluma, &p_enc->HDR10minluma, 0, 4); + p_enc->HDR10Enable = 1; + } OPT(NI_ENC_PARAM_LOOK_AHEAD_DEPTH) { if (atoi(value)!= 0 && ((atoi(value) > 40 ) || (atoi(value) < 4))) @@ -4872,6 +6290,10 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } OPT(NI_ENC_PARAM_GDR_DURATION) { + if (QUADRA) + { + return NI_RETCODE_PARAM_WARNING_DEPRECATED; + } p_enc->gdrDuration = atoi(value); } OPT(NI_ENC_PARAM_LTR_REF_INTERVAL) @@ -4937,6 +6359,22 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, } p_enc->rcQpDeltaRange = atoi(value); } + OPT(NI_ENC_CTB_ROW_QP_STEP) + { + if ((atoi(value) > 500) || (atoi(value) < 0)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->ctbRowQpStep = atoi(value); + } + OPT(NI_ENC_NEW_RC_ENABLE) + { + if ((atoi(value) > 1) || (atoi(value) < 0)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->newRcEnable = atoi(value); + } OPT(NI_ENC_INLOOP_DS_RATIO) { if ((atoi(value) > 1) || (atoi(value) < 0)) @@ -4948,23 +6386,32 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, OPT(NI_ENC_PARAM_COLOR_PRIMARY) { COMPARE(value, 22, 0) - p_params->color_primaries = atoi(value); + p_params->color_primaries = p_enc->colorPrimaries = atoi(value); + p_enc->colorDescPresent = 1; } OPT(NI_ENC_PARAM_COLOR_TRANSFER_CHARACTERISTIC) { COMPARE(value, 18, 0) - p_params->color_transfer_characteristic = atoi(value); + p_params->color_transfer_characteristic = p_enc->colorTrc = atoi(value); + p_enc->colorDescPresent = 1; } OPT(NI_ENC_PARAM_COLOR_SPACE) { COMPARE(value, 14, 0) - p_params->color_space = atoi(value); + p_params->color_space = p_enc->colorSpace = atoi(value); + p_enc->colorDescPresent = 1; + } + OPT(NI_ENC_PARAM_SAR_NUM) + { + p_params->sar_num = p_enc->aspectRatioWidth = atoi(value); + } + OPT(NI_ENC_PARAM_SAR_DENOM) + { + p_params->sar_denom = p_enc->aspectRatioHeight = atoi(value); } - OPT(NI_ENC_PARAM_SAR_NUM) { p_params->sar_num = atoi(value); } - OPT(NI_ENC_PARAM_SAR_DENOM) { p_params->sar_denom = atoi(value); } OPT(NI_ENC_PARAM_VIDEO_FULL_RANGE_FLAG) { - p_params->video_full_range_flag = atoi(value); + p_params->video_full_range_flag = p_enc->videoFullRange = atoi(value); } OPT(NI_KEEP_ALIVE_TIMEOUT) { @@ -4987,26 +6434,336 @@ ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, { if ((atoi(value) != 0) && (atoi(value) != 1)) { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->enable_ssim = atoi(value); + } + OPT(NI_ENC_PARAM_AV1_ERROR_RESILIENT_MODE) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->av1_error_resilient_mode = atoi(value); + } + OPT(NI_ENC_PARAM_STATIC_MMAP_THRESHOLD) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->staticMmapThreshold = atoi(value); + } + OPT(NI_ENC_PARAM_TEMPORAL_LAYERS_ENABLE) + { + p_enc->temporal_layers_enable = atoi(value); + } + OPT(NI_ENC_PARAM_ENABLE_AI_ENHANCE) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->enable_ai_enhance = atoi(value); + } + OPT(NI_ENC_PARAM_ENABLE_2PASS_GOP) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->enable2PassGop = atoi(value); + } + OPT( NI_ENC_PARAM_ZEROCOPY_MODE ) + { + if ((atoi(value) != 0) && (atoi(value) != 1) && (atoi(value) != -1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->zerocopy_mode = atoi(value); + } + OPT(NI_ENC_PARAM_AI_ENHANCE_LEVEL) + { + if ((atoi(value) == 0) || (atoi(value) > 3)) + { return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->ai_enhance_level = atoi(value); } - p_enc->enable_ssim = atoi(value); - } - else { return NI_RETCODE_PARAM_INVALID_NAME; } - -#undef OPT -#undef OPT2 -#undef atobool -#undef atoi -#undef atof - - b_error |= bValueWasNull && !bNameWasBool; - - ni_log(NI_LOG_TRACE, "%s: exit, b_error=%d\n", __func__, b_error); - - return b_error ? NI_RETCODE_PARAM_INVALID_VALUE : NI_RETCODE_SUCCESS; -} - -#undef atoi + OPT( NI_ENC_PARAM_CROP_WIDTH ) + { + if ((atoi(value) < NI_MIN_WIDTH) || + (atoi(value) > NI_PARAM_MAX_WIDTH)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->crop_width = atoi(value); + } + OPT( NI_ENC_PARAM_CROP_HEIGHT ) + { + if ((atoi(value) < NI_MIN_HEIGHT) || + (atoi(value) > NI_PARAM_MAX_HEIGHT)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->crop_height = atoi(value); + } + OPT( NI_ENC_PARAM_HORIZONTAL_OFFSET ) + { + if ((atoi(value) < 0) || + (atoi(value) > NI_PARAM_MAX_WIDTH)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->hor_offset = atoi(value); + } + OPT( NI_ENC_PARAM_VERTICAL_OFFSET ) + { + if ((atoi(value) < 0) || + (atoi(value) > NI_PARAM_MAX_HEIGHT)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->ver_offset = atoi(value); + } + OPT(NI_ENC_PARAM_CONSTANT_RATE_FACTOR_MAX) + { + if ((atoi(value) > 51) || (atoi(value) < -1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->crfMax = atoi(value); + } + OPT(NI_ENC_PARAM_QCOMP) + { + if ((atof(value) > 1.0) || (atof(value) < 0.0)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->qcomp = (float)atof(value); + } + OPT(NI_ENC_PARAM_NO_MBTREE) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->noMbtree = atoi(value); + } + OPT(NI_ENC_PARAM_NO_HW_MULTIPASS_SUPPORT) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->noHWMultiPassSupport = atoi(value); + } + OPT(NI_ENC_PARAM_CU_TREE_FACTOR) + { + if ((atoi(value) > 10) || (atoi(value) < 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->cuTreeFactor = atoi(value); + } + OPT(NI_ENC_PARAM_IP_RATIO) + { + if ((atof(value) > 10.0) || (atof(value) < 0.01)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->ipRatio = (float)atof(value); + } + OPT(NI_ENC_PARAM_ENABLE_IP_RATIO) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->enableipRatio = atoi(value); + } + OPT(NI_ENC_PARAM_PB_RATIO) + { + if ((atof(value) > 10.0) || (atof(value) < 0.01)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->pbRatio = (float)atof(value); + } + OPT(NI_ENC_PARAM_CPLX_DECAY) + { + if ((atof(value) > 1.0) || (atof(value) < 0.1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->cplxDecay = (float)atof(value); + } + OPT(NI_ENC_PARAM_PPS_INIT_QP) + { + if ((atoi(value) > 51) || (atoi(value) < -1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->pps_init_qp = atoi(value); + } + OPT(NI_ENC_PARAM_DDR_PRIORITY_MODE) + { + if (atoi(value) >= NI_DDR_PRIORITY_MAX || + atoi(value) <= NI_DDR_PRIORITY_NONE) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_params->ddr_priority_mode = atoi(value); + } + OPT(NI_ENC_PARAM_BITRATE_MODE) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->bitrateMode = atoi(value); + } + OPT(NI_ENC_PARAM_PASS1_QP) + { + if ((atoi(value) > 51) || (atoi(value) < -1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->pass1_qp = atoi(value); + } + OPT(NI_ENC_PARAM_CONSTANT_RATE_FACTOR_FLOAT) + { + if (((atof(value) < 0.0) && (atof(value) != -1.0)) || + (atof(value) > 51.00)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->crfFloat = (float)atof(value); + } + OPT(NI_ENC_PARAM_HVS_BASE_MB_COMPLEXITY) + { + if ((atoi(value) < 0) || (atoi(value) > 31)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->hvsBaseMbComplexity = atoi(value); + } + OPT(NI_ENC_PARAM_STATISTIC_OUTPUT_LEVEL) + { + if (atoi(value) < 0 || atoi(value) > 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->statistic_output_level = atoi(value); + } + OPT(NI_ENC_PARAM_SKIP_FRAME_ENABLE) + { + if (atoi(value) < 0 || atoi(value) > 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->skip_frame_enable = atoi(value); + } + OPT(NI_ENC_PARAM_MAX_CONSUTIVE_SKIP_FRAME_NUMBER) + { + if (atoi(value) < 0) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->max_consecutive_skip_num = atoi(value); + } + OPT(NI_ENC_PARAM_SKIP_FRAME_INTERVAL) + { + if (atoi(value) <= 0 || atoi(value) > 255) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->skip_frame_interval = atoi(value); + } + OPT(NI_ENC_PARAM_ENABLE_ALL_SEI_PASSTHRU) + { + if (atoi(value) != 0 && atoi(value) != 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->enable_all_sei_passthru = atoi(value); + } + OPT(NI_ENC_PARAM_IFRAME_SIZE_RATIO) + { + if (atoi(value) <= 0) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->iframe_size_ratio = atoi(value); + } + OPT(NI_ENC_PARAM_CRF_MAX_IFRAME_ENABLE) + { + if (atoi(value) != 0 && atoi(value) != 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->crf_max_iframe_enable = atoi(value); + } + OPT( NI_ENC_PARAM_VBV_MINRATE) + { + p_enc->vbv_min_rate = atoi(value); + } + OPT(NI_ENC_PARAM_DISABLE_ADAPTIVE_BUFFERS) + { + if (atoi(value) != 0 && atoi(value) != 1) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->disable_adaptive_buffers = atoi(value); + } + OPT(NI_ENC_PARAM_DISABLE_BFRAME_RDOQ) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->disableBframeRdoq = atoi(value); + } + OPT(NI_ENC_PARAM_FORCE_BFRAME_QPFACTOR) + { + if ((atof(value) > 1.0) || (atof(value) < 0.0)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->forceBframeQpfactor = (float)atof(value); + } + OPT(NI_ENC_PARAM_TUNE_BFRAME_VISUAL) + { + if (atoi(value) < 0 || atoi(value) > 2) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->tune_bframe_visual = atoi(value); + } + OPT(NI_ENC_PARAM_ENABLE_ACQUIRE_LIMIT) + { + if ((atoi(value) != 0) && (atoi(value) != 1)) + { + return NI_RETCODE_PARAM_ERROR_OOR; + } + p_enc->enable_acq_limit = atoi(value); + } + else { return NI_RETCODE_PARAM_INVALID_NAME; } + +#undef OPT +#undef OPT2 +#undef atobool +#undef atoi +#undef atof + + b_error |= bValueWasNull && !bNameWasBool; + + ni_log(NI_LOG_TRACE, "%s: exit, b_error=%d\n", __func__, b_error); + + return b_error ? NI_RETCODE_PARAM_INVALID_VALUE : NI_RETCODE_SUCCESS; +} + +#undef atoi #undef atof #define atoi(p_str) ni_atoi(p_str, &b_error) #define atof(p_str) ni_atof(p_str, &b_error) @@ -5034,63 +6791,53 @@ ni_retcode_t ni_encoder_gop_params_set_value(ni_xcoder_params_t *p_params, bool b_error = false; bool bNameWasBool = false; bool bValueWasNull = !value; - ni_encoder_cfg_params_t *p_enc = &p_params->cfg_enc_params; - ni_custom_gop_params_t* p_gop = &p_enc->custom_gop_params; - + ni_encoder_cfg_params_t *p_enc = NULL; + ni_custom_gop_params_t* p_gop = NULL; char nameBuf[64] = { 0 }; ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_params) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Null pointer parameters passed\n", - __func__); - return NI_RETCODE_INVALID_PARAM; + ni_log(NI_LOG_ERROR, "ERROR: %s(): Null pointer parameters passed\n", + __func__); + return NI_RETCODE_INVALID_PARAM; } if ( !name ) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Null name pointer parameters passed\n", - __func__); - return NI_RETCODE_PARAM_INVALID_NAME; + ni_log(NI_LOG_ERROR, "ERROR: %s(): Null name pointer parameters passed\n", + __func__); + return NI_RETCODE_PARAM_INVALID_NAME; } + p_enc = &p_params->cfg_enc_params; + p_gop = &p_enc->custom_gop_params; // skip -- prefix if provided - if ((name[0] == '-') && (name[1] == '-')) + if (name[0] == '-' && name[1] == '-') { - name += 2; + name += 2; } // s/_/-/g if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name, '_')) { - char* c; - strcpy(nameBuf, name); - while ((c = strchr(nameBuf, '_')) != 0) - { - *c = '-'; - } - - name = nameBuf; + char* c; + strcpy(nameBuf, name); + while ((c = strchr(nameBuf, '_')) != 0) + { + *c = '-'; + } + name = nameBuf; } - if (!strncmp(name, "no-", 3)) + if (!value) { - name += 3; - value = !value || ni_atobool(value, &b_error) ? "false" : "true"; - } - else if (!strncmp(name, "no", 2)) - { - name += 2; - value = !value || ni_atobool(value, &b_error) ? "false" : "true"; - } - else if (!value) - { - value = "true"; + value = "true"; } else if (value[0] == '=') { - value++; + value++; } #if defined(_MSC_VER) @@ -5098,8 +6845,7 @@ ni_retcode_t ni_encoder_gop_params_set_value(ni_xcoder_params_t *p_params, #else #define OPT(STR) else if (!strcasecmp(name, STR)) #endif - if (0) - ; + if (0); // suppress cppcheck OPT(NI_ENC_GOP_PARAMS_CUSTOM_GOP_SIZE) { if (atoi(value) > NI_MAX_GOP_SIZE) @@ -5886,37 +7632,48 @@ ni_retcode_t ni_device_session_copy(ni_session_context_t *src_p_ctx, ni_session_ ******************************************************************************/ int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type) { - ni_log(NI_LOG_DEBUG, "%s start\n", __func__); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s start\n", __func__); ni_retcode_t retval = NI_RETCODE_SUCCESS; if ((!p_ctx) || (!p_data)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + // Here check if keep alive thread is closed. +#ifdef _WIN32 + if (p_ctx->keep_alive_thread.handle && + p_ctx->keep_alive_thread_args->close_thread) +#else + if (p_ctx->keep_alive_thread && p_ctx->keep_alive_thread_args->close_thread) +#endif + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() keep alive thread has been closed, " + "hw:%d, session:%d\n", + __func__, p_ctx->hw_id, p_ctx->session_id); + return NI_RETCODE_ERROR_INVALID_SESSION; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); // In close state, let the close process execute first. - if (p_ctx->xcoder_state & NI_XCODER_CLOSE_STATE || - #ifdef _WIN32 - (p_ctx->keep_alive_thread.handle && - #else - (p_ctx->keep_alive_thread && - #endif - p_ctx->keep_alive_thread_args->close_thread)) - { - ni_log(NI_LOG_DEBUG, "%s close state, return\n", __func__); - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + if (p_ctx->xcoder_state & NI_XCODER_CLOSE_STATE) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s close state, return\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); ni_usleep(100); - return NI_RETCODE_SUCCESS; + return NI_RETCODE_ERROR_INVALID_SESSION; } p_ctx->xcoder_state |= NI_XCODER_READ_DESC_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); switch (device_type) { case NI_DEVICE_TYPE_DECODER: { int seq_change_read_count = 0; + p_data->data.frame.src_codec = p_ctx->codec_format; for (;;) { //retval = ni_decoder_session_read(p_ctx, &(p_data->data.frame)); @@ -5936,7 +7693,7 @@ int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_i aligned_width = ((p_data->data.frame.video_width + 31) / 32) * 32; } - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "FNum %" PRIu64 ", DFVWxDFVH %u x %u, AlWid %u, AVW x AVH %u x %u\n", p_ctx->frame_num, p_data->data.frame.video_width, @@ -5945,7 +7702,7 @@ int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_i if (0 == retval && seq_change_read_count) { - ni_log(NI_LOG_DEBUG, "%s (decoder): seq change NO data, next time.\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "%s (decoder): seq change NO data, next time.\n", __func__); p_ctx->active_video_width = 0; p_ctx->active_video_height = 0; @@ -5954,22 +7711,26 @@ int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_i } else if (retval < 0) { - ni_log(NI_LOG_ERROR, "%s (decoder): failure ret %d, return ..\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s (decoder): failure ret %d, return ..\n", __func__, retval); break; } - else if (p_ctx->frame_num && p_data->data.frame.video_width && - p_data->data.frame.video_height && - (aligned_width != p_ctx->active_video_width || - p_data->data.frame.video_height != p_ctx->active_video_height)) + // aligned_width may equal to active_video_width if bit depth and width + // are changed at the same time. So, check video_width != actual_video_width. + else if (p_ctx->frame_num && (p_ctx->pixel_format_changed || + (p_data->data.frame.video_width && + p_data->data.frame.video_height && + (aligned_width != p_ctx->active_video_width || + p_data->data.frame.video_height != p_ctx->active_video_height)))) { - ni_log(NI_LOG_DEBUG, - "%s (decoder): resolution change, frame size " - "%ux%u -> %ux%u, width %u bit %d, continue read ...\n", - __func__, p_ctx->active_video_width, - p_ctx->active_video_height, aligned_width, - p_data->data.frame.video_height, - p_data->data.frame.video_width, p_ctx->bit_depth_factor); + ni_log2( + p_ctx, NI_LOG_DEBUG, + "%s (decoder): resolution change, frame size %ux%u -> %ux%u, " + "width %u bit %d, pix_fromat_changed %d, actual_video_width %d, continue read ...\n", + __func__, p_ctx->active_video_width, p_ctx->active_video_height, + aligned_width, p_data->data.frame.video_height, + p_data->data.frame.video_width, p_ctx->bit_depth_factor, + p_ctx->pixel_format_changed, p_ctx->actual_video_width); // reset active video resolution to 0 so it can be queried in the re-read p_ctx->active_video_width = 0; p_ctx->active_video_height = 0; @@ -5986,7 +7747,7 @@ int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_i } case NI_DEVICE_TYPE_ENCODER: { - ni_log(NI_LOG_ERROR, "ERROR: Encoder has no hwdesc to read\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Encoder has no hwdesc to read\n"); return NI_RETCODE_INVALID_PARAM; } @@ -5996,17 +7757,24 @@ int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_i break; } + case NI_DEVICE_TYPE_AI: + { + retval = ni_ai_session_read_hwdesc(p_ctx, &(p_data->data.frame)); + break; + } + default: { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unrecognized device type: %d", __func__, device_type); break; } } + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state &= ~NI_XCODER_READ_DESC_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -6033,25 +7801,57 @@ int ni_device_session_hwdl(ni_session_context_t* p_ctx, ni_session_data_io_t *p_ ni_retcode_t retval = NI_RETCODE_SUCCESS; if ((!hwdesc) || (!p_data)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); - p_ctx->xcoder_state |= NI_XCODER_HWDL_STATE; - p_ctx->session_id = hwdesc->ui16session_ID; - p_ctx->blk_io_handle = (ni_device_handle_t)(int64_t)hwdesc->device_handle; - p_ctx->codec_format = NI_CODEC_FORMAT_H264; //unused - p_ctx->bit_depth_factor = (int)hwdesc->bit_depth; - p_ctx->hw_action = NI_CODEC_HW_DOWNLOAD; - ni_log(NI_LOG_DEBUG, "%s: bit_depth_factor %d\n", __func__, - p_ctx->bit_depth_factor); + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + if (p_ctx->pext_mutex == &(p_ctx->mutex)) + { + ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session\n", + __func__); + return NI_RETCODE_ERROR_INVALID_SESSION; + } + } + + ni_pthread_mutex_lock(p_ctx->pext_mutex); + bool use_external_mutex = false; + uint32_t orig_session_id = p_ctx->session_id; + ni_device_handle_t orig_blk_io_handle = p_ctx->blk_io_handle; + uint32_t orig_codec_format = p_ctx->codec_format; + int orig_bit_depth_factor = p_ctx->bit_depth_factor; + int orig_hw_action = p_ctx->hw_action; + + ni_pthread_mutex_t *p_ctx_mutex = &(p_ctx->mutex); + if ((p_ctx_mutex != p_ctx->pext_mutex) || + ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r8") < 0) + { + use_external_mutex = true; + p_ctx->session_id = hwdesc->ui16session_ID; + p_ctx->blk_io_handle = (ni_device_handle_t)(int64_t)hwdesc->device_handle; + p_ctx->codec_format = NI_CODEC_FORMAT_H264; //unused + p_ctx->bit_depth_factor = (int)hwdesc->bit_depth; + p_ctx->hw_action = NI_CODEC_HW_DOWNLOAD; + } + + p_ctx->xcoder_state |= NI_XCODER_HWDL_STATE; retval = ni_hwdownload_session_read(p_ctx, &(p_data->data.frame), hwdesc); //cut me down as needed p_ctx->xcoder_state &= ~NI_XCODER_HWDL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + if (use_external_mutex) + { + p_ctx->session_id = orig_session_id; + p_ctx->blk_io_handle = orig_blk_io_handle; + p_ctx->codec_format = orig_codec_format; + p_ctx->bit_depth_factor = orig_bit_depth_factor; + p_ctx->hw_action = orig_hw_action; + } + ni_pthread_mutex_unlock(p_ctx->pext_mutex); return retval; } @@ -6078,17 +7878,17 @@ int ni_device_session_hwup(ni_session_context_t* p_ctx, ni_session_data_io_t *p_ ni_retcode_t retval = NI_RETCODE_SUCCESS; if ((!hwdesc) || (!p_src_data)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_HWUP_STATE; retval = ni_hwupload_session_write(p_ctx, &p_src_data->data.frame, hwdesc); p_ctx->xcoder_state &= ~NI_XCODER_HWUP_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -6125,9 +7925,6 @@ ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t* p_frame, int video_width, ni_log(NI_LOG_DEBUG, "%s: extra_len=%d\n", __func__, extra_len); - int luma_size = 0;////linesize[0] * height_aligned; - int chroma_b_size = 0;//luma_size / 4; - int chroma_r_size = 0;//luma_size / 4; int buffer_size = (int)sizeof(niFrameSurface1_t) + extra_len; buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT + NI_MEM_PAGE_ALIGNMENT; @@ -6176,6 +7973,8 @@ ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t* p_frame, int video_width, p_frame->video_width = video_width; p_frame->video_height = height_aligned; + ((niFrameSurface1_t*)p_frame->p_data[3])->device_handle = NI_INVALID_DEVICE_HANDLE; + ni_log(NI_LOG_DEBUG, "%s: success: p_frame->buffer_size=%u\n", __func__, p_frame->buffer_size); @@ -6202,6 +8001,7 @@ ni_retcode_t ni_hwframe_buffer_recycle(niFrameSurface1_t *surface, int32_t device_handle) { ni_retcode_t retval = NI_RETCODE_SUCCESS; + if (surface) { ni_log(NI_LOG_DEBUG, "%s(): Start cleaning out buffer\n", __func__); @@ -6209,59 +8009,163 @@ ni_retcode_t ni_hwframe_buffer_recycle(niFrameSurface1_t *surface, "%s(): ui16FrameIdx=%d sessionId=%d device_handle=0x%x\n", __func__, surface->ui16FrameIdx, surface->ui16session_ID, device_handle); - retval = ni_clear_instance_buf(surface, device_handle); + retval = ni_clear_instance_buf(surface); } else { ni_log(NI_LOG_DEBUG, "%s(): Surface is empty\n", __func__); } + return retval; } /*!***************************************************************************** -* \brief Sends frame pool setup info to device +* \brief Recycle a frame buffer on card, only hwframe descriptor is needed * -* \param[in] p_ctx Pointer to a caller allocated -* ni_session_context_t struct -* \param[in] pool_size Upload session initial allocated frames count -* must be > 0, -* \param[in] pool 0 use the normal pool -* 1 use a dedicated P2P pool +* \param[in] surface Struct containing device and frame location to clear out * -* \return On success Return code -* On failure -* NI_RETCODE_INVALID_PARAM -* NI_RETCODE_ERROR_NVME_CMD_FAILED -* NI_RETCODE_ERROR_INVALID_SESSION -* NI_RETCODE_ERROR_MEM_ALOC +* \return On success NI_RETCODE_SUCCESS +* On failure NI_RETCODE_INVALID_PARAM *******************************************************************************/ -int ni_device_session_init_framepool(ni_session_context_t *p_ctx, - uint32_t pool_size, uint32_t pool) +ni_retcode_t ni_hwframe_buffer_recycle2(niFrameSurface1_t *surface) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + int32_t saved_dma_buf_fd; + if (surface) + { + if(surface->ui16FrameIdx == 0) + { + ni_log(NI_LOG_DEBUG, "%s(): Invaild frame index\n", __func__); + return retval; + } + ni_log(NI_LOG_DEBUG, "%s(): Start cleaning out buffer\n", __func__); + ni_log(NI_LOG_DEBUG, + "%s(): ui16FrameIdx=%d sessionId=%d device_handle=0x%x\n", + __func__, surface->ui16FrameIdx, surface->ui16session_ID, + surface->device_handle); + retval = ni_clear_instance_buf(surface); + saved_dma_buf_fd = surface->dma_buf_fd; + memset(surface, 0, sizeof(niFrameSurface1_t)); + surface->dma_buf_fd = saved_dma_buf_fd; + } + else + { + ni_log(NI_LOG_DEBUG, "%s(): Surface is empty\n", __func__); + retval = NI_RETCODE_INVALID_PARAM; + } + + return retval; +} + +/*!***************************************************************************** +* \brief Sends frame pool setup info to device +* +* \param[in] p_ctx Pointer to a caller allocated +* ni_session_context_t struct +* \param[in] pool_size Upload session initial allocated frames count +* must be > 0, +* \param[in] pool 0 use the normal pool +* 1 use a dedicated P2P pool +* +* \return On success Return code +* On failure +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_ERROR_NVME_CMD_FAILED +* NI_RETCODE_ERROR_INVALID_SESSION +* NI_RETCODE_ERROR_MEM_ALOC +*******************************************************************************/ +int ni_device_session_init_framepool(ni_session_context_t *p_ctx, + uint32_t pool_size, uint32_t pool) { ni_retcode_t retval = NI_RETCODE_SUCCESS; if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } if (pool_size == 0 || pool_size > NI_MAX_UPLOAD_INSTANCE_FRAMEPOOL) { - ni_log(NI_LOG_ERROR, "ERROR: Invalid poolsize == 0 or > 100\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Invalid poolsize == 0 or > 100\n"); return NI_RETCODE_INVALID_PARAM; } - if (pool != 0 && pool != 1) + if (pool & NI_UPLOADER_FLAG_LM) { - ni_log(NI_LOG_ERROR, "ERROR: bad pool number %u\n", pool); - return NI_RETCODE_INVALID_PARAM; + ni_log2(p_ctx, NI_LOG_DEBUG, "uploader buffer acquisition is limited!\n"); } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; retval = ni_config_instance_set_uploader_params(p_ctx, pool_size, pool); p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return retval; +} + +/*!***************************************************************************** +* \brief Sends frame pool change info to device +* +* \param[in] p_ctx Pointer to a caller allocated +* ni_session_context_t struct +* \param[in] pool_size if pool_size = 0, free allocated device memory buffers +* if pool_size > 0, expand device frame buffer pool of +* current instance with pool_size more frame buffers +* +* \return On success Return code +* On failure +* NI_RETCODE_FAILURE +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_ERROR_NVME_CMD_FAILED +* NI_RETCODE_ERROR_INVALID_SESSION +* NI_RETCODE_ERROR_MEM_ALOC +* NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION +*******************************************************************************/ +ni_retcode_t ni_device_session_update_framepool(ni_session_context_t *p_ctx, + uint32_t pool_size) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r3") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s function not supported in FW API version < 6r3\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + if (p_ctx->pool_type == NI_POOL_TYPE_NONE) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: can't free or expand framepool of session 0x%x " + "before init framepool\n", p_ctx->session_id); + return NI_RETCODE_FAILURE; + } + if (pool_size > NI_MAX_UPLOAD_INSTANCE_FRAMEPOOL) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: Invalid poolsize > %u\n", NI_MAX_UPLOAD_INSTANCE_FRAMEPOOL); + return NI_RETCODE_INVALID_PARAM; + } + if (pool_size == 0) + { + ni_log2(p_ctx, NI_LOG_INFO, "Free frame pool of session 0x%x\n", p_ctx->session_id); + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + retval = ni_config_instance_set_uploader_params(p_ctx, pool_size, p_ctx->pool_type); + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -6284,21 +8188,182 @@ ni_retcode_t ni_scaler_set_params(ni_session_context_t *p_ctx, if (!p_ctx || !p_params) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; retval = ni_config_instance_set_scaler_params(p_ctx, p_params); p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return retval; +} + +/*!****************************************************************************** + * \brief Send a p_config command to configure scaling drawbox parameters. + * + * \param ni_session_context_t p_ctx - xcoder Context + * \param ni_scaler_params_t * params - pointer to the scaler ni_scaler_drawbox params_t struct + * + * \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, NI_RETCODE_ERROR_NVME_CMD_FAILED on failure +*******************************************************************************/ +ni_retcode_t ni_scaler_set_drawbox_params(ni_session_context_t *p_ctx, + ni_scaler_drawbox_params_t *p_params) +{ + void *p_scaler_config = NULL; + uint32_t buffer_size = sizeof(ni_scaler_multi_drawbox_params_t); + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx || !p_params) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + buffer_size = + ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * + NI_MEM_PAGE_ALIGNMENT; + if (ni_posix_memalign(&p_scaler_config, sysconf(_SC_PAGESIZE), buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() malloc p_scaler_config buffer failed\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_scaler_config, 0, buffer_size); + + //configure the session here + ui32LBA = CONFIG_INSTANCE_SetScalerDrawBoxPara_W(p_ctx->session_id, + NI_DEVICE_TYPE_SCALER); + + memcpy(p_scaler_config, p_params, buffer_size); + + if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_scaler_config, buffer_size, ui32LBA) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_nvme_send_write_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %d, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + // Close the session since we can't configure it as per fw + retval = ni_scaler_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s failed: blk_io_handle: %" PRIx64 "," + "hw_id, %d, xcoder_inst_id: %d\n", + __func__, + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, + p_ctx->session_id); + } + + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + +END: + + ni_aligned_free(p_scaler_config); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} + +/*!****************************************************************************** + * \brief Send a p_config command to configure scaling watermark parameters. + * + * \param ni_session_context_t p_ctx - xcoder Context + * \param ni_scaler_params_t * params - pointer to the scaler ni_scaler_watermark_params_t struct + * + * \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, NI_RETCODE_ERROR_NVME_CMD_FAILED on failure +*******************************************************************************/ +ni_retcode_t ni_scaler_set_watermark_params(ni_session_context_t *p_ctx, + ni_scaler_watermark_params_t *p_params) +{ + void *p_scaler_config = NULL; + uint32_t buffer_size = sizeof(ni_scaler_multi_watermark_params_t); + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx || !p_params) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + buffer_size = + ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * + NI_MEM_PAGE_ALIGNMENT; + if (ni_posix_memalign(&p_scaler_config, sysconf(_SC_PAGESIZE), buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() malloc p_scaler_config buffer failed\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_scaler_config, 0, buffer_size); + + //configure the session here + ui32LBA = CONFIG_INSTANCE_SetScalerWatermarkPara_W(p_ctx->session_id, + NI_DEVICE_TYPE_SCALER); + + memcpy(p_scaler_config, p_params, buffer_size); + + if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_scaler_config, buffer_size, ui32LBA) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_nvme_send_write_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %d, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + // Close the session since we can't configure it as per fw + retval = ni_scaler_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s failed: blk_io_handle: %" PRIx64 "," + "hw_id, %d, xcoder_inst_id: %d\n", + __func__, + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, + p_ctx->session_id); + } + + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + +END: + + ni_aligned_free(p_scaler_config); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } + /*!***************************************************************************** * \brief Allocate a frame on the device for 2D engine or AI engine * to work on based on provided parameters @@ -6316,7 +8381,6 @@ ni_retcode_t ni_scaler_set_params(ni_session_context_t *p_ctx, * \param[in] rectangle_x horizontal position of clipping rectangle * \param[in] rectangle_y vertical position of clipping rectangle * \param[in] rgba_color RGBA fill colour (for padding only) - * \param[in] rgba_color RGBA fill colour (for padding only) * \param[in] frame_index input hwdesc index * \param[in] device_type only NI_DEVICE_TYPE_SCALER * and NI_DEVICE_TYPE_AI (only needs p_ctx and frame_index) @@ -6343,11 +8407,11 @@ ni_retcode_t ni_device_alloc_frame(ni_session_context_t* p_ctx, if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; switch (device_type) @@ -6360,21 +8424,126 @@ ni_retcode_t ni_device_alloc_frame(ni_session_context_t* p_ctx, break; case NI_DEVICE_TYPE_AI: - retval = ni_ai_alloc_hwframe(p_ctx, frame_index); + retval = ni_ai_alloc_hwframe(p_ctx, width, height, options, rgba_color, + frame_index); + break; + + case NI_DEVICE_TYPE_ENCODER: + case NI_DEVICE_TYPE_DECODER: + /* fall through */ + + default: + ni_log2(p_ctx, NI_LOG_ERROR, "Bad device type %d\n", device_type); + retval = NI_RETCODE_INVALID_PARAM; + break; + } + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return retval; +} + +/*!***************************************************************************** + * \brief Allocate a frame on the device and return the frame index + * + * \param[in] p_ctx pointer to session context + * \param[in] p_out_surface pointer to output frame surface + * \param[in] device_type currently only NI_DEVICE_TYPE_AI + * + * \return NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +ni_retcode_t ni_device_alloc_dst_frame(ni_session_context_t *p_ctx, + niFrameSurface1_t *p_out_surface, + ni_device_type_t device_type) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, %p, return\n", + __func__, p_ctx); + return NI_RETCODE_INVALID_PARAM; + } + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + switch (device_type) + { + case NI_DEVICE_TYPE_AI: + retval = ni_ai_alloc_dst_frame(p_ctx, p_out_surface); break; + case NI_DEVICE_TYPE_SCALER: case NI_DEVICE_TYPE_ENCODER: case NI_DEVICE_TYPE_DECODER: /* fall through */ default: - ni_log(NI_LOG_ERROR, "Bad device type %d\n", device_type); + ni_log2(p_ctx, NI_LOG_ERROR, "Bad device type %d\n", device_type); retval = NI_RETCODE_INVALID_PARAM; break; + } + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return retval; +} + +/*!***************************************************************************** + * \brief Copy the data of src hwframe to dst hwframe + * + * \param[in] p_ctx pointer to session context + * \param[in] p_frameclone_desc pointer to the frameclone descriptor + * + * \return NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +ni_retcode_t ni_device_clone_hwframe(ni_session_context_t *p_ctx, + ni_frameclone_desc_t *p_frameclone_desc) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rL") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "Error: %s function not supported on device with FW API version < 6rL\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; } + retval = ni_hwframe_clone(p_ctx, p_frameclone_desc); + +END: p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -6397,12 +8566,12 @@ ni_retcode_t ni_device_config_frame(ni_session_context_t *p_ctx, if (!p_ctx || !p_cfg) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; switch (p_ctx->device_type) @@ -6412,13 +8581,13 @@ ni_retcode_t ni_device_config_frame(ni_session_context_t *p_ctx, break; default: - ni_log(NI_LOG_ERROR, "Bad device type %d\n", p_ctx->device_type); + ni_log2(p_ctx, NI_LOG_ERROR, "Bad device type %d\n", p_ctx->device_type); retval = NI_RETCODE_INVALID_PARAM; break; } p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -6445,12 +8614,12 @@ ni_retcode_t ni_device_multi_config_frame(ni_session_context_t *p_ctx, if (!p_ctx || !p_cfg_in) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; switch (p_ctx->device_type) @@ -6459,14 +8628,18 @@ ni_retcode_t ni_device_multi_config_frame(ni_session_context_t *p_ctx, retval = ni_scaler_multi_config_frame(p_ctx, p_cfg_in, numInCfgs, p_cfg_out); break; + case NI_DEVICE_TYPE_AI: + retval = ni_ai_multi_config_frame(p_ctx, p_cfg_in, numInCfgs, p_cfg_out); + break; + default: - ni_log(NI_LOG_ERROR, "Bad device type %d\n", p_ctx->device_type); + ni_log2(p_ctx, NI_LOG_ERROR, "Bad device type %d\n", p_ctx->device_type); retval = NI_RETCODE_INVALID_PARAM; break; } p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -6513,6 +8686,10 @@ int ni_calculate_total_frame_size(const ni_session_context_t *p_upl_ctx, break; case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_BGR0: if ((width < 0) || (width > NI_MAX_RESOLUTION_WIDTH)) { return NI_RETCODE_INVALID_PARAM; @@ -6551,6 +8728,10 @@ int ni_calculate_total_frame_size(const ni_session_context_t *p_upl_ctx, break; case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_BGR0: total = width * height * 4 + NI_APP_ENC_FRAME_META_DATA_SIZE; break; @@ -6635,7 +8816,7 @@ ni_retcode_t ni_frame_buffer_alloc_pixfmt(ni_frame_t *p_frame, int pixel_format, * height restriction. The 2D engine supports a height/width of up to * 32K but but we will limit the max height and width to 8K. */ - if ((video_width < 32) && (video_width > NI_MAX_RESOLUTION_WIDTH)) + if ((video_width < 0) || (video_width > NI_MAX_RESOLUTION_WIDTH)) { ni_log(NI_LOG_ERROR, "Video resolution width %d out of range\n", video_width); @@ -6833,6 +9014,8 @@ ni_retcode_t ni_frame_buffer_alloc_pixfmt(ni_frame_t *p_frame, int pixel_format, p_frame->data_len[1] = chroma_b_size; p_frame->data_len[2] = 0; p_frame->data_len[3] = 0; + + video_width = NI_VPU_ALIGN64(video_width); break; } @@ -6900,16 +9083,17 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); if (stat(file, &file_stat) != 0) { - ni_log(NI_LOG_ERROR, "%s: failed to get network binary file stat, %s\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s: failed to get network binary file stat, %s\n", __func__, strerror(NI_ERRNO)); retval = NI_RETCODE_FAILURE; LRETURN; @@ -6917,7 +9101,7 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, if (file_stat.st_size == 0) { - ni_log(NI_LOG_ERROR, "%s: network binary size is null\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s: network binary size is null\n", __func__); retval = NI_RETCODE_FAILURE; LRETURN; } @@ -6925,7 +9109,7 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, fp = fopen(file, "rb"); if (!fp) { - ni_log(NI_LOG_ERROR, "%s: failed to open network binary, %s\n", __func__, + ni_log2(p_ctx, NI_LOG_ERROR, "%s: failed to open network binary, %s\n", __func__, strerror(NI_ERRNO)); retval = NI_RETCODE_FAILURE; LRETURN; @@ -6934,14 +9118,14 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, buffer = malloc(file_stat.st_size); if (!buffer) { - ni_log(NI_LOG_ERROR, "%s: failed to alloate memory\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s: failed to alloate memory\n", __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } if (fread(buffer, file_stat.st_size, 1, fp) != 1) { - ni_log(NI_LOG_ERROR, "%s: failed to read network binary\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s: failed to read network binary\n", __func__); retval = NI_RETCODE_FAILURE; LRETURN; } @@ -6950,7 +9134,7 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, ni_config_instance_network_binary(p_ctx, buffer, file_stat.st_size); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "%s: failed to configure instance, retval %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s: failed to configure instance, retval %d\n", __func__, retval); LRETURN; } @@ -6958,7 +9142,7 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, retval = ni_config_read_inout_layers(p_ctx, p_network); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR: failed to read network layers, retval %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: failed to read network layers, retval %d\n", retval); } @@ -6968,10 +9152,11 @@ ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, { fclose(fp); } - ni_aligned_free(buffer); + free(buffer); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return retval; } @@ -7063,7 +9248,7 @@ ni_retcode_t ni_ai_packet_buffer_alloc(ni_packet_t *p_packet, void *p_buffer = NULL; int retval = NI_RETCODE_SUCCESS; uint32_t buffer_size = 0; - uint32_t i, this_size; + uint32_t i, data_size; ni_network_layer_info_t *p_linfo; if (!p_packet || !p_network) @@ -7076,19 +9261,19 @@ ni_retcode_t ni_ai_packet_buffer_alloc(ni_packet_t *p_packet, p_linfo = &p_network->linfo; for (i = 0; i < p_network->output_num; i++) { - this_size = ni_ai_network_layer_size(&p_linfo->out_param[i]); - this_size = - (this_size + NI_AI_HW_ALIGN_SIZE - 1) & ~(NI_AI_HW_ALIGN_SIZE - 1); + data_size = ni_ai_network_layer_size(&p_linfo->out_param[i]); + data_size = + (data_size + NI_AI_HW_ALIGN_SIZE - 1) & ~(NI_AI_HW_ALIGN_SIZE - 1); if (p_network->outset[i].offset != buffer_size) { ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid buffer_size of network\n", __func__); return NI_RETCODE_INVALID_PARAM; } - buffer_size += this_size; + buffer_size += data_size; } + data_size = buffer_size; - this_size = buffer_size; ni_log(NI_LOG_DEBUG, "%s(): packet_size=%u\n", __func__, buffer_size); if (buffer_size & (NI_MEM_PAGE_ALIGNMENT - 1)) @@ -7123,7 +9308,7 @@ ni_retcode_t ni_ai_packet_buffer_alloc(ni_packet_t *p_packet, p_packet->buffer_size = buffer_size; p_packet->p_buffer = p_buffer; p_packet->p_data = p_packet->p_buffer; - p_packet->data_len = this_size; + p_packet->data_len = data_size; END: @@ -7151,16 +9336,16 @@ ni_retcode_t ni_reconfig_bitrate(ni_session_context_t *p_ctx, int32_t bitrate) { if (!p_ctx || bitrate < NI_MIN_BITRATE || bitrate > NI_MAX_BITRATE) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid bitrate passed in %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid bitrate passed in %d\n", __func__, bitrate); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; if (p_ctx->target_bitrate > 0) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning: %s(): bitrate %d overwriting current one %d\n", __func__, bitrate, p_ctx->target_bitrate); } @@ -7168,44 +9353,85 @@ ni_retcode_t ni_reconfig_bitrate(ni_session_context_t *p_ctx, int32_t bitrate) p_ctx->target_bitrate = bitrate; p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } /*!***************************************************************************** - * \brief Reconfigure VUI HRD dynamically during encoding. + * \brief Reconfigure intraPeriod dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] intra_period Target intra period to set * - * \param[in] p_ctx Pointer to caller allocated ni_session_context_t - * \param[in] bitrate Target bitrate to set * * \return On success NI_RETCODE_SUCCESS * On failure NI_RETCODE_INVALID_PARAM + * + * NOTE - the frame upon which intra period is reconfigured is encoded as IDR frame + * NOTE - reconfigure intra period is not allowed if intraRefreshMode is enabled or if gopPresetIdx is 1 + * ******************************************************************************/ -ni_retcode_t ni_reconfig_vui(ni_session_context_t *p_ctx, ni_vui_hrd_t *vui) +ni_retcode_t ni_reconfig_intraprd(ni_session_context_t *p_ctx, + int32_t intra_period) { - if (!p_ctx || vui->colorDescPresent < 0 || vui->colorDescPresent > 1) + if (!p_ctx || intra_period < 0 || intra_period > 1024) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid colorDescPresent passed in %d\n", - __func__, vui->colorDescPresent); + ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid intraPeriod passed in %d\n", + __func__, intra_period); + return NI_RETCODE_INVALID_PARAM; + } + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + if (p_ctx->reconfig_intra_period >= 0) + { + ni_log(NI_LOG_DEBUG, + "Warning: %s(): intraPeriod %d overwriting current one %d\n", + __func__, intra_period, p_ctx->reconfig_intra_period); + } + + p_ctx->reconfig_intra_period = intra_period; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure VUI HRD dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] bitrate Target bitrate to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_vui(ni_session_context_t *p_ctx, ni_vui_hrd_t *vui) +{ + if (!p_ctx || vui->colorDescPresent < 0 || vui->colorDescPresent > 1) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid colorDescPresent passed in %d\n", + __func__, vui->colorDescPresent); return NI_RETCODE_INVALID_PARAM; } if ((vui->aspectRatioWidth > NI_MAX_ASPECTRATIO) || (vui->aspectRatioHeight > NI_MAX_ASPECTRATIO)) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid aspect ratio passed in (%dx%d)\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid aspect ratio passed in (%dx%d)\n", __func__, vui->aspectRatioWidth, vui->aspectRatioHeight); return NI_RETCODE_INVALID_PARAM; } if (vui->videoFullRange < 0 || vui->videoFullRange > 1) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid videoFullRange passed in %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid videoFullRange passed in %d\n", __func__, vui->videoFullRange); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; p_ctx->vui.colorDescPresent = vui->colorDescPresent; @@ -7217,7 +9443,7 @@ ni_retcode_t ni_reconfig_vui(ni_session_context_t *p_ctx, ni_vui_hrd_t *vui) p_ctx->vui.videoFullRange = vui->videoFullRange; p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } @@ -7233,23 +9459,23 @@ ni_retcode_t ni_force_idr_frame_type(ni_session_context_t *p_ctx) { if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; if (p_ctx->force_idr_frame) { - ni_log(NI_LOG_DEBUG, "Warning: %s(): already forcing IDR frame\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning: %s(): already forcing IDR frame\n", __func__); } p_ctx->force_idr_frame = 1; p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } @@ -7267,17 +9493,17 @@ ni_retcode_t ni_set_ltr(ni_session_context_t *p_ctx, ni_long_term_ref_t *ltr) { if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->ltr_to_set.use_cur_src_as_long_term_pic = ltr->use_cur_src_as_long_term_pic; p_ctx->ltr_to_set.use_long_term_ref = ltr->use_long_term_ref; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } @@ -7296,15 +9522,15 @@ ni_retcode_t ni_set_ltr_interval(ni_session_context_t *p_ctx, { if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->ltr_interval = ltr_interval; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } @@ -7324,13 +9550,13 @@ ni_retcode_t ni_set_frame_ref_invalid(ni_session_context_t *p_ctx, { if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->ltr_frame_ref_invalid = frame_num; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } @@ -7351,7 +9577,7 @@ ni_retcode_t ni_reconfig_framerate(ni_session_context_t *p_ctx, int32_t framerate_denom = framerate->framerate_denom; if (!p_ctx || framerate_num <= 0 || framerate_denom <= 0) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid framerate passed in (%d/%d)\n", __func__, framerate_num, framerate_denom); return NI_RETCODE_INVALID_PARAM; @@ -7373,18 +9599,18 @@ ni_retcode_t ni_reconfig_framerate(ni_session_context_t *p_ctx, if (((framerate_num + framerate_denom - 1) / framerate_denom) > NI_MAX_FRAMERATE) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid framerate passed in (%d/%d)\n", __func__, framerate->framerate_num, framerate->framerate_denom); return NI_RETCODE_INVALID_PARAM; } - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; if (p_ctx->framerate.framerate_num > 0) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning: %s(): framerate (%d/%d) overwriting current " "one (%d/%d)\n", __func__, framerate_num, framerate_denom, @@ -7396,7 +9622,430 @@ ni_retcode_t ni_reconfig_framerate(ni_session_context_t *p_ctx, p_ctx->framerate.framerate_denom = framerate_denom; p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure maxFrameSize dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] max_frame_size maxFrameSize to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + * + * NOTE - maxFrameSize_Bytes value less than ((bitrate / 8) / framerate) will be rejected + * + ******************************************************************************/ +ni_retcode_t ni_reconfig_max_frame_size(ni_session_context_t *p_ctx, int32_t max_frame_size) +{ + ni_xcoder_params_t *api_param; + int32_t bitrate, framerate_num, framerate_denom; + uint32_t maxFrameSize = (uint32_t)max_frame_size / 2000; + uint32_t min_maxFrameSize; + + if (!p_ctx || !p_ctx->p_session_config) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_session_config pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + api_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + + if (!api_param->low_delay_mode) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size is valid only when lowDelay mode is enabled\n", + __func__, max_frame_size); + return NI_RETCODE_INVALID_PARAM; + } + + bitrate = (p_ctx->target_bitrate > 0) ? p_ctx->target_bitrate : api_param->bitrate; + + if ((p_ctx->framerate.framerate_num > 0) && (p_ctx->framerate.framerate_denom > 0)) + { + framerate_num = p_ctx->framerate.framerate_num; + framerate_denom = p_ctx->framerate.framerate_denom; + } + else + { + framerate_num = (int32_t) api_param->fps_number; + framerate_denom = (int32_t) api_param->fps_denominator; + } + + min_maxFrameSize = (((uint32_t)bitrate / framerate_num * framerate_denom) / 8) / 2000; + + if (maxFrameSize < min_maxFrameSize) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is too small (invalid)\n", + __func__, max_frame_size); + return NI_RETCODE_INVALID_PARAM; + } + if (max_frame_size > NI_MAX_FRAME_SIZE) { + max_frame_size = NI_MAX_FRAME_SIZE; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + if (p_ctx->max_frame_size > 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Warning: %s(): max_frame_size %d overwriting current one %d\n", + __func__, max_frame_size, p_ctx->max_frame_size); + } + + p_ctx->max_frame_size = max_frame_size; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure min&max qp dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] ni_rc_min_max_qp Target min&max qp to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_min_max_qp(ni_session_context_t *p_ctx, + ni_rc_min_max_qp *p_min_max_qp) +{ + int32_t minQpI, maxQpI, maxDeltaQp, minQpPB, maxQpPB; + + if (!p_ctx || !p_min_max_qp) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_min_max_qp pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + minQpI = p_min_max_qp->minQpI; + maxQpI = p_min_max_qp->maxQpI; + maxDeltaQp = p_min_max_qp->maxDeltaQp; + minQpPB = p_min_max_qp->minQpPB; + maxQpPB = p_min_max_qp->maxQpPB; + + if (minQpI > maxQpI || minQpPB > maxQpPB || + maxQpI > 51 || minQpI < 0 || maxQpPB > 51 || minQpPB < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid qp setting <%d %d %d %d %d>\n", + __func__, minQpI, maxQpI, maxDeltaQp, minQpPB, maxQpPB); + return NI_RETCODE_INVALID_PARAM; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + p_ctx->enc_change_params->minQpI = minQpI; + p_ctx->enc_change_params->maxQpI = maxQpI; + p_ctx->enc_change_params->maxDeltaQp = maxDeltaQp; + p_ctx->enc_change_params->minQpPB = minQpPB; + p_ctx->enc_change_params->maxQpPB = maxQpPB; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure crf value dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] crf crf value to reconfigure + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_crf(ni_session_context_t *p_ctx, + int32_t crf) +{ + ni_xcoder_params_t *api_param; + + if (!p_ctx || !p_ctx->p_session_config) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_session_config pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + api_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + + if (api_param->cfg_enc_params.crf < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %d is valid only in CRF mode\n", + __func__, crf); + return NI_RETCODE_INVALID_PARAM; + } + + if (crf < 0 || crf > 51) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %d is invalid (valid range in [0..51])\n", + __func__, crf); + return NI_RETCODE_INVALID_PARAM; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + if (p_ctx->reconfig_crf >= 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Warning: %s(): crf reconfig value %d overwriting current reconfig_crf %d\n", + __func__, crf, p_ctx->reconfig_crf); + } + + p_ctx->reconfig_crf = crf; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure crf float point value dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] crf crf float point value to reconfigure + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_crf2(ni_session_context_t *p_ctx, + float crf) +{ + ni_xcoder_params_t *api_param; + + if (!p_ctx || !p_ctx->p_session_config) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_session_config pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + api_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + + if (api_param->cfg_enc_params.crfFloat < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %f is valid only in CRF mode\n", + __func__, crf); + return NI_RETCODE_INVALID_PARAM; + } + + if (crf < 0.0 || crf > 51.0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %f is invalid (valid range in [0..51])\n", + __func__, crf); + return NI_RETCODE_INVALID_PARAM; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + if (p_ctx->reconfig_crf >= 0 || p_ctx->reconfig_crf_decimal > 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Warning: %s(): crf reconfig value %d overwriting current " + "reconfig_crf %d, reconfig_crf_decimal %d\n", __func__, + crf, p_ctx->reconfig_crf, p_ctx->reconfig_crf_decimal); + } + + p_ctx->reconfig_crf = (int)crf; + p_ctx->reconfig_crf_decimal = (int)((crf - (float)p_ctx->reconfig_crf) * 100); + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure vbv buffer size and vbv max rate dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] vbvBufferSize Target vbvBufferSize to set + * \param[in] vbvMaxRate Target vbvMaxRate to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_vbv_value(ni_session_context_t *p_ctx, + int32_t vbvMaxRate, int32_t vbvBufferSize) +{ + ni_xcoder_params_t *api_param; + if (!p_ctx || !p_ctx->p_session_config) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_session_config pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + if ((vbvBufferSize < 10 && vbvBufferSize != 0) || vbvBufferSize > 3000) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): vbvBufferSize value %d\n", + __func__, vbvBufferSize); + return NI_RETCODE_INVALID_PARAM; + } + api_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + if (api_param->bitrate > 0 && vbvMaxRate > 0 && vbvMaxRate < api_param->bitrate) { + ni_log2(p_ctx, NI_LOG_ERROR, "vbvMaxRate %u cannot be smaller than bitrate %d\n", + vbvMaxRate, api_param->bitrate); + return NI_RETCODE_INVALID_PARAM; + } + if (vbvBufferSize == 0 && vbvMaxRate > 0) { + ni_log2(p_ctx, NI_LOG_INFO, "vbvMaxRate %d does not take effect when " + "vbvBufferSize is 0, force vbvMaxRate to 0\n", + vbvMaxRate); + vbvMaxRate = 0; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + p_ctx->reconfig_vbv_buffer_size = vbvBufferSize; + p_ctx->reconfig_vbv_max_rate = vbvMaxRate; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure maxFrameSizeRatio dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] max_frame_size_ratio maxFrameSizeRatio to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_max_frame_size_ratio(ni_session_context_t *p_ctx, int32_t max_frame_size_ratio) +{ + ni_xcoder_params_t *api_param; + int32_t bitrate, framerate_num, framerate_denom; + uint32_t min_maxFrameSize, maxFrameSize; + + if (!p_ctx || !p_ctx->p_session_config) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_session_config pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + api_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + + if (!api_param->low_delay_mode) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size_ratio is valid only when lowDelay mode is enabled\n", + __func__, max_frame_size_ratio); + return NI_RETCODE_INVALID_PARAM; + } + + if (max_frame_size_ratio < 1) { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size_ratio %d cannot < 1\n", + max_frame_size_ratio); + return NI_RETCODE_INVALID_PARAM; + } + + bitrate = (p_ctx->target_bitrate > 0) ? p_ctx->target_bitrate : api_param->bitrate; + + if ((p_ctx->framerate.framerate_num > 0) && (p_ctx->framerate.framerate_denom > 0)) + { + framerate_num = p_ctx->framerate.framerate_num; + framerate_denom = p_ctx->framerate.framerate_denom; + } + else + { + framerate_num = (int32_t) api_param->fps_number; + framerate_denom = (int32_t) api_param->fps_denominator; + } + + min_maxFrameSize = (((uint32_t)bitrate / framerate_num * framerate_denom) / 8) / 2000; + + maxFrameSize = min_maxFrameSize * max_frame_size_ratio > NI_MAX_FRAME_SIZE ? + NI_MAX_FRAME_SIZE : min_maxFrameSize * max_frame_size_ratio; + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + if (p_ctx->max_frame_size > 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Warning: %s(): max_frame_size %d overwriting current one %d\n", + __func__, maxFrameSize, p_ctx->max_frame_size); + } + + p_ctx->max_frame_size = maxFrameSize; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Reconfigure sliceArg dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] sliceArg the new sliceArg value + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_reconfig_slice_arg(ni_session_context_t *p_ctx, int16_t sliceArg) +{ + ni_xcoder_params_t *api_param; + ni_encoder_cfg_params_t *p_enc; + + if (!p_ctx || !p_ctx->p_session_config) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid ni_session_context_t or p_session_config pointer\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + api_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + p_enc = &api_param->cfg_enc_params; + if (p_enc->slice_mode == 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s():not support to reconfig slice_arg when slice_mode disable.\n", + __func__); + sliceArg = 0; + } + if (NI_CODEC_FORMAT_JPEG == p_ctx->codec_format || NI_CODEC_FORMAT_AV1 == p_ctx->codec_format) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s():sliceArg is only supported for H.264 or H.265.\n", + __func__); + sliceArg = 0; + } + int ctu_mb_size = (NI_CODEC_FORMAT_H264 == p_ctx->codec_format) ? 16 : 64; + int max_num_ctu_mb_row = (api_param->source_height + ctu_mb_size - 1) / ctu_mb_size; + if (sliceArg < 1 || sliceArg > max_num_ctu_mb_row) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid data sliceArg %d\n", __func__, + sliceArg); + sliceArg = 0; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + p_ctx->xcoder_state |= NI_XCODER_GENERAL_STATE; + + p_ctx->reconfig_slice_arg = sliceArg; + + p_ctx->xcoder_state &= ~NI_XCODER_GENERAL_STATE; + ni_pthread_mutex_unlock(&p_ctx->mutex); return NI_RETCODE_SUCCESS; } @@ -7429,31 +10078,31 @@ int ni_device_session_acquire(ni_session_context_t *p_ctx, ni_frame_t *p_frame) if (p_ctx == NULL || p_frame == NULL || p_frame->p_data[3] == NULL) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } p_surface = (niFrameSurface1_t *)p_frame->p_data[3]; - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_lock(&p_ctx->mutex); p_ctx->xcoder_state = NI_XCODER_HWUP_STATE; retval = ni_hwupload_session_read_hwdesc(p_ctx, &hwdesc); p_ctx->xcoder_state = NI_XCODER_IDLE_STATE; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR: hwdesc read failure %d\n", retval); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: hwdesc read failure %d\n", retval); return retval; } retval = ni_get_memory_offset(p_ctx, &hwdesc, &offset); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR: bad buffer id\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: bad buffer id\n"); return NI_RETCODE_INVALID_PARAM; } @@ -7480,7 +10129,7 @@ int ni_device_session_acquire(ni_session_context_t *p_ctx, ni_frame_t *p_frame) ret = ioctl(p_ctx->netint_fd, NETINT_IOCTL_EXPORT_DMABUF, &uexp); if (ret < 0) { - ni_log(NI_LOG_ERROR, "%s: Failed to export dmabuf %d errno %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s: Failed to export dmabuf %d errno %d\n", __func__, ret, NI_ERRNO); return NI_RETCODE_FAILURE; } @@ -7488,7 +10137,7 @@ int ni_device_session_acquire(ni_session_context_t *p_ctx, ni_frame_t *p_frame) *p_surface = hwdesc; p_surface->ui16width = p_ctx->active_video_width; p_surface->ui16height = p_ctx->active_video_height; - p_surface->ui32nodeAddress = 0; // unused field + p_surface->ui32nodeAddress = offset; p_surface->encoding_type = is_semi_planar ? NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR : NI_PIXEL_PLANAR_FORMAT_PLANAR; @@ -7518,13 +10167,13 @@ ni_retcode_t ni_uploader_frame_buffer_lock(ni_session_context_t *p_upl_ctx, if (p_upl_ctx == NULL || p_frame == NULL) { - ni_log(NI_LOG_ERROR, "%s: bad parameters\n", __func__); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: bad parameters\n", __func__); return NI_RETCODE_INVALID_PARAM; } if (p_frame->p_data[3] == NULL) { - ni_log(NI_LOG_ERROR, "%s: not a hardware frame\n", __func__); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: not a hardware frame\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -7537,8 +10186,8 @@ ni_retcode_t ni_uploader_frame_buffer_lock(ni_session_context_t *p_upl_ctx, ret = poll(pfds, 1, -1); if (ret < 0) { - ni_log(NI_LOG_ERROR, "%s:failed to poll dmabuf fd errno %d\n", __func__, - NI_ERRNO); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s:failed to poll dmabuf fd errno %s\n", __func__, + strerror(NI_ERRNO)); return ret; } @@ -7546,9 +10195,9 @@ ni_retcode_t ni_uploader_frame_buffer_lock(ni_session_context_t *p_upl_ctx, ret = ioctl(p_upl_ctx->netint_fd, NETINT_IOCTL_ATTACH_RFENCE, &uatch); if (ret < 0) { - ni_log(NI_LOG_ERROR, - "%s: failed to attach dmabuf read fence errno %d\n", __func__, - NI_ERRNO); + ni_log2(p_upl_ctx, NI_LOG_ERROR, + "%s: failed to attach dmabuf read fence errno %s\n", __func__, + strerror(NI_ERRNO)); return ret; } @@ -7575,7 +10224,7 @@ ni_retcode_t ni_uploader_frame_buffer_unlock(ni_session_context_t *p_upl_ctx, if ((p_upl_ctx == NULL) || (p_frame == NULL)) { - ni_log(NI_LOG_ERROR, "%s: Invalid parameters %p %p\n", __func__, + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: Invalid parameters %p %p\n", __func__, p_upl_ctx, p_frame); return NI_RETCODE_INVALID_PARAM; } @@ -7584,7 +10233,7 @@ ni_retcode_t ni_uploader_frame_buffer_unlock(ni_session_context_t *p_upl_ctx, if (p_surface == NULL) { - ni_log(NI_LOG_ERROR, "%s: Invalid hw frame\n", __func__); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: Invalid hw frame\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -7592,7 +10241,7 @@ ni_retcode_t ni_uploader_frame_buffer_unlock(ni_session_context_t *p_upl_ctx, ret = ioctl(p_upl_ctx->netint_fd, NETINT_IOCTL_SIGNAL_RFENCE, &usigl); if (ret < 0) { - ni_log(NI_LOG_ERROR, "Failed to signal dmabuf read fence\n"); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "Failed to signal dmabuf read fence\n"); return NI_RETCODE_FAILURE; } @@ -7624,13 +10273,13 @@ ni_retcode_t ni_uploader_p2p_test_send(ni_session_context_t *p_upl_ctx, if (p_upl_ctx == NULL || p_data == NULL || p_hwframe == NULL) { - ni_log(NI_LOG_ERROR, "%s: invalid null parameters\n", __func__); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: invalid null parameters\n", __func__); return NI_RETCODE_INVALID_PARAM; } if (p_hwframe->p_data[3] == NULL) { - ni_log(NI_LOG_ERROR, "%s: empty frame\n", __func__); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: empty frame\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -7639,11 +10288,12 @@ ni_retcode_t ni_uploader_p2p_test_send(ni_session_context_t *p_upl_ctx, uis.fd = p_surface->dma_buf_fd; uis.data = p_data; uis.len = len; + uis.dir = NI_DMABUF_WRITE_TO_DEVICE; ret = ioctl(p_upl_ctx->netint_fd, NETINT_IOCTL_ISSUE_REQ, &uis); if (ret < 0) { - ni_log(NI_LOG_ERROR, + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: Failed to request dmabuf rendering errno %d\n", __func__, NI_ERRNO); return NI_RETCODE_FAILURE; @@ -7666,7 +10316,6 @@ ni_retcode_t ni_uploader_p2p_test_send(ni_session_context_t *p_upl_ctx, ni_retcode_t ni_hwframe_p2p_buffer_recycle(ni_frame_t *p_frame) { niFrameSurface1_t *p_surface; - ni_retcode_t rc = NI_RETCODE_SUCCESS; if (p_frame == NULL) { @@ -7675,17 +10324,28 @@ ni_retcode_t ni_hwframe_p2p_buffer_recycle(ni_frame_t *p_frame) } p_surface = (niFrameSurface1_t *)p_frame->p_data[3]; - if (p_surface == NULL) { ni_log(NI_LOG_ERROR, "%s: Invalid surface data\n", __func__); return NI_RETCODE_INVALID_PARAM; } - rc = ni_hwframe_buffer_recycle(p_surface, p_surface->device_handle); - return rc; + return ni_hwframe_buffer_recycle2(p_surface); } +/*!***************************************************************************** + * \brief Acquire the scaler P2P DMA buffer for read/write + * + * \param [in] p_ctx pointer to caller allocated upload context + * [in] p_surface pointer to a caller allocated hardware frame + * [in] data_len scaler frame buffer data length + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_FAILURE +*******************************************************************************/ ni_retcode_t ni_scaler_p2p_frame_acquire(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, int data_len) @@ -7696,7 +10356,7 @@ ni_retcode_t ni_scaler_p2p_frame_acquire(ni_session_context_t *p_ctx, ret = ni_get_memory_offset(p_ctx, p_surface, &offset); if (ret != 0) { - ni_log(NI_LOG_ERROR, "Error: bad buffer id\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "Error: bad buffer id\n"); return NI_RETCODE_FAILURE; } p_surface->ui32nodeAddress = 0; @@ -7714,7 +10374,7 @@ ni_retcode_t ni_scaler_p2p_frame_acquire(ni_session_context_t *p_ctx, ret = ioctl(p_ctx->netint_fd, NETINT_IOCTL_EXPORT_DMABUF, &uexp); if (ret < 0) { - ni_log(NI_LOG_ERROR, "failed to export dmabuf: %s\n", strerror(errno)); + ni_log2(p_ctx, NI_LOG_ERROR, "failed to export dmabuf: %s\n", strerror(errno)); return NI_RETCODE_FAILURE; } p_surface->dma_buf_fd = uexp.fd; @@ -7751,26 +10411,26 @@ ni_retcode_t ni_encoder_set_input_frame_format(ni_session_context_t *p_enc_ctx, if (p_enc_ctx == NULL || p_enc_params == NULL) { - ni_log(NI_LOG_ERROR, "%s: null ptr\n", __func__); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s: null ptr\n", __func__); return NI_RETCODE_INVALID_PARAM; } if (!(bit_depth == 8) && !(bit_depth == 10)) { - ni_log(NI_LOG_ERROR, "%s: bad bit depth %d\n", __func__, bit_depth); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s: bad bit depth %d\n", __func__, bit_depth); return NI_RETCODE_INVALID_PARAM; } if (!(src_endian == NI_FRAME_LITTLE_ENDIAN) && !(src_endian == NI_FRAME_BIG_ENDIAN)) { - ni_log(NI_LOG_ERROR, "%s: bad endian %d\n", __func__, src_endian); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s: bad endian %d\n", __func__, src_endian); return NI_RETCODE_INVALID_PARAM; } - if (!(planar == 0) && !(planar == 1)) + if ((planar < 0) || (planar >= NI_PIXEL_PLANAR_MAX)) { - ni_log(NI_LOG_ERROR, "%s: bad planar value %d\n", __func__, planar); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s: bad planar value %d\n", __func__, planar); return NI_RETCODE_INVALID_PARAM; } @@ -7834,14 +10494,7 @@ ni_retcode_t ni_uploader_set_frame_format(ni_session_context_t *p_upl_ctx, { if (p_upl_ctx == NULL) { - ni_log(NI_LOG_ERROR, "%s: null ptr\n", __func__); - return NI_RETCODE_INVALID_PARAM; - } - - if (pixel_format == NI_PIX_FMT_NONE || pixel_format == NI_PIX_FMT_RGBA) - { - ni_log(NI_LOG_ERROR, "%s: Invalid pixel format %d\n", __func__, - pixel_format); + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: null ptr\n", __func__); return NI_RETCODE_INVALID_PARAM; } @@ -7852,15 +10505,22 @@ ni_retcode_t ni_uploader_set_frame_format(ni_session_context_t *p_upl_ctx, p_upl_ctx->src_bit_depth = 8; p_upl_ctx->bit_depth_factor = 1; break; - case NI_PIX_FMT_YUV420P10LE: case NI_PIX_FMT_P010LE: p_upl_ctx->src_bit_depth = 10; p_upl_ctx->bit_depth_factor = 2; break; - + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_BGR0: + case NI_PIX_FMT_BGRP: + p_upl_ctx->src_bit_depth = 8; + p_upl_ctx->bit_depth_factor = 4; + break; default: - ni_log(NI_LOG_ERROR, "%s: Invalid pixfmt %d\n", __func__, + ni_log2(p_upl_ctx, NI_LOG_ERROR, "%s: Invalid pixfmt %d\n", __func__, pixel_format); return NI_RETCODE_INVALID_PARAM; } @@ -7899,7 +10559,7 @@ int ni_encoder_session_read_stream_header(ni_session_context_t *p_ctx, /* This function should be called once at the start of encoder read */ if (p_ctx->pkt_num != 0) { - ni_log(NI_LOG_ERROR, "Error: stream header has already been read\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "Error: stream header has already been read\n"); return NI_RETCODE_ERROR_INVALID_SESSION; } @@ -7913,16 +10573,16 @@ int ni_encoder_session_read_stream_header(ni_session_context_t *p_ctx, bytes_read += (rx_size - (int)p_ctx->meta_size); p_ctx->pkt_num = 1; - ni_log(NI_LOG_DEBUG, "Got encoded stream header\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "Got encoded stream header\n"); done = 1; } else if (rx_size != 0) { - ni_log(NI_LOG_ERROR, "Error: received rx_size = %d\n", rx_size); + ni_log2(p_ctx, NI_LOG_ERROR, "Error: received rx_size = %d\n", rx_size); bytes_read = -1; done = 1; } else { - ni_log(NI_LOG_DEBUG, "No data, keep reading..\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "No data, keep reading..\n"); continue; } } @@ -7977,34 +10637,46 @@ int32_t ni_get_dma_buf_file_descriptor(const ni_frame_t* p_frame) * NI_RETCODE_ERROR_MEM_ALOC * NI_RETCODE_ERROR_NVME_CMD_FAILED * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION ******************************************************************************/ ni_retcode_t ni_device_session_sequence_change(ni_session_context_t *p_ctx, int width, int height, int bit_depth_factor, ni_device_type_t device_type) { ni_resolution_t resolution; ni_retcode_t retval = NI_RETCODE_SUCCESS; + ni_xcoder_params_t *p_param = NULL; // requires API version >= 54 - if (p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] < (uint8_t)'5' || - (p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX] < (uint8_t)'4' && - p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] == (uint8_t)'5')) + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "54") < 0) { - ni_log(NI_LOG_ERROR, "Error: %s function not supported in FW API version %c%c\n", __func__, - (char)p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - (char)p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX]); - return NI_RETCODE_ERROR_INVALID_SESSION; + ni_log2(p_ctx, NI_LOG_ERROR, "Error: %s function not supported on device with FW API version < 5.4\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; } /* This function should be called only if sequence change is detected */ if (p_ctx->session_run_state != SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) { - ni_log(NI_LOG_ERROR, "Error: stream header has already been read\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "Error: stream header has already been read\n"); return NI_RETCODE_ERROR_INVALID_SESSION; } resolution.width = width; resolution.height = height; resolution.bit_depth_factor = bit_depth_factor; + resolution.luma_linesize = 0; + resolution.chroma_linesize = 0; + if (p_ctx->p_session_config) + { + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + resolution.luma_linesize = p_param->luma_linesize; + resolution.chroma_linesize = p_param->chroma_linesize; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: resolution change config - width %d height %d bit_depth_factor %d " + "luma_linesize %d chroma_linesize %d\n", __func__, + resolution.width, resolution.height, resolution.bit_depth_factor, + resolution.luma_linesize, resolution.chroma_linesize); switch (device_type) { @@ -8017,10 +10689,1437 @@ ni_retcode_t ni_device_session_sequence_change(ni_session_context_t *p_ctx, default: { retval = NI_RETCODE_INVALID_PARAM; - ni_log(NI_LOG_ERROR, "ERROR: Config sequence change not supported for device type: %d", device_type); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Config sequence change not supported for device type: %d", device_type); return retval; } } return retval; } +ni_retcode_t ni_ai_session_read_metrics(ni_session_context_t *p_ctx, + ni_network_perf_metrics_t *p_metrics) +{ + return ni_ai_session_query_metrics(p_ctx, p_metrics); +} + +ni_retcode_t ni_query_fl_fw_versions(ni_device_handle_t device_handle, + ni_device_info_t *p_dev_info) +{ + void *buffer; + uint32_t size; + ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; + ni_log_fl_fw_versions_t fl_fw_versions; + + if ((NI_INVALID_DEVICE_HANDLE == device_handle) || (!p_dev_info)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (ni_cmp_fw_api_ver((char*) &p_dev_info->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6h") < 0) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s function not supported on device with FW API version < 6.h\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + buffer = NULL; + size = ((sizeof(ni_log_fl_fw_versions_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + if (ni_posix_memalign((void **)&buffer, sysconf(_SC_PAGESIZE), size)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } + + memset(buffer, 0, size); + + if (ni_nvme_send_read_cmd(device_handle, + event_handle, + buffer, + size, + QUERY_GET_VERSIONS_R) < 0) + { + ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_aligned_free(buffer); + return NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + + memcpy(&fl_fw_versions, buffer, sizeof(ni_log_fl_fw_versions_t)); + + memcpy(p_dev_info->fl_ver_last_ran, + &fl_fw_versions.last_ran_fl_version, + NI_VERSION_CHARACTER_COUNT); + memcpy(p_dev_info->fl_ver_nor_flash, + &fl_fw_versions.nor_flash_fl_version, + NI_VERSION_CHARACTER_COUNT); + memcpy(p_dev_info->fw_rev_nor_flash, + &fl_fw_versions.nor_flash_fw_revision, + NI_VERSION_CHARACTER_COUNT); + + ni_aligned_free(buffer); + return NI_RETCODE_SUCCESS; +} + +ni_retcode_t ni_query_nvme_status(ni_session_context_t *p_ctx, + ni_load_query_t *p_load_query) +{ + void *buffer; + uint32_t size; + + ni_instance_mgr_general_status_t general_status; + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: p_ctx cannot be null\n"); + return NI_RETCODE_INVALID_PARAM; + } + if (!p_load_query) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: p_load_query cannot be null\n"); + return NI_RETCODE_INVALID_PARAM; + } + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6O") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s function not supported on device with FW API version < 6.O\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + buffer = NULL; + size = ((sizeof(ni_instance_mgr_general_status_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + if (ni_posix_memalign((void **)&buffer, sysconf(_SC_PAGESIZE), size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } + + memset(buffer, 0, size); + + if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, + p_ctx->event_handle, + buffer, + size, + QUERY_GET_NVME_STATUS_R) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_aligned_free(buffer); + return NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + + memcpy(&general_status, buffer, sizeof(ni_instance_mgr_general_status_t)); + + p_load_query->tp_fw_load = general_status.tp_fw_load; + p_load_query->pcie_load = general_status.pcie_load; + p_load_query->pcie_throughput = general_status.pcie_throughput; + p_load_query->fw_load = general_status.fw_load; + p_load_query->fw_share_mem_usage = general_status.fw_share_mem_usage; + + ni_aligned_free(buffer); + return NI_RETCODE_SUCCESS; +} + +ni_retcode_t ni_query_vf_ns_id(ni_device_handle_t device_handle, + ni_device_vf_ns_id_t *p_dev_ns_vf, + uint8_t fw_rev[]) +{ + void *p_buffer = NULL; + uint32_t size; + ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; + + if ((NI_INVALID_DEVICE_HANDLE == device_handle) || (!p_dev_ns_vf)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (ni_cmp_fw_api_ver((char*) &fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6m") < 0) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s function not supported on device with FW API version < 6.m\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + size = ((sizeof(ni_device_vf_ns_id_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + if (ni_posix_memalign((void **)&p_buffer, sysconf(_SC_PAGESIZE), size)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } + + memset(p_buffer, 0, size); + + if (ni_nvme_send_read_cmd(device_handle, + event_handle, + p_buffer, + size, + QUERY_GET_NS_VF_R) < 0) + { + ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_aligned_free(p_buffer); + return NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + + ni_device_vf_ns_id_t *p_dev_ns_vf_data = (ni_device_vf_ns_id_t *)p_buffer; + p_dev_ns_vf->vf_id = p_dev_ns_vf_data->vf_id; + p_dev_ns_vf->ns_id = p_dev_ns_vf_data->ns_id; + ni_log(NI_LOG_DEBUG, "%s(): NS/VF %u/%u\n", __func__, p_dev_ns_vf->ns_id, p_dev_ns_vf->vf_id); + ni_aligned_free(p_buffer); + return NI_RETCODE_SUCCESS; +} + +ni_retcode_t ni_query_temperature(ni_device_handle_t device_handle, + ni_device_temp_t *p_dev_temp, + uint8_t fw_rev[]) +{ + void *p_buffer = NULL; + uint32_t size; + ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; + + if ((NI_INVALID_DEVICE_HANDLE == device_handle) || (!p_dev_temp)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (ni_cmp_fw_api_ver((char*) &fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rC") < 0) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s function not supported on device with FW API version < 6rC\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + size = ((sizeof(ni_device_temp_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + if (ni_posix_memalign((void **)&p_buffer, sysconf(_SC_PAGESIZE), size)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } + + memset(p_buffer, 0, size); + + if (ni_nvme_send_read_cmd(device_handle, + event_handle, + p_buffer, + size, + QUERY_GET_TEMPERATURE_R) < 0) + { + ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_aligned_free(p_buffer); + return NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + + ni_device_temp_t *p_dev_temp_data = (ni_device_temp_t *)p_buffer; + p_dev_temp->composite_temp = p_dev_temp_data->composite_temp; + p_dev_temp->on_board_temp = p_dev_temp_data->on_board_temp; + p_dev_temp->on_die_temp = p_dev_temp_data->on_die_temp; + ni_log(NI_LOG_DEBUG, "%s(): current composite temperature %d on board temperature %d on die temperature %d\n", + __func__, p_dev_temp->composite_temp, p_dev_temp->on_board_temp, p_dev_temp->on_die_temp); + ni_aligned_free(p_buffer); + return NI_RETCODE_SUCCESS; +} + +ni_retcode_t ni_query_extra_info(ni_device_handle_t device_handle, + ni_device_extra_info_t *p_dev_extra_info, + uint8_t fw_rev[]) +{ + void *p_buffer = NULL; + uint32_t size; + ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; + + if ((NI_INVALID_DEVICE_HANDLE == device_handle) || (!p_dev_extra_info)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s(): passed parameters are null, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (ni_cmp_fw_api_ver((char*) &fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rC") < 0) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s function not supported on device with FW API version < 6rC\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + size = ((sizeof(ni_device_extra_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + if (ni_posix_memalign((void **)&p_buffer, sysconf(_SC_PAGESIZE), size)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } + + memset(p_buffer, 0, size); + + if (ni_nvme_send_read_cmd(device_handle, + event_handle, + p_buffer, + size, + QUERY_GET_EXTTRA_INFO_R) < 0) + { + ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_aligned_free(p_buffer); + return NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + + ni_device_extra_info_t *p_dev_extra_info_data = (ni_device_extra_info_t *)p_buffer; + p_dev_extra_info->composite_temp = p_dev_extra_info_data->composite_temp; + p_dev_extra_info->on_board_temp = p_dev_extra_info_data->on_board_temp; + p_dev_extra_info->on_die_temp = p_dev_extra_info_data->on_die_temp; + if (ni_cmp_fw_api_ver((char*) &fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6rC") >= 0 && + ni_cmp_fw_api_ver((char*) &fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6rR") < 0) + { + p_dev_extra_info->power_consumption = 0xFFFFFFFF; + } + else + { + p_dev_extra_info->power_consumption = p_dev_extra_info_data->power_consumption; + } + ni_log(NI_LOG_DEBUG, "%s(): current composite temperature %d on board temperature %d " + "on die temperature %d power consumption %d\n", + __func__, p_dev_extra_info->composite_temp, p_dev_extra_info->on_board_temp, + p_dev_extra_info->on_die_temp, p_dev_extra_info->power_consumption); + ni_aligned_free(p_buffer); + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** + * \brief Allocate log buffer if needed and retrieve firmware logs from device + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_log_buffer Reference to pointer to a log buffer + * If log buffer pointer is NULL, this function will allocate log buffer + * NOTE caller is responsible for freeing log buffer after calling this function + * \param[in] gen_log_file Indicating whether it is required to generate log files + * + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_INVALID_PARAM +*******************************************************************************/ +ni_retcode_t ni_device_alloc_and_get_firmware_logs(ni_session_context_t *p_ctx, void** p_log_buffer, bool gen_log_file) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + if (*p_log_buffer == NULL) + { + if (ni_posix_memalign(p_log_buffer, sysconf(_SC_PAGESIZE), TOTAL_CPU_LOG_BUFFER_SIZE)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate log buffer\n", + NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } + } + + if(*p_log_buffer != NULL){ + memset(*p_log_buffer, 0, TOTAL_CPU_LOG_BUFFER_SIZE); + retval = ni_dump_log_all_cores(p_ctx, *p_log_buffer, gen_log_file); // dump FW logs + }else{ + return NI_RETCODE_ERROR_MEM_ALOC; + } + + return retval; +} + +/*!***************************************************************************** + * \brief Set up hard coded demo ROI map + * + * \param[in] p_enc_ctx Pointer to a caller allocated + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_ERROR_MEM_ALOC +*******************************************************************************/ +ni_retcode_t ni_set_demo_roi_map(ni_session_context_t *p_enc_ctx) +{ + ni_xcoder_params_t *p_param = + (ni_xcoder_params_t *)(p_enc_ctx->p_session_config); + int sumQp = 0, ctu, i, j; + // mode 1: Set QP for center 1/3 of picture to highest - lowest quality + // the rest to lowest - highest quality; + // mode non-1: reverse of mode 1 + int importanceLevelCentre = p_param->roi_demo_mode == 1 ? 40 : 10; + int importanceLevelRest = p_param->roi_demo_mode == 1 ? 10 : 40; + int linesize_aligned = p_param->source_width; + int height_aligned = p_param->source_height; + if (QUADRA) + { + uint32_t block_size, max_cu_size, customMapSize; + uint32_t mbWidth; + uint32_t mbHeight; + uint32_t numMbs; + uint32_t roiMapBlockUnitSize; + uint32_t entryPerMb; + uint32_t entryWidth; + uint32_t entryPos; + bool bIsCenter; + + max_cu_size = p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264 ? 16: 64; + // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation + if (NI_CODEC_FORMAT_AV1 == p_enc_ctx->codec_format) + { + linesize_aligned = (linesize_aligned / 8) * 8; + height_aligned = (height_aligned / 8) * 8; + } + + // (ROI map version >= 1) each QP info takes 8-bit, represent 8 x 8 + // pixel block + block_size = + ((linesize_aligned + max_cu_size - 1) & (~(max_cu_size - 1))) * + ((height_aligned + max_cu_size - 1) & (~(max_cu_size - 1))) / + (8 * 8); + + // need to align to 64 bytes + customMapSize = ((block_size + 63) & (~63)); + if (!p_enc_ctx->roi_map) + { + p_enc_ctx->roi_map = + (ni_enc_quad_roi_custom_map *)calloc(1, customMapSize); + } + if (!p_enc_ctx->roi_map) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + + // for H.264, select ROI Map Block Unit Size: 16x16 + // for H.265, select ROI Map Block Unit Size: 64x64 + roiMapBlockUnitSize = p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264 ? 16 : 64; + + mbWidth = + ((linesize_aligned + max_cu_size - 1) & (~(max_cu_size - 1))) / + roiMapBlockUnitSize; + mbHeight = + ((height_aligned + max_cu_size - 1) & (~(max_cu_size - 1))) / + roiMapBlockUnitSize; + numMbs = mbWidth * mbHeight; + + // copy roi MBs QPs into custom map + // number of qp info (8x8) per mb or ctb + entryPerMb = (roiMapBlockUnitSize / 8) * (roiMapBlockUnitSize / 8); + entryWidth = roiMapBlockUnitSize / 8; + for (i = 0; i < numMbs; i++) + { + for (j = 0; j < entryPerMb; j++) + { + entryPos = (i % mbWidth) * entryWidth + j % entryWidth; + bIsCenter = (entryPos >= mbWidth * entryWidth / 3) && (entryPos < mbWidth * entryWidth * 2 / 3); + /* + g_quad_roi_map[i*4+j].field.skip_flag = 0; // don't force + skip mode g_quad_roi_map[i*4+j].field.roiAbsQp_flag = 1; // + absolute QP g_quad_roi_map[i*4+j].field.qp_info = bIsCenter + ? importanceLevelCentre : importanceLevelRest; + */ + p_enc_ctx->roi_map[i * entryPerMb + j].field.ipcm_flag = + 0; // don't force skip mode + p_enc_ctx->roi_map[i * entryPerMb + j] + .field.roiAbsQp_flag = 1; // absolute QP + p_enc_ctx->roi_map[i * entryPerMb + j].field.qp_info = + bIsCenter ? importanceLevelCentre : importanceLevelRest; + sumQp += p_enc_ctx->roi_map[i * entryPerMb + j].field.qp_info; + } + } + p_enc_ctx->roi_len = customMapSize; + p_enc_ctx->roi_avg_qp = + // NOLINTNEXTLINE(clang-analyzer-core.DivideZero) + (sumQp + ((numMbs * entryPerMb) >> 1)) / (numMbs * entryPerMb); // round off + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s() set avg_qp %d\n", + __func__, p_enc_ctx->roi_avg_qp); + } + else if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) + { + // roi for H.264 is specified for 16x16 pixel macroblocks - 1 MB + // is stored in each custom map entry + + // number of MBs in each row + uint32_t mbWidth = (linesize_aligned + 16 - 1) >> 4; + // number of MBs in each column + uint32_t mbHeight = (height_aligned + 16 - 1) >> 4; + uint32_t numMbs = mbWidth * mbHeight; + uint32_t customMapSize = + sizeof(ni_enc_avc_roi_custom_map_t) * numMbs; + p_enc_ctx->avc_roi_map = + (ni_enc_avc_roi_custom_map_t *)calloc(1, customMapSize); + if (!p_enc_ctx->avc_roi_map) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + + // copy roi MBs QPs into custom map + for (i = 0; i < numMbs; i++) + { + if ((i % mbWidth > mbWidth / 3) && (i % mbWidth < mbWidth * 2 / 3)) + { + p_enc_ctx->avc_roi_map[i].field.mb_qp = importanceLevelCentre; + } + else + { + p_enc_ctx->avc_roi_map[i].field.mb_qp = importanceLevelRest; + } + sumQp += p_enc_ctx->avc_roi_map[i].field.mb_qp; + } + p_enc_ctx->roi_len = customMapSize; + p_enc_ctx->roi_avg_qp = + (sumQp + (numMbs >> 1)) / numMbs; // round off + } + else if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H265) + { + // roi for H.265 is specified for 32x32 pixel subCTU blocks - 4 + // subCTU QPs are stored in each custom CTU map entry + + // number of CTUs in each row + uint32_t ctuWidth = (linesize_aligned + 64 - 1) >> 6; + // number of CTUs in each column + uint32_t ctuHeight = (height_aligned + 64 - 1) >> 6; + // number of sub CTUs in each row + uint32_t subCtuWidth = ctuWidth * 2; + // number of CTUs in each column + uint32_t subCtuHeight = ctuHeight * 2; + uint32_t numSubCtus = subCtuWidth * subCtuHeight; + + p_enc_ctx->hevc_sub_ctu_roi_buf = (uint8_t *)malloc(numSubCtus); + if (!p_enc_ctx->hevc_sub_ctu_roi_buf) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + for (i = 0; i < numSubCtus; i++) + { + if ((i % subCtuWidth > subCtuWidth / 3) && + (i % subCtuWidth < subCtuWidth * 2 / 3)) + { + p_enc_ctx->hevc_sub_ctu_roi_buf[i] = importanceLevelCentre; + } + else + { + p_enc_ctx->hevc_sub_ctu_roi_buf[i] = importanceLevelRest; + } + } + p_enc_ctx->hevc_roi_map = (ni_enc_hevc_roi_custom_map_t *)calloc( + 1, sizeof(ni_enc_hevc_roi_custom_map_t) * ctuWidth * ctuHeight); + if (!p_enc_ctx->hevc_roi_map) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + + for (i = 0; i < ctuHeight; i++) + { + uint8_t *ptr = &p_enc_ctx->hevc_sub_ctu_roi_buf[subCtuWidth * i * 2]; + for (j = 0; j < ctuWidth; j++, ptr += 2) + { + ctu = (int)(i * ctuWidth + j); + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_0 = *ptr; + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_1 = *(ptr + 1); + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_2 = + *(ptr + subCtuWidth); + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_3 = + *(ptr + subCtuWidth + 1); + sumQp += (p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_0 + + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_1 + + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_2 + + p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_3); + } + } + p_enc_ctx->roi_len = + ctuWidth * ctuHeight * sizeof(ni_enc_hevc_roi_custom_map_t); + p_enc_ctx->roi_avg_qp = + (sumQp + (numSubCtus >> 1)) / numSubCtus; // round off. + } + return NI_RETCODE_SUCCESS; +} + +ni_retcode_t ni_enc_prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_frame) +{ + // NETINT_INTERNAL - currently only for internal testing + // reset encoder change data buffer for reconf parameters + ni_retcode_t retval = 0; + ni_xcoder_params_t *p_param = + (ni_xcoder_params_t *)p_enc_ctx->p_session_config; + ni_aux_data_t *aux_data = NULL; + if (p_param->reconf_demo_mode > XCODER_TEST_RECONF_OFF && + p_param->reconf_demo_mode < XCODER_TEST_RECONF_END) + { + memset(p_enc_ctx->enc_change_params, 0, sizeof(ni_encoder_change_params_t)); + } + + switch (p_param->reconf_demo_mode) { + case XCODER_TEST_RECONF_BR: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_BITRATE, sizeof(int32_t)); + if (!aux_data) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + + p_enc_ctx->reconfigCount++; + if (p_param->cfg_enc_params.hrdEnable) + { + p_frame->force_key_frame = 1; + p_frame->ni_pict_type = PIC_TYPE_IDR; + } + } + break; + // reconfig intraperiod param + case XCODER_TEST_RECONF_INTRAPRD: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_INTRAPRD, sizeof(int32_t)); + if (!aux_data) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + int32_t intraprd = *((int32_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "intraPeriod %d\n", + p_enc_ctx->frame_num, + intraprd); + p_enc_ctx->reconfigCount++; + } + break; + // reconfig VUI parameters + case XCODER_TEST_RECONF_VUI_HRD: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data(p_frame, + NI_FRAME_AUX_DATA_VUI, + sizeof(ni_vui_hrd_t)); + if (!aux_data) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + ni_vui_hrd_t *vui = (ni_vui_hrd_t *)aux_data->data; + vui->colorDescPresent = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + vui->colorPrimaries = + p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + vui->colorTrc = + p_param->reconf_hash[p_enc_ctx->reconfigCount][3]; + vui->colorSpace = + p_param->reconf_hash[p_enc_ctx->reconfigCount][4]; + vui->aspectRatioWidth = + p_param->reconf_hash[p_enc_ctx->reconfigCount][5]; + vui->aspectRatioHeight = + p_param->reconf_hash[p_enc_ctx->reconfigCount][6]; + vui->videoFullRange = + p_param->reconf_hash[p_enc_ctx->reconfigCount][7]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "vui colorDescPresent %d colorPrimaries %d " + "colorTrc %d colorSpace %d aspectRatioWidth %d " + "aspectRatioHeight %d videoFullRange %d\n", + p_enc_ctx->frame_num, vui->colorDescPresent, + vui->colorPrimaries, vui->colorTrc, + vui->colorSpace, vui->aspectRatioWidth, + vui->aspectRatioHeight, vui->videoFullRange); + + p_enc_ctx->reconfigCount++; + } + break; + // long term ref + case XCODER_TEST_RECONF_LONG_TERM_REF: + // the reconf file data line format for this is: + // :useCurSrcAsLongtermPic,useLongtermRef where + // values will stay the same on every frame until changed. + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) + { + ni_long_term_ref_t *p_ltr; + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_LONG_TERM_REF, + sizeof(ni_long_term_ref_t)); + if (!aux_data) + { + return NI_RETCODE_ERROR_MEM_ALOC; + } + p_ltr = (ni_long_term_ref_t *)aux_data->data; + p_ltr->use_cur_src_as_long_term_pic = + (uint8_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + p_ltr->use_long_term_ref = + (uint8_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu metadata " + "use_cur_src_as_long_term_pic %d use_long_term_ref " + "%d\n", + p_enc_ctx->frame_num, + p_ltr->use_cur_src_as_long_term_pic, + p_ltr->use_long_term_ref); + p_enc_ctx->reconfigCount++; + } + break; + // reconfig min / max QP + case XCODER_TEST_RECONF_RC_MIN_MAX_QP: + case XCODER_TEST_RECONF_RC_MIN_MAX_QP_REDUNDANT: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_MAX_MIN_QP, sizeof(ni_rc_min_max_qp)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + + ni_rc_min_max_qp *qp_info = (ni_rc_min_max_qp *)aux_data->data; + qp_info->minQpI = p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + qp_info->maxQpI = p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + qp_info->maxDeltaQp = p_param->reconf_hash[p_enc_ctx->reconfigCount][3]; + qp_info->minQpPB = p_param->reconf_hash[p_enc_ctx->reconfigCount][4]; + qp_info->maxQpPB = p_param->reconf_hash[p_enc_ctx->reconfigCount][5]; + + p_enc_ctx->reconfigCount++; + } + break; +#ifdef QUADRA + // reconfig LTR interval + case XCODER_TEST_RECONF_LTR_INTERVAL: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data(p_frame, + NI_FRAME_AUX_DATA_LTR_INTERVAL, + sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "ltrInterval %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + // invalidate reference frames + case XCODER_TEST_INVALID_REF_FRAME: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_INVALID_REF_FRAME, + sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "invalidFrameNum %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + // reconfig framerate + case XCODER_TEST_RECONF_FRAMERATE: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + ni_framerate_t *framerate; + + aux_data = ni_frame_new_aux_data(p_frame, + NI_FRAME_AUX_DATA_FRAMERATE, + sizeof(ni_framerate_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + + framerate = (ni_framerate_t *)aux_data->data; + framerate->framerate_num = + (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + framerate->framerate_denom = + (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "framerate (%d/%d)\n", + p_enc_ctx->frame_num, framerate->framerate_num, + framerate->framerate_denom); + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "maxFrameSize %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_CRF: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_CRF, sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "crf %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_CRF_FLOAT: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_CRF_FLOAT, sizeof(float)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + float crf = (float)(p_param->reconf_hash[p_enc_ctx->reconfigCount][1] + + (float)p_param->reconf_hash[p_enc_ctx->reconfigCount][2] / 100.0); + *((float *)aux_data->data) = crf; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "crf %f\n", + p_enc_ctx->frame_num, crf); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_VBV: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + int32_t vbvBufferSize = p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + int32_t vbvMaxRate = p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + if ((vbvBufferSize < 10 && vbvBufferSize != 0) || vbvBufferSize > 3000) + { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid vbvBufferSize value %d\n", + __func__, vbvBufferSize); + return NI_RETCODE_INVALID_PARAM; + } + if (p_param->bitrate > 0 && vbvMaxRate > 0 && vbvMaxRate < p_param->bitrate) { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "vbvMaxRate %u cannot be smaller than bitrate %d\n", + vbvMaxRate, p_param->bitrate); + return NI_RETCODE_INVALID_PARAM; + } + if (vbvBufferSize == 0 && vbvMaxRate > 0) { + ni_log2(p_enc_ctx, NI_LOG_INFO, "vbvMaxRate %d does not take effect when " + "vbvBufferSize is 0, force vbvMaxRate to 0\n", + vbvMaxRate); + vbvMaxRate = 0; + } + + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_VBV_MAX_RATE, sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = vbvMaxRate; + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE, sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int32_t *)aux_data->data) = vbvBufferSize; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconfig vbvMaxRate %d vbvBufferSize " + "%d by frame aux data\n", + p_enc_ctx->frame_num, vbvMaxRate, vbvBufferSize); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + int maxFrameSizeRatio = p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + if (maxFrameSizeRatio < 1) { + ni_log2(p_enc_ctx, NI_LOG_ERROR, "maxFrameSizeRatio %d cannot < 1\n", + maxFrameSizeRatio); + return NI_RETCODE_INVALID_PARAM; + } + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, sizeof(int32_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + + int32_t bitrate, framerate_num, framerate_denom; + uint32_t min_maxFrameSize, maxFrameSize; + bitrate = (p_enc_ctx->target_bitrate > 0) ? p_enc_ctx->target_bitrate : p_param->bitrate; + + if ((p_enc_ctx->framerate.framerate_num > 0) && (p_enc_ctx->framerate.framerate_denom > 0)) + { + framerate_num = p_enc_ctx->framerate.framerate_num; + framerate_denom = p_enc_ctx->framerate.framerate_denom; + } + else + { + framerate_num = (int32_t) p_param->fps_number; + framerate_denom = (int32_t) p_param->fps_denominator; + } + + min_maxFrameSize = ((uint32_t)bitrate / framerate_num * framerate_denom) / 8; + maxFrameSize = min_maxFrameSize * maxFrameSizeRatio > NI_MAX_FRAME_SIZE ? + NI_MAX_FRAME_SIZE : min_maxFrameSize * maxFrameSizeRatio; + *((int32_t *)aux_data->data) = maxFrameSize; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "maxFrameSizeRatio %d maxFrameSize %d\n", + p_enc_ctx->frame_num, maxFrameSizeRatio, maxFrameSize); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_SLICE_ARG: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + p_frame, NI_FRAME_AUX_DATA_SLICE_ARG, sizeof(int16_t)); + if (!aux_data) { + return NI_RETCODE_ERROR_MEM_ALOC; + } + *((int16_t *)aux_data->data) = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "sliceArg %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + // force IDR frame through API test code + case XCODER_TEST_FORCE_IDR_FRAME: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + ni_force_idr_frame_type(p_enc_ctx); + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu force IDR frame\n", + p_enc_ctx->frame_num); + + p_enc_ctx->reconfigCount++; + } + break; + // reconfig bit rate through API test code + case XCODER_TEST_RECONF_BR_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_reconfig_bitrate( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))){ + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig BR %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_INTRAPRD_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + int32_t intraprd = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + if ((retval = ni_reconfig_intraprd(p_enc_ctx, intraprd))){ + return retval; + } + ni_log(NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig intraPeriod %d\n", + p_enc_ctx->frame_num, + intraprd); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_VUI_HRD_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + ni_vui_hrd_t vui; + vui.colorDescPresent = + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + vui.colorPrimaries = + p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + vui.colorTrc = + p_param->reconf_hash[p_enc_ctx->reconfigCount][3]; + vui.colorSpace = + p_param->reconf_hash[p_enc_ctx->reconfigCount][4]; + vui.aspectRatioWidth = + p_param->reconf_hash[p_enc_ctx->reconfigCount][5]; + vui.aspectRatioHeight = + p_param->reconf_hash[p_enc_ctx->reconfigCount][6]; + vui.videoFullRange = + p_param->reconf_hash[p_enc_ctx->reconfigCount][7]; + if ((retval = ni_reconfig_vui(p_enc_ctx, &vui))){ + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "vui colorDescPresent %d colorPrimaries %d " + "colorTrc %d colorSpace %d aspectRatioWidth %d " + "aspectRatioHeight %d videoFullRange %d\n", + p_enc_ctx->frame_num, vui.colorDescPresent, + vui.colorPrimaries, vui.colorTrc, + vui.colorSpace, vui.aspectRatioWidth, + vui.aspectRatioHeight, vui.videoFullRange); + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_LTR_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + ni_long_term_ref_t ltr; + ltr.use_cur_src_as_long_term_pic = + (uint8_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + ltr.use_long_term_ref = + (uint8_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + + if ((retval = ni_set_ltr(p_enc_ctx, <r))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame(): frame #%lu API set LTR\n", + p_enc_ctx->frame_num); + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_RC_MIN_MAX_QP_API: + case XCODER_TEST_RECONF_RC_MIN_MAX_QP_API_REDUNDANT: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + ni_rc_min_max_qp qp_info; + qp_info.minQpI = (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + qp_info.maxQpI = (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + qp_info.maxDeltaQp = (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][3]; + qp_info.minQpPB = (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][4]; + qp_info.maxQpPB = (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][5]; + if ((retval = ni_reconfig_min_max_qp(p_enc_ctx, &qp_info))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_DEBUG, + "%s(): frame %d minQpI %d maxQpI %d maxDeltaQp %d minQpPB %d maxQpPB %d\n", + __func__, p_enc_ctx->frame_num, + qp_info.minQpI, qp_info.maxQpI, qp_info.maxDeltaQp, qp_info.minQpPB, qp_info.maxQpPB); + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_LTR_INTERVAL_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_set_ltr_interval( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))) { + return retval; + } + ni_log2(p_enc_ctx, + NI_LOG_TRACE, + "xcoder_send_frame(): frame #%lu API set LTR interval %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_INVALID_REF_FRAME_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_set_frame_ref_invalid( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))) { + return retval; + } + ni_log2(p_enc_ctx, + NI_LOG_TRACE, + "xcoder_send_frame(): frame #%lu API set frame ref invalid " + "%d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_FRAMERATE_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + ni_framerate_t framerate; + framerate.framerate_num = + (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][1]; + framerate.framerate_denom = + (int32_t)p_param->reconf_hash[p_enc_ctx->reconfigCount][2]; + if ((retval = ni_reconfig_framerate(p_enc_ctx, &framerate))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig framerate " + "(%d/%d)\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1], + p_param->reconf_hash[p_enc_ctx->reconfigCount][2]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_reconfig_max_frame_size( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig maxFrameSize %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_CRF_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_reconfig_crf( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig crf %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_CRF_FLOAT_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + float crf = (float)(p_param->reconf_hash[p_enc_ctx->reconfigCount][1] + + (float)p_param->reconf_hash[p_enc_ctx->reconfigCount][2] / 100.0); + if ((retval = ni_reconfig_crf2(p_enc_ctx, crf))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig crf %f\n", + p_enc_ctx->frame_num, crf); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_VBV_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_reconfig_vbv_value( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1], + p_param->reconf_hash[p_enc_ctx->reconfigCount][2]))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig vbvMaxRate %d vbvBufferSize %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1], + p_param->reconf_hash[p_enc_ctx->reconfigCount][2]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + + if ((retval = ni_reconfig_max_frame_size_ratio( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf maxFrameSizeRatio %d\n", + p_enc_ctx->frame_num, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; + case XCODER_TEST_RECONF_SLICE_ARG_API: + if (p_enc_ctx->frame_num == + p_param->reconf_hash[p_enc_ctx->reconfigCount][0]) { + if ((retval = ni_reconfig_slice_arg( + p_enc_ctx, p_param->reconf_hash[p_enc_ctx->reconfigCount][1]))) { + return retval; + } + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig sliceArg %d\n", + p_enc_ctx->frame_num, + p_param->reconf_hash[p_enc_ctx->reconfigCount][1]); + + p_enc_ctx->reconfigCount++; + } + break; +#endif + case XCODER_TEST_RECONF_OFF: + default: + ; + } + return NI_RETCODE_SUCCESS; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static int ni_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +int ni_strcasecmp(const char *a, const char *b) +{ + uint8_t c1, c2; + do + { + c1 = ni_tolower(*a++); + c2 = ni_tolower(*b++); + } while (c1 && c1 == c2); + return c1 - c2; +} + +void ni_gop_params_check_set(ni_xcoder_params_t *p_param, char *value) +{ + ni_encoder_cfg_params_t *p_enc = &p_param->cfg_enc_params; + ni_custom_gop_params_t* p_gop = &p_enc->custom_gop_params; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC0)) + p_gop->pic_param[0].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC0_USED)) + p_gop->pic_param[0].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC1)) + p_gop->pic_param[0].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC1_USED)) + p_gop->pic_param[0].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC2)) + p_gop->pic_param[0].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC2_USED)) + p_gop->pic_param[0].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC3)) + p_gop->pic_param[0].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G0_NUM_REF_PIC3_USED)) + p_gop->pic_param[0].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC0)) + p_gop->pic_param[1].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC0_USED)) + p_gop->pic_param[1].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC1)) + p_gop->pic_param[1].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC1_USED)) + p_gop->pic_param[1].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC2)) + p_gop->pic_param[1].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC2_USED)) + p_gop->pic_param[1].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC3)) + p_gop->pic_param[1].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G1_NUM_REF_PIC3_USED)) + p_gop->pic_param[1].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC0)) + p_gop->pic_param[2].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC0_USED)) + p_gop->pic_param[2].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC1)) + p_gop->pic_param[2].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC1_USED)) + p_gop->pic_param[2].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC2)) + p_gop->pic_param[2].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC2_USED)) + p_gop->pic_param[2].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC3)) + p_gop->pic_param[2].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G2_NUM_REF_PIC3_USED)) + p_gop->pic_param[2].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC0)) + p_gop->pic_param[3].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC0_USED)) + p_gop->pic_param[3].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC1)) + p_gop->pic_param[3].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC1_USED)) + p_gop->pic_param[3].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC2)) + p_gop->pic_param[3].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC2_USED)) + p_gop->pic_param[3].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC3)) + p_gop->pic_param[3].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G3_NUM_REF_PIC3_USED)) + p_gop->pic_param[3].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC0)) + p_gop->pic_param[4].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC0_USED)) + p_gop->pic_param[4].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC1)) + p_gop->pic_param[4].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC1_USED)) + p_gop->pic_param[4].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC2)) + p_gop->pic_param[4].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC2_USED)) + p_gop->pic_param[4].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC3)) + p_gop->pic_param[4].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G4_NUM_REF_PIC3_USED)) + p_gop->pic_param[4].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC0)) + p_gop->pic_param[5].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC0_USED)) + p_gop->pic_param[5].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC1)) + p_gop->pic_param[5].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC1_USED)) + p_gop->pic_param[5].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC2)) + p_gop->pic_param[5].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC2_USED)) + p_gop->pic_param[5].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC3)) + p_gop->pic_param[5].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G5_NUM_REF_PIC3_USED)) + p_gop->pic_param[5].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC0)) + p_gop->pic_param[6].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC0_USED)) + p_gop->pic_param[6].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC1)) + p_gop->pic_param[6].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC1_USED)) + p_gop->pic_param[6].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC2)) + p_gop->pic_param[6].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC2_USED)) + p_gop->pic_param[6].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC3)) + p_gop->pic_param[6].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G6_NUM_REF_PIC3_USED)) + p_gop->pic_param[6].rps[3].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC0)) + p_gop->pic_param[7].rps[0].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC0_USED)) + p_gop->pic_param[7].rps[0].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC1)) + p_gop->pic_param[7].rps[1].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC1_USED)) + p_gop->pic_param[7].rps[1].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC2)) + p_gop->pic_param[7].rps[2].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC2_USED)) + p_gop->pic_param[7].rps[2].ref_pic_used = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC3)) + p_gop->pic_param[7].rps[3].ref_pic = 1; + if (!ni_strcasecmp(value, NI_ENC_GOP_PARAMS_G7_NUM_REF_PIC3_USED)) + p_gop->pic_param[7].rps[3].ref_pic_used = 1; + +} + +bool ni_gop_params_check(ni_xcoder_params_t *p_param) +{ + ni_encoder_cfg_params_t *p_enc = &p_param->cfg_enc_params; + ni_custom_gop_params_t* p_gop = &p_enc->custom_gop_params; + int i, j; + for (i=0; ipic_param[i].rps[j].ref_pic == 1 && + p_gop->pic_param[i].rps[j].ref_pic_used != 1) + { + ni_log(NI_LOG_ERROR, + "g%drefPic%d specified without g%drefPic%dUsed specified!\n", + i, j, i, j); + return false; + } + } + } + // set custom_gop_params default. + for (i=0; ipic_param[i].rps[j].ref_pic = 0; + p_gop->pic_param[i].rps[j].ref_pic_used = 0; + } + } + return true; +} + +/*!***************************************************************************** + * \brief Initiate P2P transfer + * + * \param[in] pSession Pointer to source card destination + * \param[in] source Pointer to source frame to transmit + * \param[in] ui64DestAddr Destination address on target device + * \param[in] ui32FrameSize Size of frame to transfer + * + * \return on success + * NI_RETCODE_SUCCESS + * on failure + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED +*******************************************************************************/ +ni_retcode_t ni_p2p_xfer(ni_session_context_t *pSession, niFrameSurface1_t *source, + uint64_t ui64DestAddr, uint32_t ui32FrameSize) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + + /* Firmware compatibility check */ + if ((pSession != NULL) && + (ni_cmp_fw_api_ver((char *) &pSession->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6rK") < 0)) + { + ni_log2(pSession, NI_LOG_ERROR, "%s: FW doesn't support this operation\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + if (source) + { + retval = ni_send_to_target(source, ui64DestAddr, ui32FrameSize); + } + else + { + ni_log2(pSession, NI_LOG_ERROR, "%s(): Surface is empty\n", __func__); + retval = NI_RETCODE_INVALID_PARAM; + } + + return retval; +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api.h index 97ac951c..f8b9fd12 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api.h @@ -20,13 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_device_api.h -* -* \brief Main NETINT device API header file -* provides the ability to communicate with NI Quadra type hardware -* transcoder devices -* -*******************************************************************************/ + * \file ni_device_api.h + * + * \brief Public definitions for operating NETINT video processing devices for + * video processing + ******************************************************************************/ #pragma once @@ -37,6 +35,11 @@ extern "C" #endif #include "ni_defs.h" +#include "ni_rsrc_api.h" + +// resource allocation strategy names +#define NI_BEST_MODEL_LOAD_STR "bestmodelload" +#define NI_BEST_REAL_LOAD_STR "bestload" #define NI_DATA_FORMAT_VIDEO_PACKET 0 #define NI_DATA_FORMAT_YUV_FRAME 1 @@ -44,6 +47,8 @@ extern "C" #define NI_DATA_FORMAT_CB_FRAME 3 #define NI_DATA_FORMAT_CR_FRAME 4 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_NOPTS_VALUE in ni_quadra_filter_api.h #define NI_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000)) // the following are the default values from FFmpeg @@ -53,12 +58,19 @@ extern "C" #define NI_MAX_REF_PIC 4 -#define NI_MAX_VUI_SIZE 32 +NI_DEPRECATE_MACRO(NI_MAX_VUI_SIZE) +#define NI_MAX_VUI_SIZE NI_DEPRECATED_MACRO 32 #define NI_MAX_TX_RETRIES 1000 #define NI_MAX_ENCODER_QUERY_RETRIES 5000 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_SUPPORT_DRAWBOX_NUM, NI_MAX_SUPPORT_WATERMARK_NUM +// in ni_quadra_filter_api.h +#define NI_MAX_SUPPORT_DRAWBOX_NUM 5 +#define NI_MAX_SUPPORT_WATERMARK_NUM 6 + // Number of pixels for main stream resolutions #define NI_NUM_OF_PIXELS_360P (640*360) #define NI_NUM_OF_PIXELS_720P (1280*720) @@ -73,10 +85,23 @@ extern "C" #define NI_MIN_RESOLUTION_WIDTH 144 #define NI_MIN_RESOLUTION_HEIGHT 144 - +#define NI_ENC_MIN_RESOLUTION_WIDTH 144 +#define NI_ENC_MIN_RESOLUTION_HEIGHT 128 + +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_MIN_RESOLUTION_WIDTH_SCALER, +// NI_MIN_RESOLUTION_HEIGHT_SCALER in ni_quadra_filter_api.h +#define NI_MIN_RESOLUTION_WIDTH_SCALER 16 +#define NI_MIN_RESOLUTION_HEIGHT_SCALER 16 + +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_RESOLUTION_WIDTH, +// NI_QUADRA_MAX_RESOLUTION_HEIGHT in ni_quadra_filter_api.h #define NI_MAX_RESOLUTION_WIDTH 8192 #define NI_MAX_RESOLUTION_HEIGHT 8192 #define NI_MAX_RESOLUTION_AREA 8192*8192 +#define NI_MAX_RESOLUTION_RGBA_WIDTH 7040 +#define NI_MAX_RESOLUTION_RGBA_HEIGHT 7040 #define NI_MAX_RESOLUTION_LINESIZE (NI_MAX_RESOLUTION_WIDTH*2) @@ -92,12 +117,15 @@ extern "C" #define NI_MAX_ASPECTRATIO 65535 /*Values below used for VPU resolution range checking*/ +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_WIDTH, NI_QUADRA_MIN_WIDTH, +// NI_QUADRA_MAX_HEIGHT, NI_QUADRA_MIN_HEIGHT in ni_quadra_filter_api.h #define NI_MAX_WIDTH 8192 #define NI_MIN_WIDTH 144 #define NI_MAX_HEIGHT 8192 #define NI_MIN_HEIGHT 128 -#define NI_2PASS_ENCODE_MIN_WIDTH 272 +#define NI_2PASS_ENCODE_MIN_WIDTH ((272 + 31) / 32 * 32) #define NI_2PASS_ENCODE_MIN_HEIGHT 256 #define NI_MULTICORE_ENCODE_MIN_WIDTH 256 @@ -121,7 +149,7 @@ extern "C" #define NI_MAX_GOP_SIZE 8 #define NI_MIN_GOP_SIZE 1 -#define NI_MAX_GOP_PRESET_IDX 9 +#define NI_MAX_GOP_PRESET_IDX 10 #define NI_MIN_GOP_PRESET_IDX -1 #define NI_MAX_DECODING_REFRESH_TYPE 2 #define NI_MIN_DECODING_REFRESH_TYPE 0 @@ -148,12 +176,15 @@ extern "C" #define NI_MAX_NUM_SESSIONS 32 #define NI_MIN_FRAME_SIZE 0 #define NI_MAX_FRAME_SIZE (7680*4320*3) +#define NI_AV1_INVALID_BUFFER_INDEX (-1) #define RC_SUCCESS true #define RC_ERROR false #define MAX_CHAR_IN_DEVICE_NAME 32 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change MAX_QUADRA_NUM_FRAMEPOOL_HWAVFRAME in ni_quadra_filter_api.h #define MAX_NUM_FRAMEPOOL_HWAVFRAME 128 /* These constants are the values used by the GC620 2D engine */ @@ -162,12 +193,12 @@ extern "C" #define GC620_I420 0x103 #define GC620_P010_MSB 0x108 #define GC620_I010 0x10A -#define GC620_YUYV 0x100 -#define GC620_UYVY 0x101 -#define GC620_NV16 0x106 +#define GC620_YUYV 0x100 +#define GC620_UYVY 0x101 +#define GC620_NV16 0x106 #define GC620_RGBA8888 0 #define GC620_BGRA8888 4 -#define GC620_BGRX8888 5 +#define GC620_BGRX8888 5 #define GC620_ABGR8888 12 #define GC620_ARGB8888 15 #define GC620_RGB565 3 @@ -177,6 +208,33 @@ extern "C" #define NI_ENABLE_AUD_FOR_GLOBAL_HEADER 2 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_FIFO_CAPACITY in ni_quadra_filter_api.h +#define NI_MAX_FIFO_CAPACITY 120 + +/* These are Namespace and QOS configuration related */ +#define NI_NAMESPACE_MAX_NUM 64 + +/*!* +* Operation modes for QOS +*/ +typedef enum ni_qos_modes +{ + QOS_MODE_DISABLED = 0, + QOS_MODE_ENABLED_NO_SHARE = 1, + QOS_MODE_ENABLED_SHARE = 2, +} ni_qos_modes_t; + +/*!* +* Operation codes for ni_device_config_ns_qos +*/ +typedef enum ni_qos_codes +{ + QOS_NAMESPACE_CODE = NI_NAMESPACE_MAX_NUM + 1, + QOS_OP_CONFIG_REC_OP_CODE, + QOS_OP_CONFIG_CODE, +} ni_qos_codes_t; + // XCODER STATE typedef enum { @@ -207,25 +265,52 @@ typedef enum NI_PIX_FMT_ARGB = 6, /* 32-bit ARGB packed */ NI_PIX_FMT_ABGR = 7, /* 32-bit ABGR packed */ NI_PIX_FMT_BGR0 = 8, /* 32-bit RGB packed */ - NI_PIX_FMT_BGRP = 9, /* 24bit RGB packed */ + NI_PIX_FMT_BGRP = 9, /* 24-bit RGB packed */ NI_PIX_FMT_NV16 = 10, /* 8-bit YUV422 semi-planar */ NI_PIX_FMT_YUYV422 = 11, /* 8-bit YUV422 */ NI_PIX_FMT_UYVY422 = 12, /* 8-bit YUV422 */ - NI_PIX_FMT_NONE = 13, /* invalid format */ + NI_PIX_FMT_8_TILED4X4 = 13, /* 8 bit tiled4x4 */ + NI_PIX_FMT_10_TILED4X4 = 14,/* 10 bit tiled4x4 */ + NI_PIX_FMT_NONE = 15, /* invalid format */ } ni_pix_fmt_t; +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_SCALER_FLAG_* in ni_quadra_filter_api.h #define NI_SCALER_FLAG_IO 0x0001 /* 0 = source frame, 1 = destination frame */ #define NI_SCALER_FLAG_PC 0x0002 /* 0 = single allocation, 1 = create pool */ #define NI_SCALER_FLAG_PA 0x0004 /* 0 = straight alpha, 1 = premultiplied alpha */ -#define NI_SCALER_FLAG_P2 0x0008 /* 0 = normal allocation, 1 = P2P allocation */ +#define NI_SCALER_FLAG_P2 0x0008 /* 0 = normal allocation, 1 = P2P allocation */ #define NI_SCALER_FLAG_FCE 0x0010 /* 0 = no fill color, 1 = fill color enabled */ +#define NI_SCALER_FLAG_CS 0x0020 /* 0 = BT.709, 1 = BT.2020 */ +#define NI_SCALER_FLAG_LM 0x0040 /* 0 == no memory acquisition limit, 1 == limit memory acquisition */ +#define NI_SCALER_FLAG_CMP 0x0800 /* 0 = no compress, 1 = compress*/ + +#define NI_AI_FLAG_IO 0x0001 /* 0 = source frame, 1 = destination frame */ +#define NI_AI_FLAG_PC 0x0002 /* 0 = single allocation, 1 = create pool */ +#define NI_AI_FLAG_LM 0x0004 /* 0 == no memory acquisition limit; 1 == limit memory acquisition */ + +#define NI_UPLOADER_FLAG_LM 0x0010 /* 0 == no memory acquisition limit, 1 == limit memory acquisition */ +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_KEEP_ALIVE_TIMEOUT, +// NI_QUADRA_MIN_KEEP_ALIVE_TIMEOUT,NI_QUADRA_DEFAULT_KEEP_ALIVE_TIMEOUT in ni_quadra_filter_api.h #define NI_MAX_KEEP_ALIVE_TIMEOUT 100 #define NI_MIN_KEEP_ALIVE_TIMEOUT 1 #define NI_DEFAULT_KEEP_ALIVE_TIMEOUT 3 +#define NI_MIN_CUSTOM_SEI_PASSTHRU -1 +#define NI_MAX_CUSTOM_SEI_PASSTHRU 254 +#define NI_DISABLE_USR_DATA_SEI_PASSTHRU 0 +#define NI_ENABLE_USR_DATA_SEI_PASSTHRU 1 +#define NI_INVALID_SVCT_DECODING_LAYER -1 +#define NI_EC_POLICY_TOLERANT 1 +#define NI_EC_POLICY_IGNORE 2 +#define NI_EC_POLICY_SKIP 3 +#define NI_EC_POLICY_BEST_EFFORT 4 +#define NI_EC_POLICY_DEFAULT NI_EC_POLICY_BEST_EFFORT + // Picked from the xcoder firmware, commit e3b882e7 -#define NI_VPU_CEIL(_data, _align) (((_data)+(_align-1))&~(_align-1)) +#define NI_VPU_CEIL(_data, _align) (((_data)+((_align)-1))&~((_align)-1)) #define NI_VPU_ALIGN4(_x) (((_x)+0x03)&~0x03) #define NI_VPU_ALIGN8(_x) (((_x)+0x07)&~0x07) #define NI_VPU_ALIGN16(_x) (((_x)+0x0f)&~0x0f) @@ -324,6 +409,8 @@ typedef enum // while #entries (same value as SEI buffer byte0) and entry 1's header are notified // separately via metadata. #define NI_MAX_SEI_DATA (NI_ENC_MAX_SEI_BUF_SIZE) // sync with decoder_manager +// Custom SEI only applies to software delivery +#define NI_MAX_CUSTOM_SEI_DATA (8192) #else // QUADRA_SEI_FMT #define NI_MAX_SEI_ENTRIES 32 @@ -361,8 +448,26 @@ typedef enum #define NI_CC_SEI_TRAILER_LEN 2 #define NI_RBSP_TRAILING_BITS_LEN 1 +// The macro definition in ni_quadra_filter_api.h need to be synchronized with libxcoder +// If you change this,you should also change NI_QUADRA_MAX_NUM_AUX_DATA_PER_FRAME in ni_quadra_filter_api.h #define NI_MAX_NUM_AUX_DATA_PER_FRAME 16 +///Max number of lines supported for the bitrate reconfig file +#define NI_BITRATE_RECONFIG_FILE_MAX_LINES 50000 +///Max number of entries per line supported for the bitrate reconfig file. +///Note the first entry is the key(frame) value, the remaining are bitrate values +#define NI_BITRATE_RECONFIG_FILE_MAX_ENTRIES_PER_LINE 10 + +/*!* +* \brief Frame pool type. +*/ +typedef enum _ni_frame_pool_type +{ + NI_POOL_TYPE_NONE = -1, /* frame pool not inited or allocated */ + NI_POOL_TYPE_NORMAL = 0, + NI_POOL_TYPE_P2P = 1, +} ni_frame_pool_type_t; + // frame auxiliary data; mostly used for SEI data associated with frame typedef enum _ni_frame_aux_data_type { @@ -400,13 +505,16 @@ typedef enum _ni_frame_aux_data_type // payload Bytes. NI_FRAME_AUX_DATA_CUSTOM_SEI, - // NETINT: custom bitrate adjustment, which takes int32_t type data as + // NETINT: bitrate adjustment, which takes int32_t type data as // payload that indicates the new target bitrate value. NI_FRAME_AUX_DATA_BITRATE, + // NETINT: custom INTRAPRD adjustment, which takes int32_t type data + // as payload that specifies the new intra period + NI_FRAME_AUX_DATA_INTRAPRD, + // NETINT: custom VUI adjustment, which is a struct of - // ni_long_term_ref_t that specifies a frame's support of long term - // reference frame. + // ni_vui_hrd_t that specifies a frame's support of vui NI_FRAME_AUX_DATA_VUI, // NETINT: long term reference frame support, which is a struct of @@ -424,9 +532,37 @@ typedef enum _ni_frame_aux_data_type // shall be invalidated. NI_FRAME_AUX_DATA_INVALID_REF_FRAME, - // NETINT: custom framerate adjustment, which takes int32_t type data as + // NETINT: framerate adjustment, which takes int32_t type data as // payload that indicates the new target framerate numerator and denominator values. NI_FRAME_AUX_DATA_FRAMERATE, + + // NETINT: maxFrameSize adjustment, which takes int16_t type data as + // payload that indicates the new maxFrameSize value + NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, + + // NETINT: max&min QP adjustment, which is a struct of + // payload that indicate the new max&min QP values + NI_FRAME_AUX_DATA_MAX_MIN_QP, + + // NETINT: crf adjustment, which takes int32_t type data + // as payload that indicates the new crf value. + NI_FRAME_AUX_DATA_CRF, + + // NETINT: crf adjustment, which takes float type data + // as payload that indicates the new crf value. + NI_FRAME_AUX_DATA_CRF_FLOAT, + + // NETINT: VbvMaxRate adjust, which takes int32_t type + // as payload that indicates the VbvMaxRate value. + NI_FRAME_AUX_DATA_VBV_MAX_RATE, + + // NETINT: VbvBufferSize adjust, which takes int32_t type + // as payload that indicates the vbvBufferSize value. + NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE, + + // NETINT: sliceArg adjust, which takes int16_t type + // as payload that indicates the sliceArg value. + NI_FRAME_AUX_DATA_SLICE_ARG, } ni_aux_data_type_t; // rational number (pair of numerator and denominator) @@ -453,7 +589,7 @@ static inline double ni_q2d(ni_rational_t a) typedef struct _ni_aux_data { ni_aux_data_type_t type; - uint8_t *data; + void *data; int size; } ni_aux_data_t; @@ -528,6 +664,15 @@ typedef struct _ni_framerate int32_t framerate_denom; } ni_framerate_t; +typedef struct _ni_rc_min_max_qp +{ + int32_t minQpI; + int32_t maxQpI; + int32_t maxDeltaQp; + int32_t minQpPB; + int32_t maxQpPB; +}ni_rc_min_max_qp; + typedef struct _ni_dec_win { int16_t left; @@ -536,6 +681,23 @@ typedef struct _ni_dec_win int16_t bottom; } ni_dec_win_t; +typedef struct _ni_extended_dec_metadata +{ + uint32_t num_units_in_tick; + uint32_t time_scale; + uint8_t color_primaries; + uint8_t color_trc; + uint8_t color_space; + uint8_t video_full_range_flag; + // 48 bytes reserved for receiving more header info + uint64_t rsvd0; + uint64_t rsvd1; + uint64_t rsvd2; + uint64_t rsvd3; + uint64_t rsvd4; + uint64_t rsvd5; +} ni_extended_dec_metadata_t; + /*!* * \brief decoded payload format of H.265 VUI * @@ -719,7 +881,9 @@ typedef enum _ni_codec_format typedef enum _ni_pixel_planar_format { NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR = 0, - NI_PIXEL_PLANAR_FORMAT_PLANAR = 1 + NI_PIXEL_PLANAR_FORMAT_PLANAR = 1, + NI_PIXEL_PLANAR_FORMAT_TILED4X4 = 2, + NI_PIXEL_PLANAR_MAX } ni_pixel_planar_format; typedef enum _ni_dec_crop_mode @@ -753,8 +917,9 @@ typedef enum _ni_param_change_flags //NI_SET_CHANGE_PARAM_INTRA_PARAM = (1 << 1), // not required by customer NI_SET_CHANGE_PARAM_RC_TARGET_RATE = (1 << 8), //NI_SET_CHANGE_PARAM_RC = (1 << 9), // not required by customer - //NI_SET_CHANGE_PARAM_RC_MIN_MAX_QP = (1 << 10), // not required by customer + NI_SET_CHANGE_PARAM_RC_MIN_MAX_QP = (1 << 10), // not required by customer NI_SET_CHANGE_PARAM_RC_BIT_RATIO_LAYER = (1 << 11), + NI_SET_CHANGE_PARAM_SLICE_ARG = (1<<12), NI_SET_CHANGE_PARAM_INDEPEND_SLICE = (1 << 16), NI_SET_CHANGE_PARAM_DEPEND_SLICE = (1 << 17), NI_SET_CHANGE_PARAM_RDO = (1 << 18), @@ -767,7 +932,11 @@ typedef enum _ni_param_change_flags NI_SET_CHANGE_PARAM_INVALID_REF_FRAME = (1 << 25), NI_SET_CHANGE_PARAM_LTR_INTERVAL = (1 << 26), NI_SET_CHANGE_PARAM_RC_FRAMERATE = (1 << 27), - + NI_SET_CHANGE_PARAM_MAX_FRAME_SIZE = (1 << 28), + NI_SET_CHANGE_PARAM_CRF = (1<<29), + NI_SET_CHANGE_PARAM_VBV = (1<<30), + NI_SET_CHANGE_PARAM_INTRA_PERIOD = ((unsigned int)1 << 31), + //bit [2,7] and [13,15] is still unused } ni_param_change_flags_t; /** @@ -819,7 +988,20 @@ typedef struct _ni_encoder_change_params_t uint8_t videoFullRange; /**< Input video signal sample range [0,1]. 0 = Y range in [16..235] Cb,Cr in [16..240]. 1 = Y,Cb,Cr in [0..255] */ // RESERVED FOR FUTURE USE - uint8_t reserved[15]; + uint8_t reserved[5]; + + // NI_SET_CHANGE_PARAM_SLICE_ARG + int16_t sliceArg; + //NI_SET_CHANGE_PARAM_VBV also reconfig for ni_vbvBufferSize + int32_t vbvMaxRate; + + // NI_SET_CHANGE_PARAM_CRF + // crf reconfig (range in [0.00 .. 51.00]) + uint8_t crfDecimal; // crf decimal fraction * 100 (range in [0 .. 99]) + uint8_t crf; // crf integer (range in [0 .. 51]) + + // NI_SET_CHANGE_PARAM_MAX_FRAME_SIZE + uint16_t maxFrameSize; // maxFrameSize reconfig (in unit of 2000 bytes) // NI_SET_CHANGE_PARAM_INVALID_REF_FRAME int32_t invalidFrameNum; @@ -888,7 +1070,7 @@ typedef struct _ni_custom_sei uint8_t type; ni_custom_sei_location_t location; uint32_t size; - uint8_t data[NI_MAX_SEI_DATA]; + uint8_t data[NI_MAX_CUSTOM_SEI_DATA]; } ni_custom_sei_t; typedef struct _ni_custom_sei_set @@ -965,14 +1147,57 @@ typedef struct _ni_load_query { uint32_t current_load; uint32_t fw_model_load; + uint32_t fw_load; uint32_t total_contexts; - uint32_t fw_video_mem_usage; + union{ + uint32_t fw_video_mem_usage; + uint32_t pcie_throughput; //PCIe throughput - ni_query_nvme_status + }; + union { + uint32_t fw_video_shared_mem_usage; + uint32_t pcie_load; //PCIe load - ni_query_nvme_status + }; uint32_t fw_share_mem_usage; uint32_t fw_p2p_mem_usage; - uint32_t active_hwuploaders; + union { + uint32_t active_hwuploaders; + uint32_t tp_fw_load; //TP FW load - ni_query_nvme_status + }; ni_context_query_t context_status[NI_MAX_CONTEXTS_PER_HW_INSTANCE]; } ni_load_query_t; +typedef struct _ni_overall_load_query +{ + uint32_t overall_current_load; + uint32_t overall_fw_model_load; + uint32_t overall_instance_count; + uint32_t admin_queried; +} ni_overall_load_query_t; + +typedef struct _ni_instance_mgr_detail_status +{ + uint8_t ui8AvgCost; + uint8_t ui8MaxCost; + uint16_t ui16FrameRate; + uint32_t ui32BitRate; + uint32_t ui32AvgBitRate; + uint32_t ui32NumIDR; + uint32_t ui32NumInFrame; + uint32_t ui32NumOutFrame; +} ni_instance_mgr_detail_status_t; + +typedef struct _ni_instance_mgr_detail_status_append{ + uint32_t ui32Width; + uint32_t ui32Height; + uint32_t ui32UserIDR; + uint32_t reserved[8]; +}ni_instance_mgr_detail_status_append_t; + +typedef struct _ni_instance_mgr_detail_status_v1{ + ni_instance_mgr_detail_status_t sInstDetailStatus[NI_MAX_CONTEXTS_PER_HW_INSTANCE]; + ni_instance_mgr_detail_status_append_t sInstDetailStatusAppend[NI_MAX_CONTEXTS_PER_HW_INSTANCE]; +}ni_instance_mgr_detail_status_v1_t; + typedef struct _ni_thread_arg_struct_t { int hw_id; // Codec ID @@ -983,7 +1208,9 @@ typedef struct _ni_thread_arg_struct_t ni_device_handle_t device_handle; // block device handler ni_event_handle_t thread_event_handle; // only for Windows asynchronous read and write void *p_buffer; // only be used when regular-io. + ni_pthread_mutex_t *p_mutex; // referring to mutex of session context. uint32_t keep_alive_timeout; // keep alive timeout setting + volatile uint64_t *plast_access_time; // shared variable for main thread to verify timeout. Keep alive thread will update last_access_time } ni_thread_arg_struct_t; typedef struct _ni_buf_t @@ -1040,13 +1267,83 @@ typedef struct _ni_timestamp_table_t ni_queue_t list; } ni_timestamp_table_t; +typedef struct _ni_network_layer_params_t +{ + uint32_t num_of_dims; /* The number of dimensions specified in *sizes */ + uint32_t sizes[6]; /* The pointer to an array of dimension */ + int32_t + data_format; /* Data format for the tensor, see ni_ai_buffer_format_e */ + int32_t + quant_format; /* Quantized format see ni_ai_buffer_quantize_format_e */ + union + { + struct + { + int32_t + fixed_point_pos; /* Specifies the fixed point position when the input element type is int16, if 0 calculations are performed in integer math */ + } dfp; + + struct + { + float scale; /* Scale value for the quantized value */ + int32_t zeroPoint; /* A 32 bit integer, in range [0, 255] */ + } affine; + } quant_data; /* The union of quantization information */ + /* The type of this buffer memory. */ + uint32_t memory_type; +} ni_network_layer_params_t; + +typedef struct _ni_network_layer_info +{ + ni_network_layer_params_t *in_param; + ni_network_layer_params_t *out_param; +} ni_network_layer_info_t; + +typedef struct _ni_network_layer_offset +{ + int32_t offset; +} ni_network_layer_offset_t; + +typedef struct _ni_network_data +{ + uint32_t input_num; + uint32_t output_num; + ni_network_layer_info_t linfo; + ni_network_layer_offset_t + *inset; /* point to each input layer start offset from p_frame */ + ni_network_layer_offset_t + *outset; /* point to each output layer start offset from p_packet */ +} ni_network_data_t; + +// if change this structure, you need to change ni_quadra_filter_api.h ni_quadra_frameclone_desc_t +typedef struct _ni_frameclone_desc +{ + uint16_t ui16SrcIdx; + uint16_t ui16DstIdx; + uint32_t ui32Offset; + uint32_t ui32Size; + uint32_t reserved; +} ni_frameclone_desc_t; + +typedef struct _ni_network_perf_metrics +{ + uint32_t total_cycles; + uint32_t total_idle_cycles; + uint64_t read_bw; + uint64_t write_bw; + uint64_t ocb_read_bw; + uint64_t ocb_write_bw; + uint64_t ddr_read_bw; + uint64_t ddr_write_bw; +} ni_network_perf_metrics_t; + typedef struct _ni_session_context { /*! MEASURE_LATENCY queue */ /* frame_time_q is pointer to ni_lat_meas_q_t but reserved as void pointer here as ni_lat_meas_q_t is part of private API */ void *frame_time_q; - uint64_t prev_read_frame_time; + NI_DEPRECATED uint64_t prev_read_frame_time; /*! close-caption/HDR10+ header and trailer template, used for encoder */ uint8_t itu_t_t35_cc_sei_hdr_hevc[NI_CC_SEI_HDR_HEVC_LEN]; @@ -1085,6 +1382,9 @@ typedef struct _ni_session_context int pkt_index; uint64_t pkt_offsets_index[NI_FIFO_SZ]; uint64_t pkt_offsets_index_min[NI_FIFO_SZ]; + uint64_t pkt_pos[NI_FIFO_SZ]; + uint64_t last_pkt_pos; + uint64_t last_frame_offset; ni_custom_sei_set_t *pkt_custom_sei_set[NI_FIFO_SZ]; /*! if session is on a decoder handling incoming pkt 512-aligned */ @@ -1131,6 +1431,9 @@ typedef struct _ni_session_context /*! Context Query */ ni_load_query_t load_query; + /* Overall resource use among namespaces */ + ni_overall_load_query_t overall_load_query; + /*! Leftover Buffer */ uint8_t *p_leftover; int prev_size; @@ -1159,7 +1462,7 @@ typedef struct _ni_session_context int keyframe_factor; uint64_t frame_num; uint64_t pkt_num; - int rc_error_count; + int rc_error_count; // Unused uint32_t hwd_Frame_Idx; uint32_t hwd_src_cpu; @@ -1191,7 +1494,7 @@ typedef struct _ni_session_context int ori_width, ori_height, ori_bit_depth_factor, ori_pix_fmt; // a muxter for Xcoder API, to keep the thread-safety. - ni_pthread_mutex_t *xcoder_mutex; + ni_pthread_mutex_t mutex; // Xcoder running state uint32_t xcoder_state; @@ -1209,11 +1512,19 @@ typedef struct _ni_session_context ni_region_of_interest_t *av_rois; int nb_rois; ni_enc_quad_roi_custom_map *roi_map; // actual AVC/HEVC QP map + + // only for H.264 test roi buffer for up to 8k resolution H.264 - 32 x 32 sub CTUs + ni_enc_avc_roi_custom_map_t *avc_roi_map; + // only for H.265 custom map buffer for up to 8k resolution - 64x64 CTU Regions + uint8_t *hevc_sub_ctu_roi_buf; + // only for hevc actual ROI map is stored in individual session context ! + ni_enc_hevc_roi_custom_map_t *hevc_roi_map; // encoder reconfig parameters ni_encoder_change_params_t *enc_change_params; // decoder lowDelay mode for All I packets or IPPP packets int decoder_low_delay; + int enable_low_delay_check; // wrapper API request data, to be sent out once with the next input frame // to encoder @@ -1258,6 +1569,7 @@ typedef struct _ni_session_context uint32_t meta_size; int64_t last_dts_interval; + int64_t last_pts_interval; int pic_reorder_delay; // flags_array to save packet flags @@ -1265,6 +1577,65 @@ typedef struct _ni_session_context // for decoder: store currently returned decoded frame's pkt offset uint64_t frame_pkt_offset; + uint32_t force_idr_intra_offset; + + ni_session_statistic_t session_statistic; + + uint32_t count_frame_num_in_sec; //used in the vfr mode, indicate the frame count in seconds + uint32_t passed_time_in_timebase_unit; //used in the vfr mode, indicate how long it has passed + + int32_t max_frame_size; // maxFrameSize (in bytes) to reconfig, 0 if inactive + + // block device name requested by caller to open: when specified this block + // device has priority over hw_id which is device specified by index. + char blk_dev_name[NI_MAX_DEVICE_NAME_LEN]; + + // decoder low delay send/recv sync; async_mode = 0 by default, i.e. + // codec send-to/recv-from FW is in synchrounous mode by default. + int async_mode; + int low_delay_sync_flag; + ni_pthread_mutex_t low_delay_sync_mutex; + ni_pthread_cond_t low_delay_sync_cond; + + // muxtex default from source session + // required pointer to external if used by hwdl + ni_pthread_mutex_t* pext_mutex; + bool mutex_initialized; + + // required parameters for slow sequence change + int32_t last_bitrate; + ni_framerate_t last_framerate; + + // AI embedded network parameters data + ni_network_data_t *network_data; + + int ori_luma_linesize; + int ori_chroma_linesize; + //shared variable for main thread to read and keepalive thread to update + volatile uint64_t last_access_time; + + int reconfig_crf; // crf value to reconfig (range in [0..51]), -1 if inactive + int reconfig_crf_decimal; // crf decimal fration value to reconfig + // (range in [0..99]), -1 if inactive + int reconfig_vbv_buffer_size; // vbv buffer size value to reconfig + int reconfig_vbv_max_rate; // vbv max rate value to reconfig + + int last_gop_size; + int initial_frame_delay; + int current_frame_delay; + int max_frame_delay; + uint64_t av1_pkt_num; + + ni_frame_pool_type_t pool_type; + int reconfigCount; + bool force_low_delay; + uint32_t force_low_delay_cnt; + int max_retry_fail_count[2]; + uint32_t pkt_delay_cnt; + char E2EID[128]; + int reconfig_intra_period; + int pixel_format_changed; // only for decoder now + int16_t reconfig_slice_arg; } ni_session_context_t; typedef struct _ni_split_context_t @@ -1284,24 +1655,39 @@ typedef enum _ni_reconfig { XCODER_TEST_RECONF_OFF = 0, XCODER_TEST_RECONF_BR = 1, - //XCODER_TEST_RECONF_INTRAPRD = 2, // not required by customer + XCODER_TEST_RECONF_INTRAPRD = 2, XCODER_TEST_RECONF_VUI_HRD = 3, XCODER_TEST_RECONF_LONG_TERM_REF = 4, //XCODER_TEST_RECONF_RC = 5, // // not required by customer -//XCODER_TEST_RECONF_RC_MIN_MAX_QP = 6, // // not required by customer + XCODER_TEST_RECONF_RC_MIN_MAX_QP = 6, // reconfig min&max QP #ifdef QUADRA XCODER_TEST_RECONF_LTR_INTERVAL = 7, XCODER_TEST_INVALID_REF_FRAME = 8, XCODER_TEST_RECONF_FRAMERATE = 9, + XCODER_TEST_RECONF_MAX_FRAME_SIZE = 10, + XCODER_TEST_RECONF_RC_MIN_MAX_QP_REDUNDANT = 11, // reconfig min&max QP through libxcoder API (redundant demo mode index) + XCODER_TEST_RECONF_CRF = 14, + XCODER_TEST_RECONF_CRF_FLOAT = 15, + XCODER_TEST_RECONF_VBV = 16, + XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO = 17, + XCODER_TEST_RECONF_SLICE_ARG = 18, XCODER_TEST_FORCE_IDR_FRAME = 100, // force IDR through libxcoder API XCODER_TEST_RECONF_BR_API = 101, // reconfig BR through libxcoder API + XCODER_TEST_RECONF_INTRAPRD_API = 102, // reconfig intraperiod through libxcoder API XCODER_TEST_RECONF_VUI_HRD_API = 103, // reconfig VUI through libxcoder API XCODER_TEST_RECONF_LTR_API = 104, // reconfig LTR through libxcoder API + XCODER_TEST_RECONF_RC_MIN_MAX_QP_API_REDUNDANT = 106, // reconfig min&max QP through libxcoder API (redundant demo mode index) XCODER_TEST_RECONF_LTR_INTERVAL_API = 107, // reconf LTR interval thru API XCODER_TEST_INVALID_REF_FRAME_API = 108, // invalidate ref frame thru API - XCODER_TEST_RECONF_FRAMERATE_API = - 109, // reconfig framerate through libxcoder API - XCODER_TEST_RECONF_END = 110, + XCODER_TEST_RECONF_FRAMERATE_API = 109, // reconfig framerate through libxcoder API + XCODER_TEST_RECONF_MAX_FRAME_SIZE_API = 110, // reconfig maxFrameSize through libxcoder API + XCODER_TEST_RECONF_RC_MIN_MAX_QP_API = 111, // reconfig min&max QP through libxcoder API + XCODER_TEST_CRF_API = 114, // reconfig crf through libxcoder API + XCODER_TEST_CRF_FLOAT_API = 115, // reconfig crf float type through libxcoder API + XCODER_TEST_RECONF_VBV_API = 116, // reconfig vbv buffer size and vbv max rate through libxcoder API + XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO_API = 117, // reconfig maxFrameSize ratio through libxcoder API + XCODER_TEST_RECONF_SLICE_ARG_API = 118, // reconfig sliceArg through libxcoder API + XCODER_TEST_RECONF_END = 119, #endif } ni_reconfig_t; @@ -1348,57 +1734,15 @@ typedef enum _ni_ai_buffer_quantize_format_e NI_AI_BUFFER_QUANTIZE_MAX, } ni_ai_buffer_quantize_format_e; -#define NI_MAX_NETWORK_INPUT_NUM 4 -#define NI_MAX_NETWORK_OUTPUT_NUM 4 - -typedef struct _ni_network_layer_params_t -{ - uint32_t num_of_dims; /* The number of dimensions specified in *sizes */ - uint32_t sizes[6]; /* The pointer to an array of dimension */ - int32_t - data_format; /* Data format for the tensor, see ni_ai_buffer_format_e */ - int32_t - quant_format; /* Quantized format see ni_ai_buffer_quantize_format_e */ - union - { - struct - { - int32_t - fixed_point_pos; /* Specifies the fixed point position when the input element type is int16, if 0 calculations are performed in integer math */ - } dfp; - - struct - { - float scale; /* Scale value for the quantized value */ - int32_t zeroPoint; /* A 32 bit integer, in range [0, 255] */ - } affine; - } quant_data; /* The union of quantization information */ - /* The type of this buffer memory. */ - uint32_t memory_type; -} ni_network_layer_params_t; - -typedef struct _ni_network_layer_info -{ - ni_network_layer_params_t in_param[NI_MAX_NETWORK_INPUT_NUM]; - ni_network_layer_params_t out_param[NI_MAX_NETWORK_OUTPUT_NUM]; -} ni_network_layer_info_t; - -typedef struct _ni_network_data +typedef enum _ni_ddr_priority_mode_t { - uint32_t input_num; - uint32_t output_num; - ni_network_layer_info_t linfo; - struct - { - int32_t - offset; /* point to each input layer start offset from p_frame */ - } inset[NI_MAX_NETWORK_INPUT_NUM]; - struct - { - int32_t - offset; /* point to each output layer start offset from p_packet */ - } outset[NI_MAX_NETWORK_OUTPUT_NUM]; -} ni_network_data_t; + NI_DDR_PRIORITY_NONE = -1, // Do not change DDR priorities + NI_DDR_PRIORITY_RESET, // Reset DDR priorities to default + NI_DDR_PRIORITY_DECENC, // DDR prioritize decoder and encoder + NI_DDR_PRIORITY_FILT, // DDR prioritize filter + NI_DDR_PRIORITY_AI, // DDR prioritize AI + NI_DDR_PRIORITY_MAX +} ni_ddr_priority_mode_t; #ifdef QUADRA #define NI_ENC_GOP_PARAMS_G0_POC_OFFSET "g0pocOffset" @@ -1646,6 +1990,7 @@ typedef struct _ni_encoder_cfg_params #define NI_ENC_PARAM_LOG "log" #define NI_ENC_PARAM_GOP_PRESET_IDX "gopPresetIdx" #define NI_ENC_PARAM_LOW_DELAY "lowDelay" +#define NI_ENC_PARAM_MIN_FRAMES_DELAY "minFramesDelay" #define NI_ENC_PARAM_USE_RECOMMENDED_ENC_PARAMS "useRecommendEncParam" #define NI_ENC_PARAM_USE_LOW_DELAY_POC_TYPE "useLowDelayPocType" #define NI_ENC_PARAM_CU_SIZE_MODE "cuSizeMode" @@ -1673,17 +2018,17 @@ typedef struct _ni_encoder_cfg_params #define NI_ENC_PARAM_FRAME_RATE_DENOM "frameRateDenom" #define NI_ENC_PARAM_INTRA_QP "intraQP" #define NI_ENC_PARAM_DECODING_REFRESH_TYPE "decodingRefreshType" +#define NI_ENC_PARAM_INTRA_REFRESH_RESET "intraRefreshResetOnForceIDR" // Rev. B: H.264 only parameters. #define NI_ENC_PARAM_ENABLE_8X8_TRANSFORM "transform8x8Enable" -#define NI_ENC_PARAM_AVC_SLICE_MODE "avcSliceMode" -#define NI_ENC_PARAM_AVC_SLICE_ARG "avcSliceArg" #define NI_ENC_PARAM_ENTROPY_CODING_MODE "entropyCodingMode" // Rev. B: shared between HEVC and H.264 +#define NI_ENC_PARAM_SLICE_MODE "sliceMode" +#define NI_ENC_PARAM_SLICE_ARG "sliceArg" #define NI_ENC_PARAM_INTRA_MB_REFRESH_MODE "intraMbRefreshMode" #define NI_ENC_PARAM_INTRA_MB_REFRESH_ARG "intraMbRefreshArg" #define NI_ENC_PARAM_INTRA_REFRESH_MODE "intraRefreshMode" #define NI_ENC_PARAM_INTRA_REFRESH_ARG "intraRefreshArg" -// TBD Rev. B: could be shared for HEVC and H.264 #define NI_ENC_PARAM_ENABLE_MB_LEVEL_RC "mbLevelRcEnable" #define NI_ENC_PARAM_PREFERRED_TRANSFER_CHARACTERISTICS "prefTRC" @@ -1693,10 +2038,13 @@ typedef struct _ni_encoder_cfg_params #define NI_ENC_PARAM_INTRA_REFRESH_MIN_PERIOD "intraRefreshMinPeriod" //QUADRA -#define NI_ENC_PARAM_CONSTANT_RATE_FACTOR "crf" +NI_DEPRECATE_MACRO(NI_ENC_PARAM_CONSTANT_RATE_FACTOR) +#define NI_ENC_PARAM_CONSTANT_RATE_FACTOR NI_DEPRECATED_MACRO "crf" +#define NI_ENC_PARAM_CONSTANT_RATE_FACTOR_FLOAT "crfFloat" #define NI_ENC_PARAM_RDO_LEVEL "rdoLevel" #define NI_ENC_PARAM_RDO_QUANT "EnableRdoQuant" #define NI_ENC_PARAM_MAX_CLL "maxCLL" +#define NI_ENC_PARAM_MASTER_DISPLAY "masterDisplay" #define NI_ENC_PARAM_LOOK_AHEAD_DEPTH "lookAheadDepth" #define NI_ENC_PARAM_ENABLE_AUD "enableAUD" #define NI_ENC_PARAM_CTB_RC_MODE "ctbRcMode" @@ -1706,9 +2054,13 @@ typedef struct _ni_encoder_cfg_params #define NI_ENC_PARAM_HRD_ENABLE "hrdEnable" #define NI_ENC_PARAM_DOLBY_VISION_PROFILE "dolbyVisionProfile" #define NI_ENC_PARAM_VBV_BUFFER_SIZE "vbvBufferSize" +#define NI_ENC_PARAM_VBV_MAXRAE "vbvMaxRate" #define NI_ENC_PARAM_ENABLE_FILLER "fillerEnable" #define NI_ENC_PARAM_ENABLE_PIC_SKIP "picSkip" -#define NI_ENC_PARAM_MAX_FRAME_SIZE_LOW_DELAY "maxFrameSize" +NI_DEPRECATE_MACRO(NI_ENC_PARAM_MAX_FRAME_SIZE_LOW_DELAY) +#define NI_ENC_PARAM_MAX_FRAME_SIZE_LOW_DELAY NI_DEPRECATED_MACRO "maxFrameSize" +#define NI_ENC_PARAM_MAX_FRAME_SIZE_BITS_LOW_DELAY "maxFrameSize-Bits" +#define NI_ENC_PARAM_MAX_FRAME_SIZE_BYTES_LOW_DELAY "maxFrameSize-Bytes" #define NI_ENC_PARAM_LTR_REF_INTERVAL "ltrRefInterval" #define NI_ENC_PARAM_LTR_REF_QPOFFSET "ltrRefQpOffset" #define NI_ENC_PARAM_LTR_FIRST_GAP "ltrFirstGap" @@ -1722,10 +2074,16 @@ typedef struct _ni_encoder_cfg_params #define NI_ENC_INLOOP_DS_RATIO "inLoopDSRatio" #define NI_ENC_BLOCK_RC_SIZE "blockRCSize" #define NI_ENC_RC_QP_DELTA_RANGE "rcQpDeltaRange" +#define NI_ENC_CTB_ROW_QP_STEP "ctbRowQpStep" +#define NI_ENC_NEW_RC_ENABLE "newRcEnable" #define NI_ENC_PARAM_INTRA_QP_DELTA "intraQpDelta" #define NI_ENC_PARAM_LONG_TERM_REFERENCE_ENABLE "longTermReferenceEnable" #define NI_ENC_PARAM_LONG_TERM_REFERENCE_COUNT "longTermReferenceCount" #define NI_ENC_PARAM_LONG_TERM_REFERENCE_INTERVAL "longTermReferenceInterval" +#define NI_ENC_PARAM_SKIP_FRAME_ENABLE "skipFrameEnable" +#define NI_ENC_PARAM_MAX_CONSUTIVE_SKIP_FRAME_NUMBER "maxConsecutiveSkipFrameNum" +#define NI_ENC_PARAM_SKIP_FRAME_INTERVAL "skipFrameInterVal" +#define NI_ENC_PARAM_IFRAME_SIZE_RATIO "iFrameSizeRatio" // stream color info #define NI_ENC_PARAM_COLOR_PRIMARY "colorPri" #define NI_ENC_PARAM_COLOR_TRANSFER_CHARACTERISTIC "colorTrc" @@ -1738,6 +2096,41 @@ typedef struct _ni_encoder_cfg_params // VFR related #define NI_ENC_PARAM_ENABLE_VFR "enableVFR" #define NI_ENC_ENABLE_SSIM "enableSSIM" +#define NI_ENC_PARAM_AV1_ERROR_RESILIENT_MODE "av1ErrorResilientMode" +// set memory allocation parameters, M_MMAP_THRESHOLD and M_TRIM_THRESHOLD +#define NI_ENC_PARAM_STATIC_MMAP_THRESHOLD "staticMmapThreshold" +#define NI_ENC_PARAM_TEMPORAL_LAYERS_ENABLE "temporalLayersEnable" +#define NI_ENC_PARAM_ENABLE_AI_ENHANCE "enableAIEnhance" +#define NI_ENC_PARAM_ENABLE_2PASS_GOP "enable2PassGop" +#define NI_ENC_PARAM_ZEROCOPY_MODE "zeroCopyMode" +#define NI_ENC_PARAM_AI_ENHANCE_LEVEL "AIEnhanceLevel" +#define NI_ENC_PARAM_CROP_WIDTH "cropWidth" +#define NI_ENC_PARAM_CROP_HEIGHT "cropHeight" +#define NI_ENC_PARAM_HORIZONTAL_OFFSET "horOffset" +#define NI_ENC_PARAM_VERTICAL_OFFSET "verOffset" +#define NI_ENC_PARAM_CONSTANT_RATE_FACTOR_MAX "crfMax" +#define NI_ENC_PARAM_QCOMP "qcomp" +#define NI_ENC_PARAM_NO_MBTREE "noMbtree" +#define NI_ENC_PARAM_NO_HW_MULTIPASS_SUPPORT "noHWMultiPassSupport" +#define NI_ENC_PARAM_CU_TREE_FACTOR "cuTreeFactor" +#define NI_ENC_PARAM_IP_RATIO "ipRatio" +#define NI_ENC_PARAM_ENABLE_IP_RATIO "enableipRatio" +#define NI_ENC_PARAM_PB_RATIO "pbRatio" +#define NI_ENC_PARAM_CPLX_DECAY "cplxDecay" +#define NI_ENC_PARAM_PPS_INIT_QP "ppsInitQp" +#define NI_ENC_PARAM_DDR_PRIORITY_MODE "ddrPriorityMode" +#define NI_ENC_PARAM_BITRATE_MODE "bitrateMode" +#define NI_ENC_PARAM_PASS1_QP "pass1Qp" +#define NI_ENC_PARAM_HVS_BASE_MB_COMPLEXITY "hvsBaseMbComplexity" +#define NI_ENC_PARAM_STATISTIC_OUTPUT_LEVEL "statisticOutputLevel" +#define NI_ENC_PARAM_ENABLE_ALL_SEI_PASSTHRU "enableAllSeiPassthru" +#define NI_ENC_PARAM_CRF_MAX_IFRAME_ENABLE "crfMaxIframeEnable" +#define NI_ENC_PARAM_VBV_MINRATE "vbvMinRate" +#define NI_ENC_PARAM_DISABLE_ADAPTIVE_BUFFERS "disableAdaptiveBuffers" +#define NI_ENC_PARAM_DISABLE_BFRAME_RDOQ "disableBframeRDOQ" +#define NI_ENC_PARAM_FORCE_BFRAME_QPFACTOR "forceBframeQpfactor" +#define NI_ENC_PARAM_TUNE_BFRAME_VISUAL "tuneBframeVisual" +#define NI_ENC_PARAM_ENABLE_ACQUIRE_LIMIT "enableAcqLimit" //----- Start supported by all codecs ----- int frame_rate; @@ -1745,6 +2138,7 @@ typedef struct _ni_encoder_cfg_params int aspectRatioHeight; int planar; int maxFrameSize; + int maxFrameSizeRatio; //----- End supported by all codecs ----- //----- Start supported by AV1, AVC, HEVC only ----- @@ -1773,6 +2167,17 @@ typedef struct _ni_encoder_cfg_params int HDR10MaxLight; int HDR10AveLight; int HDR10CLLEnable; + int HDR10Enable; + int HDR10dx0; + int HDR10dy0; + int HDR10dx1; + int HDR10dy1; + int HDR10dx2; + int HDR10dy2; + int HDR10wx; + int HDR10wy; + int HDR10maxluma; + int HDR10minluma; int gdrDuration; int ltrRefInterval; int ltrRefQpOffset; @@ -1837,8 +2242,8 @@ typedef struct _ni_encoder_cfg_params // Rev. B: H.264 only parameters, in ni_t408_config_t // - for H.264 on T408: int enable_transform_8x8; - int avc_slice_mode; - int avc_slice_arg; + int slice_mode; + int slice_arg; int decoding_refresh_type; //----- end DEPRECATED or for T408 ----- @@ -1858,6 +2263,7 @@ typedef struct _ni_encoder_cfg_params int hvs_qp_scale; /*!*< A QP scaling factor for CU QP adjustment when hvcQpenable = 1 */ int enable_filler; int vbv_buffer_size; + int vbv_max_rate; //deprecated int enable_hvs_qp_scale; /*!*< It enable QP scaling factor for CU QP adjustment when enable_hvs_qp = 1 */ @@ -1867,6 +2273,48 @@ typedef struct _ni_encoder_cfg_params } rc; int keep_alive_timeout; /* keep alive timeout setting */ int enable_ssim; + int av1_error_resilient_mode; + int intra_reset_refresh; + int ctbRowQpStep; + int newRcEnable; + int temporal_layers_enable; + int enable_ai_enhance; + int ai_enhance_level; + int crop_width; + int crop_height; + int hor_offset; + int ver_offset; + int crfMax; + float qcomp; + int noMbtree; + int noHWMultiPassSupport; + int cuTreeFactor; + float ipRatio; + float pbRatio; + float cplxDecay; + int pps_init_qp; + int bitrateMode; + int pass1_qp; + float crfFloat; + int hvsBaseMbComplexity; + // 0: no extra output encoder information + // 1: Frame Level output encoder information + // 2: Cu Level Output encoder information + // 3: Frame&Cu Level encoder information + int statistic_output_level; + int skip_frame_enable; + int max_consecutive_skip_num; + int skip_frame_interval; + int enableipRatio; + bool enable_all_sei_passthru; + int iframe_size_ratio; + int crf_max_iframe_enable; + int vbv_min_rate; + bool disable_adaptive_buffers; + int disableBframeRdoq; + float forceBframeQpfactor; + int tune_bframe_visual; + int enable_acq_limit; } ni_encoder_cfg_params_t; typedef struct _ni_decoder_input_params_t @@ -1889,9 +2337,35 @@ typedef struct _ni_decoder_input_params_t #define NI_DEC_PARAM_SCALE_0 "scale0" #define NI_DEC_PARAM_SCALE_1 "scale1" #define NI_DEC_PARAM_SCALE_2 "scale2" +#define NI_DEC_PARAM_SCALE_0_LONG_SHORT_ADAPT "scale0LongShortAdapt" +#define NI_DEC_PARAM_SCALE_1_LONG_SHORT_ADAPT "scale1LongShortAdapt" +#define NI_DEC_PARAM_SCALE_2_LONG_SHORT_ADAPT "scale2LongShortAdapt" +#define NI_DEC_PARAM_SCALE_0_RES_CEIL "scale0ResCeil" +#define NI_DEC_PARAM_SCALE_1_RES_CEIL "scale1ResCeil" +#define NI_DEC_PARAM_SCALE_2_RES_CEIL "scale2ResCeil" +#define NI_DEC_PARAM_SCALE_0_ROUND "scale0Round" +#define NI_DEC_PARAM_SCALE_1_ROUND "scale1Round" +#define NI_DEC_PARAM_SCALE_2_ROUND "scale2Round" #define NI_DEC_PARAM_MULTICORE_JOINT_MODE "multicoreJointMode" #define NI_DEC_PARAM_SAVE_PKT "savePkt" #define NI_DEC_PARAM_LOW_DELAY "lowDelay" +#define NI_DEC_PARAM_FORCE_LOW_DELAY "forceLowDelay" +#define NI_DEC_PARAM_MIN_PACKETS_DELAY "minPacketsDelay" +#define NI_DEC_PARAM_ENABLE_LOW_DELAY_CHECK "enableLowDelayCheck" +#define NI_DEC_PARAM_ENABLE_USR_DATA_SEI_PASSTHRU "enableUserDataSeiPassthru" +#define NI_DEC_PARAM_ENABLE_CUSTOM_SEI_PASSTHRU "customSeiPassthru" +#define NI_DEC_PARAM_SVC_T_DECODING_LAYER "svctDecodingLayer" +#define NI_DEC_PARAM_DDR_PRIORITY_MODE "ddrPriorityMode" +#define NI_DEC_PARAM_EC_POLICY "ecPolicy" +#define NI_DEC_PARAM_ENABLE_ADVANCED_EC "enableAdvancedEc" +#define NI_DEC_PARAM_ENABLE_PPU_SCALE_ADAPT "enablePpuScaleAdapt" +#define NI_DEC_PARAM_ENABLE_PPU_SCALE_LIMIT "enablePpuScaleLimit" +#define NI_DEC_PARAM_MAX_EXTRA_HW_FRAME_CNT "maxExtraHwFrameCnt" +#define NI_DEC_PARAM_SKIP_PTS_GUESS "skipPtsGuess" +#define NI_DEC_PARAM_PKT_PTS_UNCHANGE "pktPtsUnchange" +#define NI_DEC_PARAM_ENABLE_ALL_SEI_PASSTHRU "enableAllSeiPassthru" +#define NI_DEC_PARAM_ENABLE_FOLLOW_IFRAME "enableFollowIFrame" +#define NI_DEC_PARAM_DISABLE_ADAPTIVE_BUFFERS "disableAdaptiveBuffers" int hwframes; int enable_out1; @@ -1912,6 +2386,26 @@ typedef struct _ni_decoder_input_params_t int keep_alive_timeout; /* keep alive timeout setting */ // decoder lowDelay mode for All I packets or IPPP packets int decoder_low_delay; + bool force_low_delay; + int enable_low_delay_check; + int enable_user_data_sei_passthru; + int custom_sei_passthru; + int svct_decoding_layer; + int ec_policy; + int enable_advanced_ec; + int enable_ppu_scale_adapt; // 0: disabled; 1: adapt to long edge; 2: adapt to short edge. + int enable_ppu_scale_limit; + int max_extra_hwframe_cnt; + int skip_pts_guess; + int pkt_pts_unchange; + bool enable_all_sei_passthru; + bool min_packets_delay; + // 0: disabled; 1: adapt to long edge; 2: adapt to short edge. + int scale_long_short_edge[NI_MAX_NUM_OF_DECODER_OUTPUTS]; + int scale_resolution_ceil[NI_MAX_NUM_OF_DECODER_OUTPUTS]; // Rounding value + int scale_round[NI_MAX_NUM_OF_DECODER_OUTPUTS]; // 0 up align 1 dowm align + int enable_follow_iframe; + int disable_adaptive_buffers; } ni_decoder_input_params_t; typedef struct _ni_scaler_input_params_t @@ -1942,6 +2436,32 @@ typedef struct _ni_scaler_params_t int nb_inputs; } ni_scaler_params_t; +typedef struct _ni_scaler_drawbox_params_t +{ + uint32_t start_x; + uint32_t start_y; + uint32_t end_x; + uint32_t end_y; + uint32_t rgba_c; +} ni_scaler_drawbox_params_t; + +typedef struct _ni_scaler_watermark_params_t{ + uint32_t ui32StartX; + uint32_t ui32StartY; + uint32_t ui32Width; + uint32_t ui32Height; + uint32_t ui32Valid; +} ni_scaler_watermark_params_t; + +typedef struct _ni_scaler_multi_drawbox_params_t +{ + ni_scaler_drawbox_params_t multi_drawbox_params[NI_MAX_SUPPORT_DRAWBOX_NUM]; +}ni_scaler_multi_drawbox_params_t; + +typedef struct _ni_scaler_multi_watermark_params_t{ + ni_scaler_watermark_params_t multi_watermark_params[NI_MAX_SUPPORT_WATERMARK_NUM]; +}ni_scaler_multi_watermark_params_t; + typedef struct _ni_frame { // codec of the source from which this frame is decoded @@ -2034,6 +2554,23 @@ typedef struct _ni_frame uint32_t vui_time_scale; int flags; // flags of demuxed packet + + // for encoder: metadata buffer info if not contiguous with YUV + uint8_t *p_metadata_buffer; + uint32_t metadata_buffer_size; + // for encoder: whether metadata should be sent separately for frame + uint8_t separate_metadata; + uint64_t pkt_pos; + + // for encoder: non-4k-aligned part at the start of YUV data + uint8_t *p_start_buffer; + uint32_t start_buffer_size; + uint32_t start_len[NI_MAX_NUM_DATA_POINTERS]; + uint32_t total_start_len; + // for encoder: whether the start of non-4k-aligned YUV data should be sent separately for frame + uint8_t separate_start; + uint8_t inconsecutive_transfer; + long long orignal_pts; } ni_frame_t; typedef struct _ni_xcoder_params @@ -2072,12 +2609,12 @@ typedef struct _ni_xcoder_params int cacheRoi; // enables caching of ROIs applied to subsequent frames - uint32_t ui32VuiDataSizeBits; /**< size of VUI RBSP in bits **/ - uint32_t + NI_DEPRECATED uint32_t ui32VuiDataSizeBits; /**< size of VUI RBSP in bits **/ + NI_DEPRECATED uint32_t ui32VuiDataSizeBytes; /**< size of VUI RBSP in bytes up to MAX_VUI_SIZE **/ - uint8_t ui8VuiRbsp[NI_MAX_VUI_SIZE]; /**< VUI raw byte sequence **/ - uint32_t pos_num_units_in_tick; - uint32_t pos_time_scale; + NI_DEPRECATED uint8_t ui8VuiRbsp[NI_MAX_VUI_SIZE]; /**< VUI raw byte sequence **/ + NI_DEPRECATED uint32_t pos_num_units_in_tick; + NI_DEPRECATED uint32_t pos_time_scale; int color_primaries; int color_transfer_characteristic; @@ -2094,13 +2631,24 @@ typedef struct _ni_xcoder_params // NETINT_INTERNAL - currently only for internal testing of reconfig, saving // key:val1,val2,val3,...val9 (max 9 values) in the demo reconfig data file - // this supports max 100 lines in reconfig file, max 10 key/values per line - int reconf_hash[100][10]; + // this supports max 50000 lines in reconfig file, max 10 key/values per line + int reconf_hash[NI_BITRATE_RECONFIG_FILE_MAX_LINES] + [NI_BITRATE_RECONFIG_FILE_MAX_ENTRIES_PER_LINE]; int hwframes; int rootBufId; ni_frame_t *p_first_frame; int enable_vfr; //enable the vfr + + int staticMmapThreshold; + int enable_ai_enhance; + int enable2PassGop; + int zerocopy_mode; + int luma_linesize; + int chroma_linesize; + int ai_enhance_level; + ni_ddr_priority_mode_t ddr_priority_mode; + int minFramesDelay; } ni_xcoder_params_t; typedef struct _niFrameSurface1 @@ -2112,7 +2660,7 @@ typedef struct _niFrameSurface1 uint32_t ui32nodeAddress; //currently not in use, formerly offset int32_t device_handle; //handle to access device int8_t bit_depth; //1 == 8bit per pixel, 2 == 10bit - int8_t encoding_type; //0 = semiplanar, 1 = semiplanar + int8_t encoding_type; //0 = semiplanar, 1 = planar, 2 = tiled4x4 int8_t output_idx; // 0-2 for decoder output index int8_t src_cpu; // frame origin location int32_t dma_buf_fd; // P2P dma buffer file descriptor @@ -2132,6 +2680,7 @@ typedef struct _ni_frame_config uint16_t frame_index; uint16_t session_id; uint8_t output_index; + uint8_t orientation; // 0 <= n <= 3, (n * 90°) clockwise rotation } ni_frame_config_t; typedef struct _ni_packet @@ -2139,6 +2688,7 @@ typedef struct _ni_packet long long dts; long long pts; long long pos; + uint64_t pkt_pos; uint32_t end_of_stream; uint32_t start_of_stream; uint32_t video_width; @@ -2238,7 +2788,7 @@ LIB_API void ni_device_session_context_free(ni_session_context_t *p_ctx); * \return On success returns a event handle * On failure returns NI_INVALID_EVENT_HANDLE ******************************************************************************/ -LIB_API ni_event_handle_t ni_create_event(); +LIB_API ni_event_handle_t ni_create_event(void); /*!***************************************************************************** * \brief Close event and release resources (Windows only) @@ -2333,9 +2883,9 @@ LIB_API ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, /*!***************************************************************************** * \brief Send a flush command to the device - * If device_type is NI_DEVICE_TYPE_DECODER sends flush command to + * If device_type is NI_DEVICE_TYPE_DECODER sends EOS command to * decoder - * If device_type is NI_DEVICE_TYPE_ENCODER sends flush command to + * If device_type is NI_DEVICE_TYPE_ENCODER sends EOS command to * encoder * * \param[in] p_ctx Pointer to a caller allocated @@ -2475,6 +3025,95 @@ LIB_API int ni_device_session_read(ni_session_context_t *p_ctx, ******************************************************************************/ LIB_API ni_retcode_t ni_device_session_query(ni_session_context_t *p_ctx, ni_device_type_t device_type); +/*!***************************************************************************** + * \brief Query detail session data from the device - + * If device_type is valid, will query session data + * from specified device type + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] device_type NI_DEVICE_TYPE_DECODER or + * NI_DEVICE_TYPE_ENCODER or + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_INVALID_SESSION + ******************************************************************************/ + LIB_API ni_retcode_t ni_device_session_query_detail(ni_session_context_t* p_ctx, + ni_device_type_t device_type, ni_instance_mgr_detail_status_t *detail_data); + +/*!***************************************************************************** + * \brief Query detail session data from the device - + * If device_type is valid, will query session data + * from specified device type + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] device_type NI_DEVICE_TYPE_DECODER or + * NI_DEVICE_TYPE_ENCODER or + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_INVALID_SESSION + ******************************************************************************/ +LIB_API ni_retcode_t ni_device_session_query_detail_v1(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_detail_status_v1_t *detail_data); + +/*!***************************************************************************** + * \brief Send namespace num and SRIOv index to the device with specified logic block + * address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] namespace_num Set the namespace number with designated sriov + * \param[in] sriov_index Identify which sriov need to be set + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +LIB_API ni_retcode_t ni_device_config_namespace_num(ni_device_handle_t device_handle, + uint32_t namespace_num, uint32_t sriov_index); + +/*!***************************************************************************** + * \brief Send qos mode to the device with specified logic block + * address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] mode The requested qos mode + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +LIB_API ni_retcode_t ni_device_config_qos(ni_device_handle_t device_handle, + uint32_t mode); + + /*!***************************************************************************** + * \brief Send qos over provisioning mode to target namespace with specified logic + * block address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] device_handle_t Target device handle of namespace required for OP + * \param[in] over_provision The request overprovision percent + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +LIB_API ni_retcode_t ni_device_config_qos_op(ni_device_handle_t device_handle, + ni_device_handle_t device_handle_t, + uint32_t over_provision); /*!***************************************************************************** * \brief Allocate preliminary memory for the frame buffer based on provided @@ -2504,6 +3143,36 @@ LIB_API ni_retcode_t ni_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, int metadata_flag, int factor, int hw_frame_count, int is_planar); +/*!***************************************************************************** + * \brief Wrapper function for ni_frame_buffer_alloc. Meant to handle RGBA min. + * resoulution considerations for encoder. + * + * \param[in] p_frame Pointer to a caller allocated + * ni_frame_t struct + * \param[in] video_width Width of the video frame + * \param[in] video_height Height of the video frame + * \param[in] alignment Allignment requirement + * \param[in] metadata_flag Flag indicating if space for additional metadata + * should be allocated + * \param[in] factor 1 for 8 bits/pixel format, 2 for 10 bits/pixel, + * 4 for 32 bits/pixel (RGBA) + * \param[in] hw_frame_count Number of hw descriptors stored + * \param[in] is_planar 0 if semiplanar else planar + * \param[in] pix_fmt pixel format to distinguish between planar types + * and/or components + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_enc_frame_buffer_alloc(ni_frame_t *p_frame, int video_width, + int video_height, int alignment, + int metadata_flag, int factor, + int hw_frame_count, int is_planar, + ni_pix_fmt_t pix_fmt); + LIB_API ni_retcode_t ni_frame_buffer_alloc_dl(ni_frame_t *p_frame, int video_width, int video_height, int pixel_format); @@ -2715,9 +3384,9 @@ LIB_API ni_retcode_t ni_packet_buffer_alloc(ni_packet_t *ppacket, * NI_RETCODE_INVALID_PARAM * NI_RETCODE_ERROR_MEM_ALOC ******************************************************************************/ -ni_retcode_t ni_custom_packet_buffer_alloc(void *p_buffer, - ni_packet_t *p_packet, - int buffer_size); +LIB_API ni_retcode_t ni_custom_packet_buffer_alloc(void *p_buffer, + ni_packet_t *p_packet, + int buffer_size); /*!***************************************************************************** * \brief Free packet buffer that was previously allocated with @@ -2946,6 +3615,27 @@ LIB_API ni_retcode_t ni_device_session_copy(ni_session_context_t *src_p_ctx, LIB_API int ni_device_session_init_framepool(ni_session_context_t *p_ctx, uint32_t pool_size, uint32_t pool); +/*!***************************************************************************** +* \brief Sends frame pool change info to device +* +* \param[in] p_ctx Pointer to a caller allocated +* ni_session_context_t struct +* \param[in] pool_size if pool_size = 0, free allocated device memory buffers +* if pool_size > 0, expand device frame buffer pool of +* current instance with pool_size more frame buffers +* +* \return On success Return code +* On failure +* NI_RETCODE_FAILURE +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_ERROR_NVME_CMD_FAILED +* NI_RETCODE_ERROR_INVALID_SESSION +* NI_RETCODE_ERROR_MEM_ALOC +* NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION +*******************************************************************************/ +LIB_API ni_retcode_t ni_device_session_update_framepool(ni_session_context_t *p_ctx, + uint32_t pool_size); + /*!***************************************************************************** * \brief Read data from the device * If device_type is NI_DEVICE_TYPE_DECODER reads data hwdesc from @@ -3035,7 +3725,7 @@ LIB_API ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t *pframe, int extra_len); /*!***************************************************************************** -* \brief Recycle a frame buffer on card +* \brief Recycle a hwframe buffer on card * * \param[in] surface Struct containing device and frame location to clear out * \param[in] device_handle handle to access device memory buffer is stored in @@ -3046,6 +3736,17 @@ LIB_API ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t *pframe, LIB_API ni_retcode_t ni_hwframe_buffer_recycle(niFrameSurface1_t *surface, int32_t device_handle); + +/*!***************************************************************************** +* \brief Recycle a hwframe buffer on card +* +* \param[in] surface Struct containing device and frame location to clear out +* +* \return On success NI_RETCODE_SUCCESS +* On failure NI_RETCODE_INVALID_PARAM +*******************************************************************************/ +LIB_API ni_retcode_t ni_hwframe_buffer_recycle2(niFrameSurface1_t *surface); + /*!***************************************************************************** * \brief Set parameters on the device for the 2D engine * @@ -3100,27 +3801,65 @@ LIB_API ni_retcode_t ni_device_alloc_frame(ni_session_context_t* p_ctx, ni_device_type_t device_type); /*!***************************************************************************** - * \brief Config a frame on the device for 2D engined - * to work on based on provided parameters + * \brief Allocate a frame on the device and return the frame index * - * \param[in] p_ctx pointer to session context - * \param[in] p_cfg pointer to frame config + * \param[in] p_ctx pointer to session context + * \param[in] p_out_surface pointer to output frame surface + * \param[in] device_type currently only NI_DEVICE_TYPE_AI * * \return NI_RETCODE_INVALID_PARAM * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION * NI_RETCODE_ERROR_NVME_CMD_FAILED * NI_RETCODE_ERROR_MEM_ALOC ******************************************************************************/ -LIB_API ni_retcode_t ni_device_config_frame(ni_session_context_t *p_ctx, - ni_frame_config_t *p_cfg); +LIB_API ni_retcode_t ni_device_alloc_dst_frame(ni_session_context_t *p_ctx, + niFrameSurface1_t *p_out_surface, + ni_device_type_t device_type); /*!***************************************************************************** - * \brief Config multiple frame on the device for 2D engined - * to work on based on provided parameters + * \brief Copy the data of src hwframe to dst hwframe * - * \param[in] p_ctx pointer to session context - * \param[in] p_cfg_in input frame config array - * \param[in] numInCfgs number of frame config entries in the p_cfg_in array + * \param[in] p_ctx pointer to session context + * \param[in] p_frameclone_desc pointer to the frameclone descriptor + * + * \return NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_device_clone_hwframe(ni_session_context_t *p_ctx, + ni_frameclone_desc_t *p_frameclone_desc); + +/*!***************************************************************************** + * \brief Config a frame on the device for 2D engined + * to work on based on provided parameters + * + * \param[in] p_ctx pointer to session context + * \param[in] p_cfg pointer to frame config + * + * \return NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_device_config_frame(ni_session_context_t *p_ctx, + ni_frame_config_t *p_cfg); + +LIB_API ni_retcode_t ni_scaler_set_drawbox_params(ni_session_context_t *p_ctx, + ni_scaler_drawbox_params_t *p_params); + +LIB_API ni_retcode_t ni_scaler_set_watermark_params(ni_session_context_t *p_ctx, + ni_scaler_watermark_params_t *p_params); + +/*!***************************************************************************** + * \brief Config multiple frame on the device for 2D engined + * to work on based on provided parameters + * + * \param[in] p_ctx pointer to session context + * \param[in] p_cfg_in input frame config array + * \param[in] numInCfgs number of frame config entries in the p_cfg_in array * \param[in] p_cfg_out output frame config * * \return NI_RETCODE_INVALID_PARAM @@ -3219,6 +3958,22 @@ LIB_API ni_retcode_t ni_ai_packet_buffer_alloc(ni_packet_t *p_packet, LIB_API ni_retcode_t ni_reconfig_bitrate(ni_session_context_t *p_ctx, int32_t bitrate); +/*!***************************************************************************** + * \brief Reconfigure intraPeriod dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] intra_period Target intra period to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + * + * NOTE - the frame upon which intra period is reconfigured is encoded as IDR frame + * NOTE - reconfigure intra period is not allowed if intraRefreshMode is enabled or if gopPresetIdx is 1 + * + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_intraprd(ni_session_context_t *p_ctx, + int32_t intra_period); + /*!***************************************************************************** * \brief Reconfigure VUI dynamically during encoding. * @@ -3289,6 +4044,96 @@ LIB_API ni_retcode_t ni_set_frame_ref_invalid(ni_session_context_t *p_ctx, LIB_API ni_retcode_t ni_reconfig_framerate(ni_session_context_t *p_ctx, ni_framerate_t *framerate); +/*!***************************************************************************** + * \brief Reconfigure maxFrameSize dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] max_frame_size the new maxFrameSize value + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + * + * NOTE - maxFrameSize_Bytes value less than ((bitrate / 8) / framerate) will be rejected + * + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_max_frame_size(ni_session_context_t *p_ctx, + int32_t max_frame_size); + +/*!***************************************************************************** + * \brief Reconfigure min&max qp dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] ni_rc_min_max_qp Target min&max qp to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_min_max_qp(ni_session_context_t *p_ctx, + ni_rc_min_max_qp *p_min_max_qp); + + +/*!***************************************************************************** + * \brief Reconfigure crf value dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] crf crf value to reconfigure + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_crf(ni_session_context_t *p_ctx, + int32_t crf); + +/*!***************************************************************************** + * \brief Reconfigure crf float point value dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] crf crf float point value to reconfigure + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_crf2(ni_session_context_t *p_ctx, + float crf); + + +/*!***************************************************************************** + * \brief Reconfigure vbv buffer size and vbv max rate dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] vbvBufferSize Target vbvBufferSize to set + * \param[in] vbvMaxRate Target vbvMaxRate to set + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_vbv_value(ni_session_context_t *p_ctx, + int32_t vbvMaxRate, int32_t vbvBufferSize); + +/*!***************************************************************************** + * \brief Reconfigure maxFrameSizeRatio dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] max_frame_size_ratio the new maxFrameSizeRatio value + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_max_frame_size_ratio(ni_session_context_t *p_ctx, + int32_t max_frame_size_ratio); + +/*!***************************************************************************** + * \brief Reconfigure sliceArg dynamically during encoding. + * + * \param[in] p_ctx Pointer to caller allocated ni_session_context_t + * \param[in] sliceArg the new sliceArg value + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +LIB_API ni_retcode_t ni_reconfig_slice_arg(ni_session_context_t *p_ctx, + int16_t sliceArg); + #ifndef _WIN32 /*!***************************************************************************** * \brief Acquire a P2P frame buffer from the hwupload session @@ -3354,6 +4199,7 @@ LIB_API ni_retcode_t ni_uploader_p2p_test_send(ni_session_context_t *p_upl_ctx, uint8_t *p_data, uint32_t len, ni_frame_t *p_hwframe); + /*!***************************************************************************** * \brief Set the incoming frame format for the encoder * @@ -3376,24 +4222,18 @@ LIB_API ni_retcode_t ni_encoder_set_input_frame_format( int width, int height, int bit_depth, int src_endian, int planar); /*!***************************************************************************** - * \brief Set the frame format for the uploader + * \brief Acquire the scaler P2P DMA buffer for read/write * - * \param[in] p_upl_ctx pointer to uploader context - * [in] width width - * [in] height height - * [in] pixel_format pixel format - * [in] isP2P 0 = normal, 1 = P2P + * \param [in] p_ctx pointer to caller allocated upload context + * [in] p_surface pointer to a caller allocated hardware frame + * [in] data_len scaler frame buffer data length * * \return on success - * NI_RETCODE_SUCCESS + * NI_RETCODE_SUCCESS * * on failure - * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_FAILURE *******************************************************************************/ -LIB_API ni_retcode_t -ni_uploader_set_frame_format(ni_session_context_t *p_upl_ctx, int width, - int height, ni_pix_fmt_t pixel_format, int isP2P); - LIB_API ni_retcode_t ni_scaler_p2p_frame_acquire(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, int data_len); @@ -3412,6 +4252,25 @@ LIB_API ni_retcode_t ni_scaler_p2p_frame_acquire(ni_session_context_t *p_ctx, LIB_API ni_retcode_t ni_hwframe_p2p_buffer_recycle(ni_frame_t *p_frame); #endif +/*!***************************************************************************** + * \brief Set the frame format for the uploader + * + * \param[in] p_upl_ctx pointer to uploader context + * [in] width width + * [in] height height + * [in] pixel_format pixel format + * [in] isP2P 0 = normal, 1 = P2P + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_INVALID_PARAM +*******************************************************************************/ +LIB_API ni_retcode_t +ni_uploader_set_frame_format(ni_session_context_t *p_upl_ctx, int width, + int height, ni_pix_fmt_t pixel_format, int isP2P); + /*!***************************************************************************** * \brief Read encoder stream header from the device * @@ -3464,6 +4323,297 @@ LIB_API int32_t ni_get_dma_buf_file_descriptor(const ni_frame_t* p_frame); LIB_API ni_retcode_t ni_device_session_sequence_change(ni_session_context_t *p_ctx, int width, int height, int bit_depth_factor, ni_device_type_t device_type); +/*!***************************************************************************** + * \brief Fetch perf metrics of inferences from device + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_metrics Pointer to network metrics + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +LIB_API ni_retcode_t ni_ai_session_read_metrics( + ni_session_context_t *p_ctx, ni_network_perf_metrics_t *p_metrics); + +/*!***************************************************************************** + * \brief Query firmware loader and firmware versions from the device + * + * \param[in] device_handle Device handle obtained by calling ni_device_open() + * \param[in] device_info + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_query_fl_fw_versions(ni_device_handle_t device_handle, + ni_device_info_t *p_dev_info); + +/*!***************************************************************************** + * \brief Query NVMe load from the device + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_load_query Pointer to a caller allocated + * ni_load_query_t struct + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_query_nvme_status( + ni_session_context_t *p_ctx, ni_load_query_t *p_load_query); + +/*!***************************************************************************** + * \brief Query VF and NS id from device + * + * \param[in] device_handle Device handle obtained by calling ni_device_open() + * \param[in] p_dev_ns_vf Pointer to a ni_device_vf_ns_id_t struct + * \param[in] fw_rev[] Fw version to check if this function is supported + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_query_vf_ns_id(ni_device_handle_t device_handle, + ni_device_vf_ns_id_t *p_dev_ns_vf, + uint8_t fw_rev[]); + +/*!***************************************************************************** + * \brief Query CompositeTemp from device + * + * \param[in] device_handle Device handle obtained by calling ni_device_open() + * \param[in] p_dev_temp Pointer to device temperature + * \param[in] fw_rev[] Fw version to check if this function is supported + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_query_temperature(ni_device_handle_t device_handle, + ni_device_temp_t *p_dev_temp, + uint8_t fw_rev[]); + +/*!***************************************************************************** + * \brief Query CompositeTemp from device + * + * \param[in] device_handle Device handle obtained by calling ni_device_open() + * \param[in] p_dev_extra_info Pointer to device extra info + * \param[in] fw_rev[] Fw version to check if this function is supported + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_ERROR_MEM_ALOC + ******************************************************************************/ +LIB_API ni_retcode_t ni_query_extra_info(ni_device_handle_t device_handle, + ni_device_extra_info_t *p_dev_extra_info, + uint8_t fw_rev[]); + +/*!***************************************************************************** + * \brief Check if incoming frame is encoder zero copy compatible or not + * + * \param[in] p_enc_ctx pointer to encoder context + * [in] p_enc_params pointer to encoder parameters + * [in] width input width + * [in] height input height + * [in] linesize input linesizes (pointer to array) + * [in] set_linesize setup linesizes 0 means not setup linesizes, 1 means setup linesizes (before encoder open) + * + * \return on success and can do zero copy + * NI_RETCODE_SUCCESS + * + * cannot do zero copy + * NI_RETCODE_ERROR_UNSUPPORTED_FEATURE + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_INVALID_PARAM + * +*******************************************************************************/ +LIB_API ni_retcode_t ni_encoder_frame_zerocopy_check(ni_session_context_t *p_enc_ctx, + ni_xcoder_params_t *p_enc_params, + int width, int height, + const int linesize[], + bool set_linesize); + +/*!***************************************************************************** + * \brief Allocate memory for encoder zero copy (metadata, etc.) + * for encoding based on given + * parameters, taking into account pic linesize and extra data. + * Applicable to YUV planr / semi-planar 8 or 10 bit and RGBA pixel formats. + * + * + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct + * \param[in] video_width Width of the video frame + * \param[in] video_height Height of the video frame + * \param[in] linesize Picture line size + * \param[in] data Picture data pointers (for each of YUV planes) + * \param[in] extra_len Extra data size (incl. meta data) + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + *****************************************************************************/ +LIB_API ni_retcode_t ni_encoder_frame_zerocopy_buffer_alloc(ni_frame_t *p_frame, + int video_width, int video_height, + const int linesize[], const uint8_t *data[], + int extra_len); + +/*!***************************************************************************** + * \brief Check if incoming frame is hwupload zero copy compatible or not + * + * \param[in] p_upl_ctx pointer to uploader context + * [in] width input width + * [in] height input height + * [in] linesize input linesizes (pointer to array) + * [in] pixel_format input pixel format + * + * \return on success and can do zero copy + * NI_RETCODE_SUCCESS + * + * cannot do zero copy + * NI_RETCODE_ERROR_UNSUPPORTED_FEATURE + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_INVALID_PARAM + * +*******************************************************************************/ +LIB_API ni_retcode_t ni_uploader_frame_zerocopy_check(ni_session_context_t *p_upl_ctx, + int width, int height, + const int linesize[], int pixel_format); + +/*!***************************************************************************** + * \brief Allocate log buffer if needed and retrieve firmware logs from device + * + * \param[in] p_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_log_buffer Reference to pointer to a log buffer + * If log buffer pointer is NULL, this function will allocate log buffer + * NOTE caller is responsible for freeing log buffer after calling this function + * \param[in] gen_log_file Indicating whether it is required to generate log files + * + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_INVALID_PARAM +*******************************************************************************/ +LIB_API ni_retcode_t ni_device_alloc_and_get_firmware_logs(ni_session_context_t *p_ctx, void** p_log_buffer, bool gen_log_file); + +/*!***************************************************************************** + * \brief Set up hard coded demo ROI map + * + * \param[in] p_enc_ctx Pointer to a caller allocated + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_ERROR_MEM_ALOC +*******************************************************************************/ +LIB_API ni_retcode_t ni_set_demo_roi_map(ni_session_context_t *p_enc_ctx); + +/*!***************************************************************************** + * \brief Convert various reconfig and demo modes (stored in encoder configuration) to + * aux data and store them in frame + * + * \param[in] p_enc_ctx Pointer to a caller allocated + * ni_session_context_t struct + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct + * + * + * \return on success + * NI_RETCODE_SUCCESS + * + * on failure + * NI_RETCODE_ERROR_MEM_ALOC +*******************************************************************************/ +LIB_API ni_retcode_t ni_enc_prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, + ni_frame_t *p_frame); + +/*!***************************************************************************** + * \brief Set custom gop and prepare to check if success + * + * \param[in] p_param Pointer to a caller allocated ni_xcoder_params_t struct + * \param[in] value Pointer to a caller allocated customer gop name + * + * \return none + * +*******************************************************************************/ +LIB_API void ni_gop_params_check_set(ni_xcoder_params_t *p_param, char *value); + +/*!***************************************************************************** + * \brief Check customer gop params set. + * + * \param[in] p_param Pointer to a caller allocated ni_xcoder_params_t struct + * + * + * \return on success + * true + * + * on failure + * false +*******************************************************************************/ +LIB_API bool ni_gop_params_check(ni_xcoder_params_t *p_param); + +/*!***************************************************************************** + * \brief Initiate P2P transfer + * + * \param[in] pSession Pointer to source card destination + * \param[in] source Pointer to source frame to transmit + * \param[in] ui64DestAddr Destination address on target device + * \param[in] ui32FrameSize Size of frame to transfer + * + * \return on success + * NI_RETCODE_SUCCESS + * on failure + * NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED +*******************************************************************************/ +LIB_API ni_retcode_t ni_p2p_xfer(ni_session_context_t *pSession, + niFrameSurface1_t *source, + uint64_t ui64DestAddr, uint32_t ui32FrameSize); + +/*!***************************************************************************** + * \brief Calculate the total size of a frame based on the upload + * context attributes and includes rounding up to the page size + * + * \param[in] p_upl_ctx pointer to an uploader session context + * \param[in] linesize array of line stride + * + * \return size + * NI_RETCODE_INVALID_PARAM + * + ******************************************************************************/ +LIB_API int ni_calculate_total_frame_size(const ni_session_context_t *p_upl_ctx, + const int linesize[]); #ifdef __cplusplus } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.c index 8f776cdd..fc7ff385 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.c @@ -20,17 +20,19 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_device_api_priv.c -* -* \brief Private functions used by main ni_device_api_c file -* -*******************************************************************************/ + * \file ni_device_api_priv.c + * + * \brief Private definitions used by ni_device_api.c for video processing + * tasks + ******************************************************************************/ #ifdef _WIN32 #include #elif __linux__ || __APPLE__ #if __linux__ #include +#include +#include #endif #include #include @@ -49,13 +51,16 @@ #include #include #include +#ifndef _ANDROID +#include +#endif #endif #include #include #include #include -#ifndef _WIN32 +#ifdef __linux__ #include #include #include "ni_p2p_ioctl.h" @@ -66,6 +71,16 @@ #include "ni_device_api_priv.h" #include "ni_util.h" #include "ni_lat_meas.h" +#include "ni_rsrc_priv.h" + +//Map the gopPresetIdx to gopSize, +//gopPresetIdx -1: Adaptive Gop, using the biggest gopsize 8 +//gopPresetIdx 0 : Customer Gop +//g_map_preset_to_gopsize[lookAheadEnable][gopPresetIdx + 1]; +//for the not support gopPresetIdx value, such as gopPresetIdx == 2, set g_map_preset_to_gopsize to -1 +static const int g_map_preset_to_gopsize[2][13] = {{8, 0, 1, -1, 1, 2, 4, -1, 4, 8, 1, 4}, + {8, 0, -1, -1, -1, 2, 4, -1, -1, 8, 1, -1}}; +#define MAGIC_P2P_VALUE "p2p" typedef enum _ni_t35_sei_mesg_type { @@ -73,6 +88,13 @@ typedef enum _ni_t35_sei_mesg_type NI_T35_SEI_HDR10_PLUS = 1 } ni_t35_sei_mesg_type_t; +typedef enum +{ + OPT_1 = 1, // is a combination of OPT_3 and OPT_2 in that order + OPT_2 = 2, // returns NI_RETCODE_FAILURE after NI_XCODER_FAILURES_MAX attempts, and LRETURNs for failures + OPT_3 = 3 // queries session statistics +} check_err_rc_option_t; + static uint8_t g_itu_t_t35_cc_sei_hdr_hevc[NI_CC_SEI_HDR_HEVC_LEN] = { 0x00, 0x00, 0x00, 0x01, // NAL start code 00 00 00 01 0x4e, @@ -143,179 +165,93 @@ static uint8_t g_sei_trailer[NI_CC_SEI_TRAILER_LEN] = { }; #define NI_XCODER_FAILURES_MAX 25 +#define DP_IPC_PASSTHRU 0xFFFFFFFF -//Following macros will only check for critical failures. -//After the macro runs, rc should contain the status of the last command sent -//For non-critical failures, it is assumed in the code that eventually after enough retries, a command will succeed. -//Invalid parameters or resource busy do not account for failures that cause error count to be incremented so they can be retried indefinitely #ifdef _WIN32 -#define CHECK_ERR_RC(ctx, rc, opcode, type, hw_id, inst_id) \ - { \ - ni_session_stats_t err_rc_info = {0}; \ - int err_rc = \ - ni_query_session_stats(ctx, type, &err_rc_info, rc, opcode); \ - if (err_rc != NI_RETCODE_SUCCESS) \ - { \ - ni_log(NI_LOG_ERROR, \ - "PANIC!!!! - Query for stats failed. What to do?\n"); \ - } \ - rc = err_rc_info.ui32LastTransactionCompletionStatus; \ - int tmp_rc = NI_RETCODE_FAILURE; \ - if ((ctx->rc_error_count >= NI_XCODER_FAILURES_MAX) || \ - (tmp_rc = \ - ni_nvme_check_error_code(rc, opcode, type, hw_id, inst_id))) \ - { \ - ni_log(NI_LOG_ERROR, \ - "Persistent failures detected, %s() line-%d: " \ - "session_no 0x%x sess_err_count %u inst_err_no %u " \ - "rc_error_count: %d\n", \ - __func__, __LINE__, *inst_id, err_rc_info.ui16ErrorCount, \ - err_rc_info.ui32LastErrorStatus, ctx->rc_error_count); \ - rc = tmp_rc; \ - LRETURN; \ - } \ - if (type == NI_DEVICE_TYPE_AI && err_rc_info.ui32LastErrorStatus != 0) \ - { \ - rc = NI_RETCODE_FAILURE; \ - } \ +#ifdef XCODER_SELF_KILL_ERR +#undef XCODER_SELF_KILL_ERR +#endif +#endif + +// Check for critical failures. +// Invalid parameters or resource busy do not account for failures that cause error count to be incremented so they can be retried indefinitely +static ni_retcode_t check_err_rc( + ni_session_context_t* ctx, ni_retcode_t rc, ni_session_statistic_t *stat_full, int opcode, uint32_t type, int hw_id, uint32_t *inst_id, int opt, const char* func, int line) +{ + ni_retcode_t retval = rc; + ni_session_stats_t stat = {0}; + uint16_t ui16ErrorCount = 0; + uint32_t ui32LastErrorStatus = 0; + + if(opt == OPT_1 || opt == OPT_3) + { + retval = ni_query_session_stats(ctx, type, &stat, rc, opcode); + ui16ErrorCount = stat.ui16ErrorCount; + ui32LastErrorStatus = stat.ui32LastErrorStatus; } -#define CHECK_ERR_RC2(ctx, rc, info, opcode, type, hw_id, inst_id) \ - { \ - (rc) = (info).ui32LastTransactionCompletionStatus; \ - if ((info).ui16ErrorCount || (rc)) \ - (ctx)->rc_error_count++; \ - else \ - (ctx)->rc_error_count = 0; \ - int tmp_rc = NI_RETCODE_FAILURE; \ - if ((info).ui16ErrorCount || \ - (ctx)->rc_error_count >= NI_XCODER_FAILURES_MAX || \ - (tmp_rc = ni_nvme_check_error_code(rc, (opcode), (type), (hw_id), \ - (inst_id)))) \ - { \ - ni_log(NI_LOG_ERROR, \ - "Persistent failures detected, %s() line-%d: session_no " \ - "0x%x sess_err_no %u " \ - "inst_err_no %u rc_error_count: %d\n", \ - __func__, __LINE__, *(inst_id), (info).ui16ErrorCount, \ - (info).ui32LastTransactionCompletionStatus, \ - (ctx)->rc_error_count); \ - (rc) = tmp_rc; \ - LRETURN; \ - } \ + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(ctx, NI_LOG_ERROR, "Query for statistics failed with %d!\n", retval); + return NI_RETCODE_FAILURE; } -#elif __linux__ || __APPLE__ -static struct stat g_nvme_stat = {0}; + if(opt == OPT_1) + { + retval = ni_nvme_check_error_code(stat.ui32LastTransactionCompletionStatus, opcode, type, hw_id, inst_id); -#ifdef XCODER_SELF_KILL_ERR -#define CHECK_ERR_RC(ctx, rc, opcode, type, hw_id, inst_id) \ - { \ - ni_session_stats_t err_rc_info = {0}; \ - int err_rc = \ - ni_query_session_stats(ctx, type, &err_rc_info, rc, opcode); \ - if (err_rc != NI_RETCODE_SUCCESS) \ - { \ - ni_log(NI_LOG_ERROR, \ - "PANIC!!!! - Query for stats failed. What to do?\n"); \ - exit(EXIT_FAILURE); \ - } \ - rc = err_rc_info.ui32LastTransactionCompletionStatus; \ - int tmp_rc = NI_RETCODE_FAILURE; \ - if ((ctx->rc_error_count >= NI_XCODER_FAILURES_MAX) || \ - (tmp_rc = \ - ni_nvme_check_error_code(rc, opcode, type, hw_id, inst_id))) \ - { \ - ni_log( \ - NI_LOG_ERROR, \ - "Persistent failures detected, %s() line-%d: session_no 0x%x " \ - "sess_err_count %u inst_err_no %u rc_error_count: %d\n", \ - __func__, __LINE__, *inst_id, err_rc_info.ui16ErrorCount, \ - err_rc_info.ui32LastErrorStatus, ctx->rc_error_count); \ - rc = tmp_rc; \ - kill(getpid(), SIGTERM); \ - } \ + if(!retval) + retval = ni_nvme_check_error_code(ui32LastErrorStatus, opcode, type, hw_id, inst_id); } - -#define CHECK_ERR_RC2(ctx, rc, err_rc_info, opcode, type, hw_id, inst_id) \ - { \ - (rc) = (err_rc_info).ui32LastTransactionCompletionStatus; \ - if ((err_rc_info).ui16ErrorCount || rc) \ - (ctx)->rc_error_count++; \ - else \ - (ctx)->rc_error_count = 0; \ - if ((err_rc_info).ui16ErrorCount || \ - (ctx)->rc_error_count >= NI_XCODER_FAILURES_MAX || \ - ni_nvme_check_error_code((rc), (opcode), (type), (hw_id), \ - (inst_id))) \ - { \ - ni_log(NI_LOG_ERROR, \ - "Terminating due to persistent failures, %s() line-%d: " \ - "session_no 0x%x " \ - "sess_err_no %u inst_err_no %u " \ - "rc_error_count: %d\n", \ - __func__, __LINE__, *(inst_id), \ - (err_rc_info).ui16ErrorCount, \ - (err_rc_info).ui32LastTransactionCompletionStatus, \ - (ctx)->rc_error_count); \ - kill(getpid(), SIGTERM); \ - } \ + else if(opt == OPT_2){ + if(!stat_full){ + ni_log2(ctx, NI_LOG_ERROR, "ERROR %s(): passed parameters are null!, return\n", __func__); + return NI_RETCODE_INVALID_PARAM; + } + retval = ni_nvme_check_error_code(stat_full->ui32LastTransactionCompletionStatus, opcode, type, hw_id, inst_id); + ui16ErrorCount = stat_full->ui16ErrorCount; + ui32LastErrorStatus = stat_full->ui32LastErrorStatus; + /* re-query error status for transactionId 0xFFFF */ + if(stat_full->ui32LastErrorTransactionId == 0xFFFF && + ui16ErrorCount > 0 && !retval && + type == NI_DEVICE_TYPE_DECODER) + { + retval = ni_nvme_check_error_code(ui32LastErrorStatus, opcode, type, hw_id, inst_id); + } } -#else -#define CHECK_ERR_RC(ctx, rc, opcode, type, hw_id, inst_id) \ - { \ - ni_session_stats_t err_rc_info = {0}; \ - int err_rc = \ - ni_query_session_stats(ctx, type, &err_rc_info, rc, opcode); \ - if (err_rc != NI_RETCODE_SUCCESS) \ - { \ - ni_log(NI_LOG_ERROR, \ - "PANIC!!!! - Query for stats failed. What to do?\n"); \ - exit(EXIT_FAILURE); \ - } \ - (rc) = err_rc_info.ui32LastTransactionCompletionStatus; \ - int tmp_rc = NI_RETCODE_FAILURE; \ - if (((ctx)->rc_error_count >= NI_XCODER_FAILURES_MAX) || \ - (tmp_rc = \ - ni_nvme_check_error_code(rc, opcode, type, hw_id, inst_id))) \ - { \ - ni_log( \ - NI_LOG_ERROR, \ - "Persistent failures detected, %s() line-%d: session_no 0x%x " \ - "sess_err_count %u inst_err_no %u rc_error_count: %d\n", \ - __func__, __LINE__, *(inst_id), err_rc_info.ui16ErrorCount, \ - err_rc_info.ui32LastErrorStatus, (ctx)->rc_error_count); \ - (rc) = tmp_rc; \ - LRETURN; \ - } \ + else if(opt == OPT_3) + { + retval = ni_nvme_check_error_code(stat.ui32LastTransactionCompletionStatus, opcode, type, hw_id, inst_id); } -#define CHECK_ERR_RC2(ctx, rc, err_rc_info, opcode, type, hw_id, inst_id) \ - { \ - (rc) = (err_rc_info).ui32LastTransactionCompletionStatus; \ - if ((err_rc_info).ui16ErrorCount || (rc)) \ - (ctx)->rc_error_count++; \ - else \ - (ctx)->rc_error_count = 0; \ - int tmp_rc = NI_RETCODE_FAILURE; \ - if ((err_rc_info).ui16ErrorCount || \ - (ctx)->rc_error_count >= NI_XCODER_FAILURES_MAX || \ - (tmp_rc = ni_nvme_check_error_code((rc), (opcode), (type), \ - (hw_id), (inst_id)))) \ - { \ - ni_log(NI_LOG_ERROR, "Persistent failures detected, %s() line-%d: "\ - "session_no 0x%x sess_err_no %u inst_err_no %u " \ - "rc_error_count: %d\n", __func__, __LINE__, *(inst_id), \ - (err_rc_info).ui16ErrorCount, \ - (err_rc_info).ui32LastTransactionCompletionStatus, \ - (ctx)->rc_error_count); \ - (rc) = tmp_rc; \ - LRETURN; \ - } \ - } + if (retval) + { + ni_log2(ctx, + NI_LOG_ERROR, + "Persistent failures detected, %s() line-%d: session_no 0x%x " + "sess_err_count %u inst_err_no %u\n", + func, line, *(inst_id), ui16ErrorCount, + ui32LastErrorStatus); +#ifdef XCODER_SELF_KILL_ERR + if(opt != OPT_3) + { + kill(getpid(), SIGTERM); + } #endif + } -#endif + return retval; +} + +//Following macros will only check for critical failures. +//After the macro runs, rc should contain the status of the last command sent +//For non-critical failures, it is assumed in the code that eventually after enough retries, a command will succeed. +//Invalid parameters or resource busy do not account for failures that cause error count to be incremented so they can be retried indefinitely +#define CHECK_ERR_RC(ctx, rc, info, opcode, type, hw_id, inst_id, opt) \ + { \ + (rc) = check_err_rc(ctx, rc, info, opcode, type, hw_id, inst_id, opt, __func__, __LINE__); \ + if((rc) && ((opt) != OPT_3)) LRETURN; \ + } #define CHECK_VPU_RECOVERY(ret) \ { \ @@ -327,6 +263,67 @@ static struct stat g_nvme_stat = {0}; } \ } +// ctx->decoder_low_delay is used as condition wait timeout for both decoder +// and encoder send/recv multi-thread in low delay mode. +static void low_delay_wait(ni_session_context_t* p_ctx) +{ + const char *name = p_ctx->device_type == NI_DEVICE_TYPE_DECODER ? \ + "decoder" : "encoder"; + if (p_ctx->async_mode && p_ctx->decoder_low_delay > 0) + { + int ret; + uint64_t abs_time_ns; + struct timespec ts; + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s waiting for %s recv thread\n", __FUNCTION__, name); + + abs_time_ns = ni_gettime_ns(); + abs_time_ns += p_ctx->decoder_low_delay * 1000000LL; + ts.tv_sec = abs_time_ns / 1000000000LL; + ts.tv_nsec = abs_time_ns % 1000000000LL; + + ni_pthread_mutex_lock(&p_ctx->low_delay_sync_mutex); + while (p_ctx->low_delay_sync_flag) + { + // In case of dead lock on waiting for notification from recv thread. + ni_pthread_mutex_unlock(&p_ctx->mutex); + ret = ni_pthread_cond_timedwait(&p_ctx->low_delay_sync_cond, + &p_ctx->low_delay_sync_mutex, &ts); + ni_pthread_mutex_lock(&p_ctx->mutex); + if (ret == ETIMEDOUT) + { + p_ctx->low_delay_sync_flag = 0; + } + } + ni_pthread_mutex_unlock(&p_ctx->low_delay_sync_mutex); + } +} + +static void low_delay_signal(ni_session_context_t* p_ctx) +{ + const char *name = p_ctx->device_type == NI_DEVICE_TYPE_DECODER ? \ + "decoder" : "encoder"; + if (p_ctx->async_mode && p_ctx->decoder_low_delay > 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: wake up %s send thread\n", __FUNCTION__, name); + ni_pthread_mutex_lock(&p_ctx->low_delay_sync_mutex); + p_ctx->low_delay_sync_flag = 0; + ni_pthread_cond_signal(&p_ctx->low_delay_sync_cond); + ni_pthread_mutex_unlock(&p_ctx->low_delay_sync_mutex); + } +} + +static void query_sleep(ni_session_context_t* p_ctx) +{ + if (p_ctx->async_mode) + { + // To avoid IO spam on NP core from queries and high volumens on latency. + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); + } +} + // create folder bearing the card name (nvmeX) if not existing // start working inside this folder: nvmeX // find the earliest saved and/or non-existing stream folder and use it as @@ -352,7 +349,7 @@ static void decoder_dump_dir_open(ni_session_context_t *p_ctx) ni_rsrc_get_device_context(p_ctx->device_type, p_ctx->hw_id); if (!p_device_context) { - ni_log(NI_LOG_ERROR, "Error retrieve device context for decoder guid %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "Error retrieve device context for decoder guid %d\n", p_ctx->hw_id); return; } @@ -364,17 +361,17 @@ static void decoder_dump_dir_open(ni_session_context_t *p_ctx) { if (0 != mkdir(dir_name, S_IRWXU | S_IRWXG | S_IRWXO)) { - ni_log(NI_LOG_ERROR, "Error create folder %s, errno %d\n", dir_name, + ni_log2(p_ctx, NI_LOG_ERROR, "Error create folder %s, errno %d\n", dir_name, NI_ERRNO); } else { - ni_log(NI_LOG_DEBUG, "Created pkt folder for: %s\n", dir_name); + ni_log2(p_ctx, NI_LOG_DEBUG, "Created pkt folder for: %s\n", dir_name); } } if (NULL == (dir = opendir(dir_name))) { - ni_log(NI_LOG_ERROR, "Error %d: failed to open directory %s\n", + ni_log2(p_ctx, NI_LOG_ERROR, "Error %d: failed to open directory %s\n", NI_ERRNO, dir_name); } else { @@ -427,7 +424,7 @@ static void decoder_dump_dir_open(ni_session_context_t *p_ctx) // just take pkt-0001 file timestamp to simplify search if (stat(file_name, &file_stat)) { - ni_log(NI_LOG_ERROR, "Error %d: failed to stat file %s\n", + ni_log2(p_ctx, NI_LOG_ERROR, "Error %d: failed to stat file %s\n", NI_ERRNO, file_name); } else @@ -451,7 +448,7 @@ static void decoder_dump_dir_open(ni_session_context_t *p_ctx) dir_name, curr_stream_idx); if (utime(file_name, NULL)) { - ni_log(NI_LOG_ERROR, "Error utime %s\n", file_name); + ni_log2(p_ctx, NI_LOG_ERROR, "Error utime %s\n", file_name); } } // 128 streams in nvmeY already closedir(dir); @@ -464,16 +461,16 @@ static void decoder_dump_dir_open(ni_session_context_t *p_ctx) { if (0 != mkdir(p_ctx->stream_dir_name, S_IRWXU | S_IRWXG | S_IRWXO)) { - ni_log(NI_LOG_ERROR, "Error create stream folder %s, errno %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "Error create stream folder %s, errno %d\n", p_ctx->stream_dir_name, NI_ERRNO); } else { - ni_log(NI_LOG_DEBUG, "Created stream sub folder: %s\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Created stream sub folder: %s\n", p_ctx->stream_dir_name); } } else { - ni_log(NI_LOG_DEBUG, "Reusing stream sub folder: %s\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Reusing stream sub folder: %s\n", p_ctx->stream_dir_name); } @@ -487,32 +484,160 @@ static void decoder_dump_dir_open(ni_session_context_t *p_ctx) if (fp) { char number[64] = {'\0'}; - ni_log(NI_LOG_DEBUG, "Decoder pkt dump log created: %s\n", file_name); + ni_log2(p_ctx, NI_LOG_DEBUG, "Decoder pkt dump log created: %s\n", file_name); snprintf(number, sizeof(number), "proc id: %ld\nsession id: %u\n", (long)getpid(), p_ctx->session_id); fwrite(number, strlen(number), 1, fp); fclose(fp); } else { - ni_log(NI_LOG_ERROR, "Error create decoder pkt dump log: %s\n", file_name); + ni_log2(p_ctx, NI_LOG_ERROR, "Error create decoder pkt dump log: %s\n", file_name); } #endif } -// check if fw_rev is higher than the specified -static uint32_t is_fw_rev_higher(ni_session_context_t* p_ctx, uint8_t major, uint8_t minor) + +// open netint p2p driver and fill the pcie address to p_ctx +static ni_retcode_t p2p_fill_pcie_address(ni_session_context_t *p_ctx) { - if ((p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] > major) || - ((p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] == major) && - (p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX] > minor))) +#ifdef _WIN32 + (void)p_ctx; + return NI_RETCODE_FAILURE; +#else + int ret = 0; + char line[256]; + char syspath[256]; + struct stat bstat; + char *p_dev; + char *dom, *bus, *dev, *fnc; + FILE *fp; + + if(!p_ctx) { - return 1; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() parameter is NULL\n",__func__); + return NI_RETCODE_FAILURE; } - else + + p_ctx->netint_fd = open("/dev/netint", O_RDWR); + if (p_ctx->netint_fd < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Can't open device /dev/netint\n"); + return NI_RETCODE_FAILURE; + } + + p_dev = &p_ctx->dev_xcoder_name[0]; + if (stat(p_dev, &bstat) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "failed to get stat of file %s\n", p_dev); + return NI_RETCODE_FAILURE; + } + + if ((bstat.st_mode & S_IFMT) != S_IFBLK) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s is not a block device\n", p_dev); + return NI_RETCODE_FAILURE; + } + +#ifdef _ANDROID + ret = snprintf(syspath, sizeof(syspath) - 1, + "/sys/block/%s/device/address", + p_dev + 5); + syspath[ret] = '\0'; + + fp = fopen(syspath, "r"); +#else + ret = snprintf(syspath, sizeof(syspath) - 1, + "udevadm info -q path -n %s | perl -nle'print $& " + "while m{(?<=/)[0-9a-f]{4}:[0-9a-f]{2}:[0-9a-f]{2}\\.[0-9a-f]}g' | tail -n 1", + p_dev + 5); + syspath[ret] = '\0'; + + fp = popen(syspath, "r"); +#endif + + if (fp == NULL) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Failed to read address\n"); + return NI_RETCODE_FAILURE; + } + + if (fgets(line, 256, fp) == NULL) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Failed to read line from address\n"); +#ifdef _ANDROID + fclose(fp); +#else + pclose(fp); +#endif + return NI_RETCODE_FAILURE; + } + +#ifdef _ANDROID + fclose(fp); +#else + pclose(fp); +#endif + + errno = 0; + p_ctx->domain = strtoul(line, &dom, 16); + if (errno < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Failed to read PCI domain\n"); + return NI_RETCODE_FAILURE; + } + + errno = 0; + p_ctx->bus = strtoul(dom + 1, &bus, 16); + if (errno < 0) { - return 0; + ni_log2(p_ctx, NI_LOG_ERROR, "Failed to read PCI bus\n"); + return NI_RETCODE_FAILURE; + } + + errno = 0; + p_ctx->dev = strtoul(bus + 1, &dev, 16); + + if (errno < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Failed to read PCI device\n"); + return NI_RETCODE_FAILURE; + } + + errno = 0; + p_ctx->fn = strtoul(dev + 1, &fnc, 16); + + if (errno < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Falied to read PCI function\n"); + return NI_RETCODE_FAILURE; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "PCI slot = %d:%d:%d:%d\n", p_ctx->domain, + p_ctx->bus, p_ctx->dev, p_ctx->fn); + + return NI_RETCODE_SUCCESS; + +#endif +} + +#if __linux__ || __APPLE__ +#ifndef _ANDROID +#ifndef DISABLE_BACKTRACE_PRINT +void ni_print_backtrace() { + void* callstack[128]; + int frames = backtrace(callstack, 128); + char** strs = backtrace_symbols(callstack, frames); + + ni_log(NI_LOG_ERROR, "Call stack:\n"); + for (int i = 0; i < frames; ++i) { + ni_log(NI_LOG_ERROR, "%s\n", strs[i]); } + + free(strs); } +#endif +#endif +#endif /*!****************************************************************************** * \brief Open a xcoder decoder instance @@ -525,15 +650,15 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) { ni_retcode_t retval = NI_RETCODE_SUCCESS; ni_xcoder_params_t *p_param = NULL; - uint32_t buffer_size = 0; void* p_buffer = NULL; uint32_t ui32LBA = 0; + char fmt_fw_api_ver1[5], fmt_fw_api_ver2[5]; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR %s(): passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -553,6 +678,7 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) p_ctx->status = 0; p_ctx->key_frame_type = 0; p_ctx->ready_to_close = 0; + p_ctx->max_retry_fail_count[0] = p_ctx->max_retry_fail_count[1] = 0; p_ctx->rc_error_count = 0; p_ctx->frame_num = 0; p_ctx->pkt_num = 0; @@ -560,13 +686,15 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) p_ctx->session_timestamp = 0; p_ctx->is_dec_pkt_512_aligned = 0; p_ctx->p_all_zero_buf = NULL; + p_ctx->last_pkt_pos = 0; + p_ctx->last_frame_offset = 0; memset(p_ctx->pkt_custom_sei_set, 0, NI_FIFO_SZ * sizeof(ni_custom_sei_set_t *)); //malloc zero data buffer if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc decoder all zero buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; @@ -577,7 +705,7 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) //malloc data buffer if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO, __func__); ni_aligned_free(p_ctx->p_all_zero_buf); retval = NI_RETCODE_ERROR_MEM_ALOC; @@ -596,25 +724,24 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); LRETURN; } //Open will return a session status structure with a valid session id if it worked. //Otherwise the invalid session id set before the open command will stay p_ctx->session_id = ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); - p_ctx->session_timestamp = - ni_htonll(((ni_session_stats_t *)p_buffer)->ui64Session_timestamp); + p_ctx->session_timestamp = ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_high); + p_ctx->session_timestamp = (p_ctx->session_timestamp << 32) | + ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_low); if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, - "ERROR %s(): p_ctx->device_handle=%" PRIx64 - ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): p_ctx->device_handle=0x%" PRIx64 ", " + "p_ctx->hw_id=%d, p_ctx->session_id=%d\n", __func__, + (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - ni_log(NI_LOG_DEBUG, "Decoder open session ID:0x%x, timestamp:%" PRIu64 "\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Decoder open session ID:0x%x, timestamp:%" PRIu64 "\n", p_ctx->session_id, p_ctx->session_timestamp); //Send keep alive timeout Info @@ -622,18 +749,18 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) p_ctx->keep_alive_timeout * 1000000; //send us to FW memset(p_buffer, 0, NI_DATA_BUFFER_LEN); memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); - ni_log(NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, keep_alive_timeout); ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme write keep_alive_timeout command " "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); @@ -641,27 +768,27 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) LRETURN; } - // Send SW version to FW if FW version is higher than major 6 minor 1 - if (is_fw_rev_higher(p_ctx, (uint8_t)'6', (uint8_t)'1')) + // Send SW version to FW if FW API version is >= 6.2 + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "62") >= 0) { // Send SW version to session manager memset(p_buffer, 0, NI_DATA_BUFFER_LEN); memcpy(p_buffer, NI_XCODER_REVISION, sizeof(uint64_t)); - ni_log(NI_LOG_DEBUG, "%s sw_version major %c minor %c fw_rev major %c minor %c\n", __func__, - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX]); + ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &fmt_fw_api_ver1[0]); + ni_fmt_fw_api_ver_str((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &fmt_fw_api_ver2[0]); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s libxcoder FW API ver %s, FW FW API ver %s\n", + __func__, fmt_fw_api_ver1, fmt_fw_api_ver2); ui32LBA = CONFIG_SESSION_SWVersion_W(p_ctx->session_id); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme write sw_version command " "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); @@ -674,29 +801,27 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) //well if(p_ctx->codec_format == NI_CODEC_FORMAT_VP9) { - ni_log(NI_LOG_DEBUG, "Adding scaling session to Vp9 decoder\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "Adding scaling session to Vp9 decoder\n"); ui32LBA = OPEN_ADD_CODEC(NI_DEVICE_TYPE_SCALER, ni_htonl(NI_SCALER_OPCODE_SCALE), ni_htons(p_ctx->session_id)); retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_open, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_open, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR couldn't add vp9 scaler to decoding session\n"); - ni_log(NI_LOG_ERROR, - "ERROR %s(): p_ctx->device_handle=%" PRIx64 ", " - "p_ctx->hw_id=%d, p_ctx->session_id=%d\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR couldn't add vp9 scaler to decoding session\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s():p_ctx->device_handle=0x%" PRIx64 ", " + "p_ctx->hw_id=%d, p_ctx->session_id=%d\n", __func__, + (int64_t)p_ctx->device_handle,p_ctx->hw_id, p_ctx->session_id); ni_decoder_session_close(p_ctx, 0); LRETURN; } } - ni_log(NI_LOG_DEBUG, - "%s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, " + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_ctx->device_handle=0x%" PRIx64 ", p_ctx->hw_id=%d, " "p_ctx->session_id=%d\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); @@ -706,7 +831,7 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) retval = ni_config_instance_set_decoder_params(p_ctx, 0); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: calling ni_config_instance_set_decoder_params(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: calling ni_config_instance_set_decoder_params(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); //ni_decoder_session_close(p_ctx, 0); //close happens on above retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -718,6 +843,7 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) p_ctx->last_pts = NI_NOPTS_VALUE; p_ctx->last_dts = NI_NOPTS_VALUE; p_ctx->last_dts_interval = 0; + p_ctx->last_pts_interval = 0; p_ctx->pts_correction_last_dts = INT64_MIN; p_ctx->pts_correction_last_pts = INT64_MIN; @@ -725,7 +851,7 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) p_ctx->p_leftover = malloc(p_ctx->max_nvme_io_size * 2); if (!p_ctx->p_leftover) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Cannot allocate leftover buffer.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Cannot allocate leftover buffer.\n", __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; //ni_decoder_session_close(p_ctx, 0); @@ -739,13 +865,37 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) { p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; ni_params_print(p_param); + + if (p_param->ddr_priority_mode > NI_DDR_PRIORITY_NONE) + { + retval = ni_device_set_ddr_configuration(p_ctx, p_param->ddr_priority_mode); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): ddr priority setting failure for %s\n", + __func__, strerror(NI_ERRNO)); + LRETURN; + } + } + } + + if (p_ctx->force_low_delay) + { + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r3") < 0) + { + p_ctx->force_low_delay = false; // forceLowDelay not available for fw < 6r3 + ni_log2(p_ctx, NI_LOG_INFO, "Warn %s(): forceLowDelay is not available for fw < 6r3\n", + __func__); + } } p_ctx->active_video_width = 0; p_ctx->active_video_height = 0; p_ctx->actual_video_width = 0; + p_ctx->pixel_format_changed = 0; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, " "p_ctx->session_id=%d\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, @@ -765,14 +915,17 @@ ni_retcode_t ni_decoder_session_open(ni_session_context_t* p_ctx) if (!dir && ENOENT == NI_ERRNO) { mkdir(dir_name, S_IRWXU | S_IRWXG | S_IRWXO); - ni_log(NI_LOG_DEBUG, "Decoder frame dump dir created: %s\n", dir_name); + ni_log2(p_ctx, NI_LOG_DEBUG, "Decoder frame dump dir created: %s\n", dir_name); + } + if(dir){ + closedir(dir); } #endif END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -816,7 +969,8 @@ ni_retcode_t ni_send_session_keep_alive(uint32_t session_id, ni_device_handle_t } else { - ni_log(NI_LOG_TRACE, "SUCCESS %s(): device_handle=%" PRIx64 " , " + ni_log(NI_LOG_TRACE, + "SUCCESS %s(): device_handle=%" PRIx64 " , " "session_id=%d\n", __func__, (int64_t)device_handle, session_id); retval = NI_RETCODE_SUCCESS; } @@ -828,6 +982,51 @@ ni_retcode_t ni_send_session_keep_alive(uint32_t session_id, ni_device_handle_t return retval; } +/*!****************************************************************************** + * \brief Send end of stream signal to the decoder + * + * \param + * + * \return + *******************************************************************************/ +ni_retcode_t ni_decoder_session_send_eos(ni_session_context_t* p_ctx) +{ + ni_retcode_t retval; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + retval = ni_config_instance_eos(p_ctx, NI_DEVICE_TYPE_DECODER); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + +END: + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): %d, return\n", __func__, retval); + } + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} + /*!****************************************************************************** * \brief Flush decoder output * @@ -838,11 +1037,11 @@ ni_retcode_t ni_send_session_keep_alive(uint32_t session_id, ni_device_handle_t ni_retcode_t ni_decoder_session_flush(ni_session_context_t* p_ctx) { ni_retcode_t retval; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -850,26 +1049,27 @@ ni_retcode_t ni_decoder_session_flush(ni_session_context_t* p_ctx) if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): xcoder instance id < 0, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): xcoder instance id < 0, return\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - retval = ni_config_instance_eos(p_ctx, NI_DEVICE_TYPE_DECODER); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + retval = ni_config_instance_flush(p_ctx, NI_DEVICE_TYPE_DECODER); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS == retval) - { - p_ctx->ready_to_close = 1; - } + &(p_ctx->session_id), OPT_1); END: - ni_log(NI_LOG_TRACE, "%s(): success exit\n", __func__); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): %d, return\n", __func__, retval); + } + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); - return retval; + return retval; } /*!****************************************************************************** @@ -884,42 +1084,81 @@ ni_retcode_t ni_decoder_session_close(ni_session_context_t* p_ctx, int eos_recie ni_retcode_t retval = NI_RETCODE_SUCCESS; void* p_buffer = NULL; uint32_t ui32LBA = 0; - int counter = 0; - int ret = 0; int i; + ni_xcoder_params_t *p_param = NULL; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_SUCCESS; LRETURN; } + if (NI_CODEC_HW_ENABLE == p_ctx->hw_action) + { + ni_session_statistic_t sessionStatistic = {0}; + ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_DECODER, &sessionStatistic); + } + + ni_log2(p_ctx, NI_LOG_INFO, + "Decoder_complete_info:session_id 0x%x, total frames input:%u " + "buffered: %u completed: %u output: %u dropped: %u error: %u\n", + p_ctx->session_id, p_ctx->session_statistic.ui32FramesInput, + p_ctx->session_statistic.ui32FramesBuffered, + p_ctx->session_statistic.ui32FramesCompleted, + p_ctx->session_statistic.ui32FramesOutput, + p_ctx->session_statistic.ui32FramesDropped, + p_ctx->session_statistic.ui32InstErrors); + + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s: Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + //malloc data buffer if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: malloc decoder close data buffer failed\n", NI_ERRNO); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: malloc decoder close data buffer failed\n", NI_ERRNO); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - ui32LBA = CLOSE_SESSION_R(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); + if (p_ctx->p_session_config) + { + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + if (p_param->ddr_priority_mode > NI_DDR_PRIORITY_NONE) + { + retval = ni_device_set_ddr_configuration(p_ctx, NI_DDR_PRIORITY_RESET); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): ddr priority setting failure for %s\n", + __func__, strerror(NI_ERRNO)); + LRETURN; + } + } + } + + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + + ui32LBA = CLOSE_SESSION_R(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); int retry = 0; while (retry < NI_SESSION_CLOSE_RETRY_MAX) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_ctx->blk_io_handle=%" PRIx64 ", p_ctx->hw_id=%d, " "p_ctx->session_id=%d, close_mode=1\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, @@ -928,16 +1167,17 @@ ni_retcode_t ni_decoder_session_close(ni_session_context_t* p_ctx, int eos_recie if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): command failed!\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): command failed!\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + p_ctx->session_id = NI_INVALID_SESSION_ID; break; } else - { - //Close should always succeed - retval = NI_RETCODE_SUCCESS; - p_ctx->session_id = NI_INVALID_SESSION_ID; - break; - } + { + //Close should always succeed + retval = NI_RETCODE_SUCCESS; + p_ctx->session_id = NI_INVALID_SESSION_ID; + break; + } /* else if (*((ni_retcode_t *)p_buffer) == RETCODE_SUCCESS) { @@ -947,7 +1187,7 @@ ni_retcode_t ni_decoder_session_close(ni_session_context_t* p_ctx, int eos_recie } else { - ni_log(NI_LOG_DEBUG, "%s(): wait for close\n", __func__); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): wait for close\n", __func__); ni_usleep(NI_SESSION_CLOSE_RETRY_INTERVAL_US); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } @@ -959,37 +1199,40 @@ ni_retcode_t ni_decoder_session_close(ni_session_context_t* p_ctx, int eos_recie ni_aligned_free(p_buffer); ni_aligned_free(p_ctx->p_all_zero_buf); - ni_aligned_free(p_ctx->p_leftover); + ni_memfree(p_ctx->p_leftover); if (p_ctx->pts_table) { ni_queue_free(&p_ctx->pts_table->list, p_ctx->buffer_pool); - ni_aligned_free(p_ctx->pts_table); - ni_log(NI_LOG_DEBUG, "ni_timestamp_done: success\n"); + ni_memfree(p_ctx->pts_table); + ni_log2(p_ctx, NI_LOG_DEBUG, "ni_timestamp_done: success\n"); } if (p_ctx->dts_queue) { ni_queue_free(&p_ctx->dts_queue->list, p_ctx->buffer_pool); - ni_aligned_free(p_ctx->dts_queue); - ni_log(NI_LOG_DEBUG, "ni_timestamp_done: success\n"); + ni_memfree(p_ctx->dts_queue); + ni_log2(p_ctx, NI_LOG_DEBUG, "ni_timestamp_done: success\n"); } ni_buffer_pool_free(p_ctx->buffer_pool); - p_ctx->buffer_pool = NULL; - ni_dec_fme_buffer_pool_free(p_ctx->dec_fme_buf_pool); + p_ctx->buffer_pool = NULL; p_ctx->dec_fme_buf_pool = NULL; for (i = 0; i < NI_FIFO_SZ; i++) { - ni_aligned_free(p_ctx->pkt_custom_sei_set[i]); + ni_memfree(p_ctx->pkt_custom_sei_set[i]); } - ni_log(NI_LOG_DEBUG, "%s(): CTX[Card:%" PRIx64 " / HW:%d / INST:%d]\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): CTX[Card:%" PRIx64 " / HW:%d / INST:%d]\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + + low_delay_signal(p_ctx); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -1005,40 +1248,39 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) { uint32_t sent_size = 0; uint32_t packet_size = 0; - uint32_t write_size_bytes = 0; - uint32_t actual_sent_size = 0; - uint32_t pkt_chunk_count = 0; int current_pkt_size; int retval = NI_RETCODE_SUCCESS; ni_xcoder_params_t *p_param; ni_instance_buf_info_t buf_info = { 0 }; + ni_session_statistic_t sessionStatistic = {0}; int query_retry = 0; uint32_t ui32LBA = 0; -#ifdef MEASURE_LATENCY - uint64_t abs_time_ns; -#endif - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if ((!p_ctx) || (!p_packet)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if ((NI_INVALID_SESSION_ID == p_ctx->session_id)) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } + low_delay_wait(p_ctx); + #ifdef MEASURE_LATENCY if ((p_packet->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) { - abs_time_ns = ni_gettime_ns(); + uint64_t abs_time_ns = ni_gettime_ns(); ni_lat_meas_q_add_entry((ni_lat_meas_q_t *)p_ctx->frame_time_q, abs_time_ns, p_packet->dts); } @@ -1050,26 +1292,65 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) for (;;) { + query_sleep(p_ctx); + query_retry++; - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, - NI_DEVICE_TYPE_DECODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "65") >= 0) + { + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_DECODER, + &sessionStatistic); + CHECK_ERR_RC(p_ctx, retval, &sessionStatistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + CHECK_VPU_RECOVERY(retval); + + buf_info.buf_avail_size = sessionStatistic.ui32WrBufAvailSize; + } else + { + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, + NI_DEVICE_TYPE_DECODER, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + } + + if (buf_info.buf_avail_size == DP_IPC_PASSTHRU) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): Bad available buffer size %u\n", __FUNCTION__, buf_info.buf_avail_size); + retval = NI_RETCODE_FAILURE; + LRETURN; + } if (p_ctx->biggest_bitstream_buffer_allocated < buf_info.buf_avail_size) { p_ctx->biggest_bitstream_buffer_allocated = buf_info.buf_avail_size; } - if (p_ctx->biggest_bitstream_buffer_allocated < packet_size) + if (p_ctx->biggest_bitstream_buffer_allocated < packet_size && + buf_info.buf_avail_size == p_ctx->biggest_bitstream_buffer_allocated) { - // Reallocate decoder bitstream buffers to accomodate. - retval = ni_config_instance_set_decoder_params(p_ctx, packet_size); + // Reallocate decoder bitstream buffers to accomodate + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "66") >= 0) + { + retval = ni_config_instance_set_write_len(p_ctx, + NI_DEVICE_TYPE_DECODER, + // packet buffer aligned to NI_MAX_PACKET_SZ(128k) + (packet_size / NI_MAX_PACKET_SZ + 1) * NI_MAX_PACKET_SZ); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_config_xcoder_config_set_write_legth, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_3); + CHECK_VPU_RECOVERY(retval); + } + else + { + retval = ni_config_instance_set_decoder_params(p_ctx, packet_size); + } if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "%s(): failed to reallocate bitstream\n", __FUNCTION__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): failed to reallocate bitstream\n", __FUNCTION__); LRETURN; } query_retry--; @@ -1079,23 +1360,25 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) if (NI_RETCODE_SUCCESS != retval || buf_info.buf_avail_size < packet_size) { - ni_log(NI_LOG_DEBUG, - "Warning dec write query fail rc %d or available " - "buf size %u < pkt size %u , retry: %d\n", - retval, buf_info.buf_avail_size, packet_size, query_retry); + ni_log2(p_ctx, NI_LOG_TRACE, + "Warning: dec write query fail rc %d or available buf size %u < " + "pkt size %u , retry: %d max_retry_fail_count %d\n", + retval, buf_info.buf_avail_size, packet_size, query_retry, p_ctx->max_retry_fail_count[0]); if (query_retry > NI_MAX_TX_RETRIES) { p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; - retval = NI_RETCODE_SUCCESS; + p_ctx->max_retry_fail_count[0]++; + retval = (p_ctx->max_retry_fail_count[0] >= NI_XCODER_FAILURES_MAX) ? NI_RETCODE_FAILURE : NI_RETCODE_SUCCESS; LRETURN; } - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); - ni_usleep(100); - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); } else { - ni_log(NI_LOG_DEBUG, "Info dec write query success, available buf " + p_ctx->max_retry_fail_count[0] = 0; + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec write query success, available buf " "size %u >= pkt size %u !\n", buf_info.buf_avail_size, packet_size); break; @@ -1105,13 +1388,13 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) //Configure write size for the buffer retval = ni_config_instance_set_write_len(p_ctx, NI_DEVICE_TYPE_DECODER, packet_size); - CHECK_ERR_RC(p_ctx, retval, nvme_config_xcoder_config_set_write_legth, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_config_xcoder_config_set_write_legth, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (retval < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): config pkt size command failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): config pkt size command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; @@ -1123,13 +1406,13 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) if (p_packet->start_of_stream) { retval = ni_config_instance_sos(p_ctx, NI_DEVICE_TYPE_DECODER); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Failed to send SOS.\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Failed to send SOS.\n", __func__); LRETURN; } @@ -1138,7 +1421,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) if (p_packet->p_data) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s() had data to send: packet_size=%u, " "p_packet->sent_size=%d, p_packet->data_len=%u, " "p_packet->start_of_stream=%u, p_packet->end_of_stream=%u, " @@ -1147,7 +1430,6 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) p_packet->start_of_stream, p_packet->end_of_stream, p_packet->video_width, p_packet->video_height); - uint32_t send_count = 0; uint8_t *p_data = (uint8_t *)p_packet->p_data; // Note: session status is NOT reset but tracked between send // and recv to catch and recover from a loop condition @@ -1160,12 +1442,12 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_data, packet_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_write, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (retval < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -1193,20 +1475,21 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) } p_ctx->pkt_num++; + p_ctx->low_delay_sync_flag = 1; } //Handle end of stream flag if (p_packet->end_of_stream) { retval = ni_config_instance_eos(p_ctx, NI_DEVICE_TYPE_DECODER); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Failed to send EOS.\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Failed to send EOS.\n", __func__); LRETURN; } @@ -1222,7 +1505,8 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) p_ctx->pts_offsets[p_ctx->pkt_index] = p_packet->pts; p_ctx->flags_array[p_ctx->pkt_index] = p_packet->flags; p_ctx->pkt_offsets_index[p_ctx->pkt_index] = current_pkt_size/512; // assuming packet_size is 512 aligned - ni_log(NI_LOG_DEBUG, + p_ctx->pkt_pos[p_ctx->pkt_index] = p_packet->pkt_pos; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: pkt_index %d pkt_offsets_index %" PRIu64 " pts_offsets %" PRId64 "\n", __func__, p_ctx->pkt_index, @@ -1231,7 +1515,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) p_ctx->pkt_index ++; if (p_ctx->pkt_index >= NI_MAX_DEC_REJECT) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): more than NI_MAX_DEC_REJECT frames are rejected by the " "decoder. Increase NI_MAX_DEC_REJECT is required or default " "gen pts values will be used !\n", @@ -1244,6 +1528,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) { p_ctx->pts_offsets[p_ctx->pkt_index % NI_FIFO_SZ] = p_packet->pts; p_ctx->flags_array[p_ctx->pkt_index % NI_FIFO_SZ] = p_packet->flags; + p_ctx->pkt_pos[p_ctx->pkt_index % NI_FIFO_SZ] = p_packet->pkt_pos; if (p_ctx->pkt_index == 0) { p_ctx->pkt_offsets_index_min[p_ctx->pkt_index % NI_FIFO_SZ] = 0; @@ -1251,7 +1536,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) * move 1 byte forward on all the pkt_offset so that frame_offset coming from fw can fall into the correct range. */ //p_ctx->pkt_offsets_index[p_ctx->pkt_index % NI_FIFO_SZ] = current_pkt_size - 1; p_ctx->pkt_offsets_index[p_ctx->pkt_index % NI_FIFO_SZ] = current_pkt_size; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (first packet) pkt_index %d i %u " "pkt_offsets_index_min %" PRIu64 " pkt_offsets_index %" PRIu64 " pts_offsets %" PRId64 "\n", @@ -1265,7 +1550,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) // cumulate sizes to correspond to FW offsets p_ctx->pkt_offsets_index_min[p_ctx->pkt_index % NI_FIFO_SZ] = p_ctx->pkt_offsets_index[(p_ctx->pkt_index - 1) % NI_FIFO_SZ]; p_ctx->pkt_offsets_index[p_ctx->pkt_index % NI_FIFO_SZ] = p_ctx->pkt_offsets_index[(p_ctx->pkt_index - 1) % NI_FIFO_SZ] + current_pkt_size; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: pkt_index %d i %u pkt_offsets_index_min " "%" PRIu64 " pkt_offsets_index %" PRIu64 " pts_offsets %" PRId64 "\n", @@ -1279,7 +1564,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) { p_ctx->pkt_offsets_index_min[p_ctx->pkt_index % NI_FIFO_SZ] = p_ctx->pkt_offsets_index_min[p_ctx->pkt_index % NI_FIFO_SZ] - (0x100000000); p_ctx->pkt_offsets_index[p_ctx->pkt_index % NI_FIFO_SZ] = p_ctx->pkt_offsets_index_min[p_ctx->pkt_index % NI_FIFO_SZ] + current_pkt_size; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (wrap) pkt_index %d i %u " "pkt_offsets_index_min %" PRIu64 " pkt_offsets_index %" PRIu64 " pts_offsets %" PRId64 "\n", @@ -1291,7 +1576,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) } /* if this wrap-around pkt_offset_index spot is about to be overwritten, free the previous one. */ - ni_aligned_free(p_ctx->pkt_custom_sei_set[p_ctx->pkt_index % NI_FIFO_SZ]); + free(p_ctx->pkt_custom_sei_set[p_ctx->pkt_index % NI_FIFO_SZ]); if (p_packet->p_custom_sei_set) { @@ -1304,7 +1589,7 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) else { /* warn and lose the sei data. */ - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "Error %s: failed to allocate custom SEI buffer for pkt.\n", __func__); } @@ -1320,23 +1605,25 @@ int ni_decoder_session_write(ni_session_context_t* p_ctx, ni_packet_t* p_packet) retval = ni_timestamp_register(p_ctx->buffer_pool, p_ctx->dts_queue, p_packet->dts, 0); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): ni_timestamp_register() for dts returned %d\n", __func__, retval); } END: + ni_pthread_mutex_unlock(&p_ctx->mutex); + if (NI_RETCODE_SUCCESS == retval) { - ni_log(NI_LOG_TRACE, + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit: packets: %" PRIu64 " offset %" PRIx64 "" - "sent_size = %u, status=%d\n", + " sent_size = %u, status=%d\n", __func__, p_ctx->pkt_num, (uint64_t)p_packet->pos, sent_size, p_ctx->status); return sent_size; } else { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): exit: returnErr: %d, p_ctx->status: %d\n", __func__, retval, p_ctx->status); return retval; @@ -1350,7 +1637,7 @@ static int64_t guess_correct_pts(ni_session_context_t* p_ctx, int64_t reordered_ { p_ctx->pts_correction_num_faulty_dts += dts <= p_ctx->pts_correction_last_dts; p_ctx->pts_correction_last_dts = dts; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: pts_correction_last_dts %" PRId64 " " "pts_correction_num_faulty_dts %d\n", __func__, p_ctx->pts_correction_last_dts, @@ -1359,14 +1646,14 @@ static int64_t guess_correct_pts(ni_session_context_t* p_ctx, int64_t reordered_ else if (reordered_pts != NI_NOPTS_VALUE) { p_ctx->pts_correction_last_dts = reordered_pts; - ni_log(NI_LOG_DEBUG, "%s: pts_correction_last_dts %" PRId64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: pts_correction_last_dts %" PRId64 "\n", __func__, p_ctx->pts_correction_last_dts); } if (reordered_pts != NI_NOPTS_VALUE) { p_ctx->pts_correction_num_faulty_pts += reordered_pts <= p_ctx->pts_correction_last_pts; p_ctx->pts_correction_last_pts = reordered_pts; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: pts_correction_last_pts %" PRId64 " " "pts_correction_num_faulty_pts %d\n", __func__, p_ctx->pts_correction_last_pts, @@ -1375,14 +1662,14 @@ static int64_t guess_correct_pts(ni_session_context_t* p_ctx, int64_t reordered_ else if (dts != NI_NOPTS_VALUE) { p_ctx->pts_correction_last_pts = dts; - ni_log(NI_LOG_DEBUG, "%s: pts_correction_last_pts %" PRId64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: pts_correction_last_pts %" PRId64 "\n", __func__, p_ctx->pts_correction_last_pts); } if ((p_ctx->pts_correction_num_faulty_pts<=p_ctx->pts_correction_num_faulty_dts || dts == NI_NOPTS_VALUE) && reordered_pts != NI_NOPTS_VALUE) { pts = reordered_pts; - ni_log(NI_LOG_DEBUG, "%s: (reordered_pts) pts %" PRId64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (reordered_pts) pts %" PRId64 "\n", __func__, pts); } else @@ -1396,7 +1683,7 @@ static int64_t guess_correct_pts(ni_session_context_t* p_ctx, int64_t reordered_ pts = reordered_pts; } - ni_log(NI_LOG_DEBUG, "%s: (dts) pts %" PRId64 "\n", __func__, pts); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (dts) pts %" PRId64 "\n", __func__, pts); } return pts; } @@ -1429,14 +1716,14 @@ static int rotated_array_binary_search(uint64_t *lefts, uint64_t *rights, hi = mid - 1; } else { - // Rotation in (lo, mid) + // Rotation in (mid, hi) lo = mid + 1; } } else { - if (rights[mid] < target && target < rights[hi]) + if (rights[mid] <= target && target < rights[hi]) { - // Elements are all monotonous in (lo, mid) + // Elements are all monotonous in (mid, hi) lo = mid + 1; } else { @@ -1461,9 +1748,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) ni_instance_mgr_stream_info_t data = { 0 }; int rx_size = 0; uint64_t frame_offset = 0; - uint16_t yuvW = 0; - uint16_t yuvH = 0; - uint8_t *p_data_buffer; + uint8_t *p_data_buffer = NULL; int i = 0; int is_planar; int retval = NI_RETCODE_SUCCESS; @@ -1471,47 +1756,57 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) int sei_size = 0; uint32_t total_bytes_to_read = 0; uint32_t read_size_bytes = 0; - uint32_t actual_read_size = 0; - int keep_processing = 1; ni_instance_buf_info_t buf_info = { 0 }; + ni_session_statistic_t sessionStatistic = {0}; + ni_xcoder_params_t *p_param; + int query_retry = 0; uint32_t ui32LBA = 0; unsigned int bytes_read_so_far = 0; int query_type = INST_BUF_INFO_RW_READ; -#ifdef MEASURE_LATENCY - uint64_t abs_time_ns; -#endif + int low_delay_notify = 0; + uint32_t frames_dropped = 0; + uint8_t get_first_metadata = 0; + uint8_t sequence_change = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if ((!p_ctx) || (!p_frame)) { - ni_log(NI_LOG_ERROR, "ERROR: passed parameters are null!, return\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: passed parameters are null!, return\n"); return NI_RETCODE_INVALID_PARAM; } + ni_pthread_mutex_lock(&p_ctx->mutex); + +start: if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): xcoder instance id < 0, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): xcoder instance id < 0, return\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; p_data_buffer = (uint8_t *)p_frame->p_buffer; // p_frame->p_data[] can be NULL before actual resolution is returned by // decoder and buffer pool is allocated, so no checking here. total_bytes_to_read = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + metadata_hdr_size; - ni_log(NI_LOG_DEBUG, "Total bytes to read %u, low_delay %u\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Total bytes to read %u, low_delay %u\n", total_bytes_to_read, p_ctx->decoder_low_delay); if (p_ctx->decoder_low_delay > 0 && !p_ctx->ready_to_close) { - ni_log(NI_LOG_DEBUG, "frame_num = %" PRIu64 ", pkt_num = %" PRIu64 "\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "frame_num = %" PRIu64 ", pkt_num = %" PRIu64 "\n", p_ctx->frame_num, p_ctx->pkt_num); - if (p_ctx->frame_num >= p_ctx->pkt_num) + frames_dropped = p_ctx->session_statistic.ui32FramesDropped; + if (p_ctx->force_low_delay && (p_ctx->force_low_delay_cnt < frames_dropped)) { + p_ctx->force_low_delay_cnt = frames_dropped; + } + if (p_ctx->frame_num + p_ctx->force_low_delay_cnt >= p_ctx->pkt_num) { //nothing to query, leave retval = NI_RETCODE_SUCCESS; @@ -1521,35 +1816,60 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) } for (;;) { + query_sleep(p_ctx); + query_retry++; - retval = ni_query_instance_buf_info(p_ctx, query_type, - NI_DEVICE_TYPE_DECODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - ni_log(NI_LOG_DEBUG, "Info query buf_info.size = %u\n", - buf_info.buf_avail_size); + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "65") >= 0) + { + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_DECODER, + &sessionStatistic); + CHECK_ERR_RC(p_ctx, retval, &sessionStatistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + CHECK_VPU_RECOVERY(retval); + + buf_info.buf_avail_size = sessionStatistic.ui32RdBufAvailSize; + } else + { + retval = ni_query_instance_buf_info(p_ctx, query_type, + NI_DEVICE_TYPE_DECODER, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + } + + ni_log2(p_ctx, NI_LOG_TRACE, "Info query buf_info.size = %u\n", + buf_info.buf_avail_size); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_DEBUG, "Warning dec read query fail rc %d retry %d\n", - retval, query_retry); + ni_log2(p_ctx, NI_LOG_TRACE, "Warning: dec read query fail rc %d retry %d max_retry_fail_count %d\n", + retval, query_retry, p_ctx->max_retry_fail_count[1]); - if (query_retry >= 1000) - { - retval = NI_RETCODE_SUCCESS; + if (query_retry >= 1000) + { + p_ctx->max_retry_fail_count[1]++; + low_delay_notify = 1; + retval = (p_ctx->max_retry_fail_count[1] >= NI_XCODER_FAILURES_MAX) ? NI_RETCODE_FAILURE : NI_RETCODE_SUCCESS; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); + } + else if (buf_info.buf_avail_size == DP_IPC_PASSTHRU) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): Bad available buffer size %u\n", __FUNCTION__, buf_info.buf_avail_size); + retval = NI_RETCODE_FAILURE; LRETURN; - } - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); - ni_usleep(100); - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); } else if (buf_info.buf_avail_size == metadata_hdr_size) { - ni_log(NI_LOG_DEBUG, "Info only metadata hdr is available, seq change?\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "Info only metadata hdr is available, seq change?\n"); total_bytes_to_read = metadata_hdr_size; + sequence_change = 1; break; } else if (0 == buf_info.buf_avail_size) @@ -1557,42 +1877,109 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) // query to see if it is eos now, if we have sent it if (p_ctx->ready_to_close) { - ni_log(NI_LOG_DEBUG, "Info dec query, ready_to_close %u, query eos\n", - p_ctx->ready_to_close); - retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + ni_log2(p_ctx, NI_LOG_TRACE, "Info dec query, ready_to_close %u, query eos\n", + p_ctx->ready_to_close); + retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); - if (data.is_flushed) + if (data.is_flushed || + query_retry >= + NI_MAX_DEC_SESSION_READ_QUERY_EOS_RETRIES) // 15000 retries + { + if (query_retry >= + NI_MAX_DEC_SESSION_READ_QUERY_EOS_RETRIES) //15000 retries + { + ni_log2(p_ctx, NI_LOG_ERROR, + "WARNING: Dec eos reached but also exceeded max dec read query " + "retries. is_flushed=%u try=%d.\n", + data.is_flushed, query_retry); + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Dec eos reached. is_flushed=%u try=%d.\n", + data.is_flushed, query_retry); + } + p_frame->end_of_stream = 1; + low_delay_notify = 1; + retval = NI_RETCODE_SUCCESS; + LRETURN; + } else { - ni_log(NI_LOG_DEBUG, "Info eos reached.\n"); - p_frame->end_of_stream = 1; - retval = NI_RETCODE_SUCCESS; - LRETURN; + ni_log2(p_ctx, NI_LOG_TRACE, "Dec read available buf size == 0, query try %d," + " retrying ..\n", query_retry); + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_200US); // 200 us + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; } } - ni_log(NI_LOG_TRACE, "Dec read available buf size == 0. retry=%d, eos=%d" + ni_log2(p_ctx, NI_LOG_TRACE, "Dec read available buf size == 0. retry=%d, eos=%d" "\n", query_retry, p_frame->end_of_stream); - if (NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == p_ctx->status && + if ((NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == p_ctx->status || + (p_ctx->decoder_low_delay > 0 && + ((p_ctx->frame_num + p_ctx->force_low_delay_cnt) + < p_ctx->pkt_num))) && query_retry < 1000 / 2) { + if (p_ctx->decoder_low_delay && p_ctx->force_low_delay) { + if (p_ctx->session_statistic.ui32FramesDropped > frames_dropped) { + // last pkt sent to decoder marked as dropped, no output, + // so just stop query and return + p_ctx->force_low_delay_cnt++; + low_delay_signal(p_ctx); + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + } + ni_pthread_mutex_unlock(&p_ctx->mutex); ni_usleep(25); + ni_pthread_mutex_lock(&p_ctx->mutex); continue; } else { - if(p_ctx->decoder_low_delay>0) + if(p_ctx->decoder_low_delay > 0) + { + if (p_ctx->force_low_delay) { + p_ctx->force_low_delay_cnt++; + low_delay_signal(p_ctx); + } else { + ni_log2(p_ctx, NI_LOG_ERROR, + "Warning: ceased using low delay decoding mode after " + "excessively long decoder read query.\n"); + // Here it should be the last signal to release the send thread + // holding the low delay mutex. + low_delay_signal(p_ctx); + p_ctx->decoder_low_delay = 0; + } + } + + if ((p_param->dec_input_params.min_packets_delay && p_ctx->pkt_delay_cnt)) { - ni_log(NI_LOG_ERROR, "Warning: low_delay mode non sequential input? Disabling LD\n"); - p_ctx->decoder_low_delay = -1; + if(p_ctx->pkt_num >= (p_ctx->frame_num + p_ctx->pkt_delay_cnt + + p_ctx->session_statistic.ui32FramesDropped)) + { + if(query_retry <= 2000) + { + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(25); + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; + } else { + p_ctx->pkt_delay_cnt++; + ni_log2(p_ctx, NI_LOG_ERROR, + "Warning: decoder pkt_num %u frame_num %u " + "timeout, increaing pkt_delay_cnt to %u\n", + p_ctx->pkt_num, p_ctx->frame_num, + p_ctx->pkt_delay_cnt); + } + } } - ni_log(NI_LOG_DEBUG, "Warning: dec read failed %d retries. rc=%d; eos=%d\n", + + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning: dec read failed %d retries. rc=%d; eos=%d\n", query_retry, p_ctx->status, p_frame->end_of_stream); - - ni_log(NI_LOG_DEBUG, "Warning: dec read query failed %d retries. rc=%d" - "\n", query_retry, retval); } retval = NI_RETCODE_SUCCESS; LRETURN; @@ -1603,25 +1990,28 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) // reorder delay otherwise wait for more packets to be sent to decoder. ni_timestamp_table_t *p_dts_queue = p_ctx->dts_queue; if ((int)p_dts_queue->list.count < p_ctx->pic_reorder_delay + 1 && - !p_ctx->ready_to_close) + !p_ctx->ready_to_close && + NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL != p_ctx->status) { retval = NI_RETCODE_SUCCESS; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "At least %d packets should be sent before reading the " "first frame!\n", p_ctx->pic_reorder_delay + 1); LRETURN; } + p_ctx->max_retry_fail_count[1] = 0; + // get actual YUV transfer size if this is the stream's very first read if (0 == p_ctx->active_video_width || 0 == p_ctx->active_video_height) { retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); - ni_log(NI_LOG_DEBUG, "Info dec YUV query, pic size %ux%u xfer frame size " + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec YUV query, pic size %ux%u xfer frame size " "%ux%u frame-rate %u is_flushed %u\n", data.picture_width, data.picture_height, data.transfer_frame_stride, data.transfer_frame_height, @@ -1635,8 +2025,9 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_ctx->bit_depth_factor = ni_get_bitdepth_factor_from_pixfmt(p_ctx->pixel_format); //p_ctx->bit_depth_factor = data.transfer_frame_stride / data.picture_width; p_ctx->is_first_frame = 1; + p_ctx->pixel_format_changed = 0; - ni_log(NI_LOG_DEBUG, "Info dec YUV, adjust frame size from %ux%u to " + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec YUV, adjust frame size from %ux%u to " "%ux%u format = %d\n", p_frame->video_width, p_frame->video_height, p_ctx->active_video_width, p_ctx->active_video_height, p_ctx->pixel_format); @@ -1649,17 +2040,20 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_ctx->codec_format == NI_CODEC_FORMAT_H264, p_ctx->bit_depth_factor)) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Cannot allocate fme buf pool.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Cannot allocate fme buf pool.\n", __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; + + ni_pthread_mutex_unlock(&p_ctx->mutex); ni_decoder_session_close(p_ctx, 0); #ifdef XCODER_SELF_KILL_ERR // if need to terminate at such occasion when continuing is not // possible, trigger a codec closure - ni_log(NI_LOG_ERROR, "Terminating due to unable to allocate fme buf " + ni_log2(p_ctx, NI_LOG_ERROR, "Terminating due to unable to allocate fme buf " "pool.\n"); kill(getpid(), SIGTERM); #endif + ni_pthread_mutex_lock(&p_ctx->mutex); LRETURN; } @@ -1678,7 +2072,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_data_buffer = (uint8_t*) p_frame->p_buffer; // make sure we don't read more than available - ni_log(NI_LOG_DEBUG, "Info dec buf size: %u YUV frame + meta-hdr size: %u " + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec buf size: %u YUV frame + meta-hdr size: %u " "available: %u\n", p_frame->buffer_size, total_bytes_to_read, buf_info.buf_avail_size); } @@ -1686,7 +2080,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) } } - ni_log(NI_LOG_DEBUG, "total_bytes_to_read %u max_nvme_io_size %u ylen %u cr len " + ni_log2(p_ctx, NI_LOG_DEBUG, "total_bytes_to_read %u max_nvme_io_size %u ylen %u cr len " "%u cb len %u hdr %d\n", total_bytes_to_read, p_ctx->max_nvme_io_size, p_frame->data_len[0], p_frame->data_len[1], @@ -1694,13 +2088,38 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) if (buf_info.buf_avail_size < total_bytes_to_read) { - ni_log(NI_LOG_ERROR, + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s() avaliable size(%u)" "less than needed (%u)\n", __func__, buf_info.buf_avail_size, total_bytes_to_read); abort(); } + if (buf_info.buf_avail_size == metadata_hdr_size && !p_ctx->frame_num) + { + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rE") >= 0) + { + // allocate p_data_buffer to read the first metadata + void *p_metadata_buffer = NULL; + int buffer_size = ((metadata_hdr_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / + NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + if (ni_posix_memalign(&p_metadata_buffer, sysconf(_SC_PAGESIZE), buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %d: %s() Cannot allocate metadata buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + p_data_buffer = (uint8_t *)p_metadata_buffer; + get_first_metadata = 1; + sequence_change = 0; + } + } + read_size_bytes = buf_info.buf_avail_size; ui32LBA = READ_INSTANCE_R(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); if (read_size_bytes % NI_MEM_PAGE_ALIGNMENT) @@ -1712,18 +2131,29 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_data_buffer, read_size_bytes, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_read, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (retval < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; - } else - { - // command issued successfully, now exit + } else if (get_first_metadata) { + // got first metadata alone ni_metadata_dec_frame_t *p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_data_buffer); + ni_log2(p_ctx, NI_LOG_DEBUG, "Got first pkt_delay_cnt %u\n", + p_meta->metadata_common.pkt_delay_cnt); + if (p_ctx->pkt_delay_cnt < p_meta->metadata_common.pkt_delay_cnt) + p_ctx->pkt_delay_cnt = p_meta->metadata_common.pkt_delay_cnt; + get_first_metadata = 0; + ni_aligned_free(p_data_buffer); + goto start; + } else { + // command issued successfully, now exit + ni_metadata_dec_frame_t *p_meta; + p_meta = (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer + p_frame->data_len[0] + p_frame->data_len[1] + @@ -1731,10 +2161,21 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) if (buf_info.buf_avail_size != metadata_hdr_size) { + low_delay_notify = 1; sei_size = p_meta->sei_size; + } else if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rE") >= 0) + { + p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer); + ni_log2(p_ctx, NI_LOG_DEBUG, "Got pkt_delay_cnt %u\n", + p_meta->metadata_common.pkt_delay_cnt); + if (p_ctx->pkt_delay_cnt < p_meta->metadata_common.pkt_delay_cnt) + p_ctx->pkt_delay_cnt = p_meta->metadata_common.pkt_delay_cnt; } total_bytes_to_read = total_bytes_to_read + sei_size; - ni_log(NI_LOG_DEBUG, "decoder read success, size %d total_bytes_to_read " + ni_log2(p_ctx, NI_LOG_DEBUG, "decoder read success, size %d total_bytes_to_read " "include sei %u sei_size %d\n", retval, total_bytes_to_read, sei_size); } @@ -1745,10 +2186,28 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) rx_size = ni_create_frame(p_frame, bytes_read_so_far, &frame_offset, false); p_ctx->frame_pkt_offset = frame_offset; + if (p_ctx->decoder_low_delay > 0 && buf_info.buf_avail_size == metadata_hdr_size && + p_ctx->enable_low_delay_check) + { + ni_log2(p_ctx, NI_LOG_TRACE, "Low delay mode amd check header if has b frame\n"); + + ni_metadata_dec_frame_t *p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer + + p_frame->data_len[0] + + p_frame->data_len[1] + + p_frame->data_len[2]); + if (p_meta->metadata_common.has_b_frame == 1) + { + ni_log2(p_ctx, NI_LOG_ERROR,"Warning: session 0x%x decoder lowDelay mode " + "is cancelled due to has_b_frames, frame_num %u\n", + p_ctx->session_id, p_ctx->frame_num); + p_ctx->decoder_low_delay = 0; + } + } if (rx_size > 0) { - ni_log(NI_LOG_DEBUG, "%s(): s-state %d first_frame %d\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): s-state %d first_frame %d\n", __func__, p_ctx->session_run_state, p_ctx->is_first_frame); if (ni_timestamp_get_with_threshold( p_ctx->dts_queue, 0, (int64_t *)&p_frame->dts, @@ -1759,7 +2218,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) { p_ctx->pic_reorder_delay++; p_frame->dts = p_ctx->last_dts + p_ctx->last_dts_interval; - ni_log(NI_LOG_DEBUG, "Padding DTS: %" PRId64 "\n", p_frame->dts); + ni_log2(p_ctx, NI_LOG_DEBUG, "Padding DTS: %" PRId64 "\n", p_frame->dts); } else { p_frame->dts = NI_NOPTS_VALUE; @@ -1794,12 +2253,24 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) // Reset for DTS padding counting p_ctx->pic_reorder_delay = 0; } - - if (p_ctx->is_dec_pkt_512_aligned) + if (p_ctx->codec_format == NI_CODEC_FORMAT_JPEG)//fw won't save frameoffset when decoding jpeg. + { + if (p_ctx->is_first_frame) + { + p_ctx->is_first_frame = 0; + } + p_frame->pts = p_ctx->pts_offsets[p_ctx->frame_num % NI_FIFO_SZ]; + p_frame->flags = p_ctx->flags_array[p_ctx->frame_num % NI_FIFO_SZ]; + p_frame->pkt_pos = p_ctx->pkt_pos[p_ctx->frame_num % NI_FIFO_SZ]; + ni_log2(p_ctx, NI_LOG_DEBUG, "p_frame->pts = %u, frame_num = %d, p_frame->dts = %u\n", + p_frame->pts, p_ctx->frame_num, p_frame->dts); + } + else if (p_ctx->is_dec_pkt_512_aligned) { if (p_ctx->is_first_frame) { p_ctx->is_first_frame = 0; + p_frame->pkt_pos = p_ctx->pkt_pos[0]; if (p_frame->dts == NI_NOPTS_VALUE) { @@ -1814,7 +2285,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_frame->data_len[2] + p_frame->data_len[3]); uint64_t num_fw_pkts = p_metadata->metadata_common.ui64_data.frame_offset / 512; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: num_fw_pkts %" PRIu64 " frame_offset %" PRIu64 "\n", __func__, num_fw_pkts, p_metadata->metadata_common.ui64_data.frame_offset); @@ -1823,17 +2294,17 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) bool bFound = (num_fw_pkts >= cumul); while (cumul < num_fw_pkts) // look for pts index { - ni_log(NI_LOG_DEBUG, "%s: cumul %" PRIu64 "\n", __func__, cumul); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: cumul %" PRIu64 "\n", __func__, cumul); if (idx == NI_MAX_DEC_REJECT) { - ni_log(NI_LOG_ERROR, "Invalid index computation > " + ni_log2(p_ctx, NI_LOG_ERROR, "Invalid index computation > " "NI_MAX_DEC_REJECT!\n"); break; } else { idx++; cumul += p_ctx->pkt_offsets_index[idx]; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: idx %d " "pkt_offsets_index[idx] %" PRIu64 "\n", __func__, idx, p_ctx->pkt_offsets_index[idx]); @@ -1844,9 +2315,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) { p_frame->pts = p_ctx->pts_offsets[idx]; p_frame->flags = p_ctx->flags_array[idx]; - p_ctx->last_pts = p_frame->pts; - p_ctx->last_dts = p_frame->dts; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (first frame) idx %d last_dts %" PRId64 "" "dts %" PRId64 " last_pts %" PRId64 " pts %" PRId64 "\n", __func__, idx, p_ctx->last_dts, p_frame->dts, @@ -1854,20 +2323,18 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) } else if ((idx != NI_MAX_DEC_REJECT) && (p_ctx->session_run_state == SESSION_RUN_STATE_RESETTING)) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): session %u recovering and " "adjusting ts.\n", __func__, p_ctx->session_id); p_frame->pts = p_ctx->pts_offsets[idx]; p_frame->flags = p_ctx->flags_array[idx]; - p_ctx->last_pts = p_frame->pts; - p_ctx->last_dts = p_frame->dts; p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; } else // use pts = 0 as offset { p_frame->pts = 0; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (zero default) dts %" PRId64 " pts " "%" PRId64 "\n", __func__, p_frame->dts, p_frame->pts); @@ -1876,7 +2343,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) else { p_frame->pts = 0; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (not bitstream) dts %" PRId64 " pts " "%" PRId64 "\n", __func__, p_frame->dts, p_frame->pts); @@ -1886,8 +2353,9 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) { int64_t pts_delta = p_frame->dts - p_ctx->last_dts; p_frame->pts = p_ctx->last_pts + pts_delta; + p_frame->pkt_pos = p_ctx->last_pkt_pos + (frame_offset - p_ctx->last_frame_offset); - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (!is_first_frame idx) last_dts %" PRId64 "" "dts %" PRId64 " pts_delta %" PRId64 " last_pts " "%" PRId64 " pts %" PRId64 "\n", @@ -1897,7 +2365,7 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) } else { - ni_log(NI_LOG_DEBUG, "%s: frame_offset %" PRIu64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: frame_offset %" PRIu64 "\n", __func__, frame_offset); if (p_ctx->is_first_frame) { @@ -1913,37 +2381,53 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) { p_frame->pts = p_ctx->pts_offsets[i]; p_frame->flags = p_ctx->flags_array[i]; - p_ctx->last_pts = p_frame->pts; - p_ctx->last_dts = p_frame->dts; - ni_log(NI_LOG_DEBUG, + p_frame->pkt_pos = p_ctx->pkt_pos[i]; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (found pts) dts %" PRId64 " pts " "%" PRId64 " frame_offset %" PRIu64 " i %d " "pkt_offsets_index_min %" PRIu64 " pkt_offsets_index " - "%" PRIu64 "\n", + "%" PRIu64 " pkt_pos %" PRIu64 " \n", __func__, p_frame->dts, p_frame->pts, frame_offset, i, p_ctx->pkt_offsets_index_min[i], - p_ctx->pkt_offsets_index[i]); + p_ctx->pkt_offsets_index[i], + p_ctx->pkt_pos[i]); p_frame->p_custom_sei_set = p_ctx->pkt_custom_sei_set[i]; p_ctx->pkt_custom_sei_set[i] = NULL; } else { - //backup solution pts - p_frame->pts = p_ctx->last_pts + (p_frame->dts - p_ctx->last_dts); - ni_log(NI_LOG_ERROR, - "ERROR: NO pts found consider increasing NI_FIFO_SZ!\n"); - ni_log(NI_LOG_DEBUG, + // backup solution pts + if (p_param->dec_input_params.skip_pts_guess && p_ctx->last_pts != NI_NOPTS_VALUE) + { + // if skip guess_correct_pts, use pts interval to get the correct pts + p_frame->pts = p_ctx->last_pts + (p_ctx->last_pts_interval > 0 ? p_ctx->last_pts_interval : 1); + } + else + { + p_frame->pts = p_ctx->last_pts + (p_frame->dts - p_ctx->last_dts); + } + p_frame->pkt_pos = p_ctx->last_pkt_pos + (frame_offset - p_ctx->last_frame_offset); + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: Frame pts %" PRId64 " not found for offset " + "%" PRIu64 "\n", p_frame->pts, frame_offset); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (not found use default) dts %" PRId64 " pts %" PRId64 "\n", __func__, p_frame->dts, p_frame->pts); } } - p_frame->pts = guess_correct_pts(p_ctx, p_frame->pts, p_frame->dts); + p_frame->orignal_pts = p_frame->pts; + p_ctx->last_pkt_pos = p_frame->pkt_pos; + p_ctx->last_frame_offset = frame_offset; + if (!p_param->dec_input_params.skip_pts_guess) + p_frame->pts = guess_correct_pts(p_ctx, p_frame->pts, p_frame->dts); + if (p_frame->pts != NI_NOPTS_VALUE && p_ctx->last_pts != NI_NOPTS_VALUE) + p_ctx->last_pts_interval = p_frame->pts - p_ctx->last_pts; p_ctx->last_pts = p_frame->pts; if (p_frame->dts != NI_NOPTS_VALUE && p_ctx->last_dts != NI_NOPTS_VALUE) p_ctx->last_dts_interval = p_frame->dts - p_ctx->last_dts; p_ctx->last_dts = p_frame->dts; - ni_log(NI_LOG_DEBUG, "%s: (best_effort_timestamp) pts %" PRId64 "\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (best_effort_timestamp) pts %" PRId64 "\n", __func__, p_frame->pts); p_ctx->frame_num++; @@ -1960,19 +2444,19 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) #endif } - ni_log(NI_LOG_DEBUG, "%s(): received data: [0x%08x]\n", __func__, rx_size); - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): received data: [0x%08x]\n", __func__, rx_size); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_frame->start_of_stream=%u, " "p_frame->end_of_stream=%u, p_frame->video_width=%u, " "p_frame->video_height=%u\n", __func__, p_frame->start_of_stream, p_frame->end_of_stream, p_frame->video_width, p_frame->video_height); - ni_log(NI_LOG_DEBUG, "%s(): p_frame->data_len[0/1/2]=%u/%u/%u\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_frame->data_len[0/1/2]=%u/%u/%u\n", __func__, p_frame->data_len[0], p_frame->data_len[1], p_frame->data_len[2]); if (p_ctx->frame_num % 500 == 0) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Decoder pts queue size = %u dts queue size = %u\n\n", p_ctx->pts_table->list.count, p_ctx->dts_queue->list.count); // scan and clean up @@ -1983,24 +2467,46 @@ int ni_decoder_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame) #ifdef MEASURE_LATENCY if ((p_frame->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) { - abs_time_ns = ni_gettime_ns(); - ni_log(NI_LOG_INFO, "DTS:%lld,DELTA:%lu,dLAT:%lu;\n", p_frame->dts, - abs_time_ns - p_ctx->prev_read_frame_time, - ni_lat_meas_q_check_latency((ni_lat_meas_q_t *)p_ctx->frame_time_q, - abs_time_ns, p_frame->dts)); - p_ctx->prev_read_frame_time = abs_time_ns; + uint64_t abs_time_ns = ni_gettime_ns(); + ni_lat_meas_q_t *q = (ni_lat_meas_q_t *)p_ctx->frame_time_q; + ni_log2(p_ctx, NI_LOG_INFO, "DTS:%" PRId64 ",DELTA:%" PRId64 ",dLAT:%" PRIu64 ";\n", + p_frame->dts, abs_time_ns - q->last_benchmark_time, + ni_lat_meas_q_check_latency(q, abs_time_ns, p_frame->dts)); + q->last_benchmark_time = abs_time_ns; } #endif END: + ni_pthread_mutex_unlock(&p_ctx->mutex); + + if (get_first_metadata && p_data_buffer) + ni_aligned_free(p_data_buffer); + if (sequence_change && p_ctx->frame_num) + { + if (p_ctx->actual_video_width == p_frame->video_width && + p_ctx->active_video_height == p_frame->video_height) + { + p_ctx->pixel_format_changed = 1; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): format changed\n", __func__); + } + } + if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "%s(): bad exit, retval = %d\n", __func__, retval); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): bad exit, retval = %d\n", __func__, retval); + if (retval == NI_RETCODE_ERROR_VPU_RECOVERY) + { + low_delay_signal(p_ctx); + } return retval; } else { - ni_log(NI_LOG_TRACE, "%s(): exit, rx_size = %d\n", __func__, rx_size); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit, rx_size = %d\n", __func__, rx_size); + if (low_delay_notify) + { + low_delay_signal(p_ctx); + } return rx_size; } } @@ -2018,47 +2524,111 @@ int ni_xcoder_session_query(ni_session_context_t *p_ctx, ni_instance_mgr_general_status_t data; int retval = NI_RETCODE_SUCCESS; - ni_log(NI_LOG_TRACE, "%s(): device_type %d:%s; enter\n", __func__, - device_type, device_type_str[device_type]); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): device_type %d:%s; enter\n", __func__, + device_type, g_device_type_str[device_type]); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } -#if 1 retval = ni_query_general_status(p_ctx, device_type, &data); -#else - ni_log(NI_LOG_DEBUG, "%s(): query skipped\n", __func__); -#endif if (NI_RETCODE_SUCCESS == retval) { - p_ctx->load_query.current_load = (uint32_t)data.process_load_percent; + p_ctx->overall_load_query.overall_current_load = (uint32_t)data.process_load_percent_overall; + p_ctx->overall_load_query.overall_fw_model_load = data.fw_model_load_overall; + p_ctx->overall_load_query.overall_instance_count = (uint32_t) data.active_sub_instances_cnt_overall; + p_ctx->overall_load_query.admin_queried = (uint32_t)data.admin_nsid; + p_ctx->load_query.current_load = + (uint32_t)data.process_load_percent | (uint32_t)(data.process_load_percent_upper << 8); p_ctx->load_query.fw_model_load = (uint32_t)data.fw_model_load; + p_ctx->load_query.fw_load = (uint32_t)data.fw_load; + switch (device_type) + { + case NI_DEVICE_TYPE_DECODER: + case NI_DEVICE_TYPE_ENCODER: + case NI_DEVICE_TYPE_UPLOAD: + if (p_ctx->load_query.fw_load == 1 && + 0 == p_ctx->overall_load_query.overall_instance_count) + { + // ignore negligible non-video traffic + p_ctx->load_query.fw_load -= 1; + } + break; + default: + break; + } p_ctx->load_query.total_contexts = (uint32_t)data.active_sub_instances_cnt; p_ctx->load_query.fw_video_mem_usage = (uint32_t)data.fw_video_mem_usage; + p_ctx->load_query.fw_video_shared_mem_usage = (uint32_t)data.fw_video_shared_mem_usage; p_ctx->load_query.fw_share_mem_usage = (uint32_t)data.fw_share_mem_usage; p_ctx->load_query.fw_p2p_mem_usage = (uint32_t)data.fw_p2p_mem_usage; p_ctx->load_query.active_hwuploaders = (uint32_t)data.active_hwupload_sub_inst_cnt; - ni_log(NI_LOG_DEBUG, "%s current_load:%u fw_model_load:%u " + ni_log2(p_ctx, NI_LOG_DEBUG, "%s blk_dev %s blk_xcoder %s dev_xcoder %s current_load:%u model_load:%u fw_load:%u " "total_contexts:%u fw_video_mem_usage:%u " - "fw_share_mem_usage:%u fw_p2p_mem_usage:%u " - "active_hwuploaders:%u\n", __func__, - p_ctx->load_query.current_load, p_ctx->load_query.fw_model_load, + "fw_video_shared_mem_usage:%u fw_share_mem_usage:%u " + "fw_p2p_mem_usage:%u active_hwuploaders:%u\n", __func__, + p_ctx->blk_dev_name, + p_ctx->blk_xcoder_name, + p_ctx->dev_xcoder_name, + p_ctx->load_query.current_load, + p_ctx->load_query.fw_model_load, + p_ctx->load_query.fw_load, p_ctx->load_query.total_contexts, p_ctx->load_query.fw_video_mem_usage, + p_ctx->load_query.fw_video_shared_mem_usage, p_ctx->load_query.fw_share_mem_usage, p_ctx->load_query.fw_p2p_mem_usage, p_ctx->load_query.active_hwuploaders); + if (p_ctx->overall_load_query.admin_queried) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Overall load %u, model load %u, instance count %u\n", + p_ctx->overall_load_query.overall_current_load, + p_ctx->overall_load_query.overall_fw_model_load, + p_ctx->overall_load_query.overall_instance_count); + } } END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} + +/*!****************************************************************************** + * \brief Query current xcoder status + * + * \param + * + * \return + *******************************************************************************/ +int ni_xcoder_session_query_detail(ni_session_context_t *p_ctx, + ni_device_type_t device_type, void *detail_data, int ver) +{ + int retval = NI_RETCODE_SUCCESS; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): device_type %d:%s; enter\n", __func__, + device_type, g_device_type_str[device_type]); + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + retval = ni_query_detail_status(p_ctx, device_type, detail_data, ver); + +END: + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -2074,36 +2644,62 @@ int ni_xcoder_session_query(ni_session_context_t *p_ctx, ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) { ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t buffer_size = 0; ni_xcoder_params_t *p_param; void *p_buffer = NULL; ni_instance_buf_info_t buf_info = {0}; uint32_t ui32LBA = 0; uint32_t max_cu_size; uint32_t block_size; + int32_t width, height; + int m_threshold = 0; + char fmt_fw_api_ver1[5], fmt_fw_api_ver2[5]; if (!p_ctx || !p_ctx->p_session_config) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } - + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; - ni_log(NI_LOG_TRACE, "%s(): enter hwframes = %d\n", __func__, + bool isrgba = (p_ctx->pixel_format == NI_PIX_FMT_ABGR || p_ctx->pixel_format == NI_PIX_FMT_ARGB + || p_ctx->pixel_format == NI_PIX_FMT_RGBA || p_ctx->pixel_format == NI_PIX_FMT_BGRA); + if (isrgba) + { + if (p_param->source_width > NI_MAX_RESOLUTION_RGBA_WIDTH || p_param->source_height > NI_MAX_RESOLUTION_RGBA_HEIGHT + || p_param->source_width < NI_MIN_WIDTH || p_param->source_height < NI_MIN_HEIGHT) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() RGBA / BGRA / ARGB / AGBR resolution invalid, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + } + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter hwframes = %d\n", __func__, p_param->hwframes); // calculate encoder ROI map size: each QP info takes 8-bit, represent 8 x 8 // pixel block max_cu_size = (NI_CODEC_FORMAT_H264 == p_ctx->codec_format) ? 16 : 64; + + width = p_param->source_width; + height = p_param->source_height; + // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation + if (NI_CODEC_FORMAT_AV1 == p_ctx->codec_format) + { + width = (width / 8) * 8; + height = (height / 8) * 8; + } + block_size = - ((p_param->source_width + max_cu_size - 1) & (~(max_cu_size - 1))) * - ((p_param->source_height + max_cu_size - 1) & (~(max_cu_size - 1))) / + ((width + max_cu_size - 1) & (~(max_cu_size - 1))) * + ((height + max_cu_size - 1) & (~(max_cu_size - 1))) / (8 * 8); p_ctx->roi_len = ((block_size + 63) & (~63)); // align to 64 bytes - ni_log(NI_LOG_DEBUG, "%s(): finish init\n", __func__); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): finish init\n", __func__); //Check if there is an instance or we need a new one if (NI_INVALID_SESSION_ID == p_ctx->session_id) @@ -2117,27 +2713,31 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) p_ctx->keyframe_factor = 1; p_ctx->frame_num = 0; p_ctx->pkt_num = 0; + p_ctx->av1_pkt_num = 0; p_ctx->rc_error_count = 0; p_ctx->force_frame_type = 0; p_ctx->ready_to_close = 0; p_ctx->auto_dl_handle = 0; - //Sequence change tracking reated stuff + //Sequence change tracking related stuff p_ctx->active_video_width = 0; p_ctx->active_video_height = 0; p_ctx->p_all_zero_buf = NULL; p_ctx->actual_video_width = 0; p_ctx->enc_pts_w_idx = 0; p_ctx->enc_pts_r_idx = 0; - p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; p_ctx->session_timestamp = 0; memset(p_ctx->pkt_custom_sei_set, 0, NI_FIFO_SZ * sizeof(ni_custom_sei_set_t *)); memset(&(p_ctx->param_err_msg[0]), 0, sizeof(p_ctx->param_err_msg)); + if (p_ctx->session_run_state != SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) + { + p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; + } //malloc zero data buffer if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -2147,8 +2747,8 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) //malloc data buffer if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", - __func__, NI_ERRNO); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + NI_ERRNO, __func__); ni_aligned_free(p_ctx->p_all_zero_buf); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -2169,11 +2769,12 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) //Otherwise the invalid session id set before the open command will stay p_ctx->session_id = ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); - p_ctx->session_timestamp = - ni_htonll(((ni_session_stats_t *)p_buffer)->ui64Session_timestamp); + p_ctx->session_timestamp = ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_high); + p_ctx->session_timestamp = (p_ctx->session_timestamp << 32) | + ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_low); if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): p_ctx->device_handle=%" PRIx64 ", " "p_ctx->hw_id=%d, p_ctx->session_id=%d\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, @@ -2182,7 +2783,7 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - ni_log(NI_LOG_DEBUG, "Encoder open session ID:0x%x timestamp:%" PRIu64 "\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Encoder open session ID:0x%x timestamp:%" PRIu64 "\n", p_ctx->session_id, p_ctx->session_timestamp); //Send keep alive timeout Info @@ -2190,18 +2791,18 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) p_ctx->keep_alive_timeout * 1000000; //send us to FW memset(p_buffer, 0, NI_DATA_BUFFER_LEN); memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); - ni_log(NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, keep_alive_timeout); ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme write keep_alive_timeout command " "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); @@ -2209,27 +2810,27 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) LRETURN; } - // Send SW version to FW if FW version is higher than major 6 minor 1 - if (is_fw_rev_higher(p_ctx, (uint8_t)'6', (uint8_t)'1')) + // Send SW version to FW if FW API version is >= 6.2 + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "62") >= 0) { // Send SW version to session manager memset(p_buffer, 0, NI_DATA_BUFFER_LEN); memcpy(p_buffer, NI_XCODER_REVISION, sizeof(uint64_t)); - ni_log(NI_LOG_DEBUG, "%s sw_version major %c minor %c fw_rev major %c minor %c\n", __func__, - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX]); + ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &fmt_fw_api_ver1[0]); + ni_fmt_fw_api_ver_str((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &fmt_fw_api_ver2[0]); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s libxcoder FW API ver %s, FW FW API ver %s\n", + __func__, fmt_fw_api_ver1, fmt_fw_api_ver2); ui32LBA = CONFIG_SESSION_SWVersion_W(p_ctx->session_id); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme write sw_version command " "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); @@ -2237,39 +2838,159 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) LRETURN; } - // For FW rev 61 or newer, initialize with the most current size - p_ctx->meta_size = sizeof(ni_metadata_enc_bstream_t); + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6p") >= 0) + // For FW API ver 6.p or newer, initialize with the most current size + p_ctx->meta_size = sizeof(ni_metadata_enc_bstream_t); + else + // For FW API ver 6.2 or newer, initialize with the most current size + p_ctx->meta_size = NI_FW_ENC_BITSTREAM_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_o; } else { - // For FW rev 60 or older, initialize with metadata size 32 + // For FW API ver 6.1 or older, initialize with metadata size 32 p_ctx->meta_size = NI_FW_ENC_BITSTREAM_META_DATA_SIZE; } - ni_log(NI_LOG_DEBUG, "Open session completed\n"); + // Open AI session for AI Enhance + if(p_param->enable_ai_enhance) + { + // Check if the bit depth & resoultion + if((p_ctx->bit_depth_factor != 1) || + ((p_param->source_width != 1280 && p_param->source_height != 720) && + (p_param->source_width != 1920 && p_param->source_height != 1080) && + (p_param->source_width != 3840 && p_param->source_height != 2160) && + (p_param->source_width != 720 && p_param->source_height != 1280) && + (p_param->source_width != 768 && p_param->source_height != 1280) && + (p_param->source_width != 1080 && p_param->source_height != 1920) && + (p_param->source_width != 2496 && p_param->source_height != 1080))) + { + p_param->enable_ai_enhance = 0; + ni_log2(p_ctx, NI_LOG_ERROR, "Resoultion=%dx%d,depth=%d\n",p_param->source_width,p_param->source_height,p_ctx->bit_depth_factor); + ni_log2(p_ctx, NI_LOG_ERROR, "The bit depth or resoultion is not supported on ai enhance mode\n"); + }else{ + ni_log2(p_ctx, NI_LOG_DEBUG, "Adding ai enhance session to encoder\n"); + ui32LBA = OPEN_ADD_CODEC(NI_DEVICE_TYPE_AI, 0, ni_htons(p_ctx->session_id)); + retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); + + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_open, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR couldn't add ai to encoder session\n"); + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): p_ctx->device_handle=%" PRIx64 ", " + "p_ctx->hw_id=%d, p_ctx->session_id=%d\n", + __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, + p_ctx->session_id); + ni_encoder_session_close(p_ctx, 0); + LRETURN; + } + } + } + + if (p_param->ddr_priority_mode > NI_DDR_PRIORITY_NONE) + { + retval = ni_device_set_ddr_configuration(p_ctx, p_param->ddr_priority_mode); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): ddr priority setting failure for %s\n", + __func__, strerror(NI_ERRNO)); + LRETURN; + } + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "Open session completed\n"); } - if (p_ctx->hw_action == NI_CODEC_HW_ENABLE) + /* Modify mmap_threshold and trim_threshold of malloc */ + // calculate the default threshold which equals to the resolution + padding size. + // 64 is AV_INPUT_BUFFER_PADDING_SIZE + m_threshold = p_param->source_width * p_param->source_height * 3 / 2 * + p_ctx->bit_depth_factor + 64; + m_threshold = ((m_threshold + (NI_MEM_PAGE_ALIGNMENT - 1)) / + NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + // The upper limit is DEFAULT_MMAP_THRESHOLD_MAX: 512*1024 on 32-bit systems, + // or 4*1024*1024*sizeof(long) on 64-bit systems. + // This macro is not defined in header file. + // So, assume that is running on 64-bit systems + if (m_threshold > 4 * 1024 * 1024 * sizeof(long)) { - ni_device_capability_t sender_cap, receiver_cap; + ni_log2(p_ctx, NI_LOG_INFO, "Warning: m_threshold (%d) is bigger than " + "DEFAULT_MMAP_THRESHOLD_MAX, use default value (%d)\n", + m_threshold, 4 * 1024 * 1024 * sizeof(long)); + m_threshold = 4 * 1024 * 1024 * sizeof(long); + } - retval = ni_device_capability_query(p_ctx->sender_handle, &sender_cap); - if (retval != NI_RETCODE_SUCCESS) + if (p_param->staticMmapThreshold) // Set Static Mmap Threshold + { +#if defined(__linux__) && !defined(_ANDROID) + // If the malloc buffer is larger than the threshold, + // glibc will use mmap to malloc the memory, which is a low speed method. + // So, set the M_MMAP_THRESHOLD >= 1 yuv buffer size here. + if (mallopt(M_MMAP_THRESHOLD, m_threshold) == 0) { - ni_log(NI_LOG_ERROR, "ERROR: ni_device_capability_query returned %d\n", - retval); + ni_log2(p_ctx, NI_LOG_ERROR, "Error: could not set M_MMAP_THRESHOLD to %d\n", + m_threshold); + retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } - retval = ni_device_capability_query(p_ctx->blk_io_handle, &receiver_cap); + // When the amount of contiguous free memory at the top of the heap + // grows larger than M_TRIM_THRESHOLD, + // free(3) employs sbrk(2) to release this memory back to the system. + // So, set the M_TRIM_THRESHOLD to 3*m_threshold, + // to avoid an inefficient case, frequently releasing and requesting physical memory. + if (mallopt(M_TRIM_THRESHOLD, 3 * m_threshold) == 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Error: could not set M_TRIM_THRESHOLD to %ds\n", + 3 * m_threshold); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } +#else + ni_log2(p_ctx, NI_LOG_INFO, + "Warning: this platform does not support staticMmapThreshold\n"); +#endif + } + else // default + { + // a way to dynamically trigger a pre-mature increase in mmap&trim threshold + // make the mmap_threshold larger than frame size to avoid frequent page faults + m_threshold = (int) (m_threshold * 1.25); // An experience value + void *temp_buf = malloc((size_t) m_threshold); + ni_log2(p_ctx, NI_LOG_TRACE, "trigger a pre-mature increase in mmap&trim threshold: 0x%p = malloc(%d)\n", + temp_buf, m_threshold); + free(temp_buf); + } + if (p_ctx->hw_action == NI_CODEC_HW_ENABLE) + { + ni_device_capability_t sender_cap, receiver_cap; + g_device_in_ctxt = true; + ni_device_handle_t temp = g_dev_handle; + g_dev_handle = p_ctx->sender_handle; + retval = ni_device_capability_query(p_ctx->sender_handle, &sender_cap); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR: ni_device_capability_query returned %d\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_device_capability_query returned %d\n", retval); LRETURN; } + g_dev_handle = p_ctx->blk_io_handle; + retval = ni_device_capability_query(p_ctx->blk_io_handle, &receiver_cap); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_device_capability_query returned %d\n", + retval); + LRETURN; + } + g_dev_handle = temp; + g_device_in_ctxt = false; //cleanup for (uint8_t ui8Index = 0; ui8Index < 20; ui8Index++) { if (sender_cap.serial_number[ui8Index] != @@ -2277,22 +2998,70 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) { // QDFW-315 Autodownload p_ctx->auto_dl_handle = p_ctx->sender_handle; - ni_log(NI_LOG_DEBUG, "Autodownload device handle set %p!\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Autodownload device handle set %p!\n", p_ctx->auto_dl_handle); p_ctx->hw_action = NI_CODEC_HW_NONE; break; } + else + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6m") >= 0) + { + ni_device_vf_ns_id_t sender_vf_ns_id = {0}; + ni_device_vf_ns_id_t curr_vf_ns_id = {0}; + retval = ni_query_vf_ns_id(p_ctx->sender_handle, &sender_vf_ns_id, p_ctx->fw_rev); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: calling ni_query_vf_ns_id(): " + "p_ctx->sender_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%u\n", + (int64_t)p_ctx->sender_handle, p_ctx->hw_id, p_ctx->session_id); + ni_encoder_session_close(p_ctx, 0); + LRETURN; + } + retval = ni_query_vf_ns_id(p_ctx->blk_io_handle, &curr_vf_ns_id, p_ctx->fw_rev); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: calling ni_query_vf_ns_id(): " + "p_ctx->blk_io_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%u\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_encoder_session_close(p_ctx, 0); + LRETURN; + } + + if ((sender_vf_ns_id.ns_id != curr_vf_ns_id.ns_id) || + (sender_vf_ns_id.vf_id != curr_vf_ns_id.vf_id)) + { + p_ctx->auto_dl_handle = p_ctx->sender_handle; + ni_log2(p_ctx, NI_LOG_DEBUG, "Autodownload device handle set %p!\n", + p_ctx->auto_dl_handle); + p_ctx->hw_action = NI_CODEC_HW_NONE; + break; + } + } + } } } retval = ni_config_instance_set_encoder_params(p_ctx); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: calling ni_config_instance_set_encoder_params(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: calling ni_config_instance_set_encoder_params(): " + "p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", + (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); ni_encoder_session_close(p_ctx, 0); - retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } + if(p_param->enable_ai_enhance) + { + retval = ni_ai_query_network_ready(p_ctx); + if(retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_ai_query_network_ready returned %d\n", retval); + LRETURN; + } + } ni_timestamp_init(p_ctx, &p_ctx->pts_table, "enc_pts"); ni_timestamp_init(p_ctx, &p_ctx->dts_queue, "enc_dts"); @@ -2315,18 +3084,19 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, NI_DEVICE_TYPE_ENCODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); - if (NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT == retval) + if (NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT == retval + || NI_RETCODE_FAILURE == retval) { - ni_log(NI_LOG_ERROR, "ERROR: VPU_RSRC_INSUFFICIENT\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() line-%d return %d\n", __func__, __LINE__, retval); LRETURN; } else if (buf_info.buf_avail_size > 0) { - ni_log(NI_LOG_DEBUG, "%s(): buf_avail_size %u\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): buf_avail_size %u\n", __func__, buf_info.buf_avail_size); break; } @@ -2336,7 +3106,7 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) } } - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, " "p_ctx->session_id=%d\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, @@ -2350,7 +3120,11 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) if (!dir && ENOENT == NI_ERRNO) { mkdir(dir_name, S_IRWXU | S_IRWXG | S_IRWXO); - ni_log(NI_LOG_DEBUG, "Encoder pkt dump dir created: %s\n", dir_name); + ni_log2(p_ctx, NI_LOG_DEBUG, "Encoder pkt dump dir created: %s\n", dir_name); + } + + if(dir){ + closedir(dir); } snprintf(dir_name, sizeof(dir_name), "%ld-%u-enc-fme", (long)getpid(), @@ -2359,14 +3133,17 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) if (!dir && ENOENT == NI_ERRNO) { mkdir(dir_name, S_IRWXU | S_IRWXG | S_IRWXO); - ni_log(NI_LOG_DEBUG, "Encoder frame dump dir created: %s\n", dir_name); + ni_log2(p_ctx, NI_LOG_DEBUG, "Encoder frame dump dir created: %s\n", dir_name); + } + if(dir){ + closedir(dir); } #endif END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -2378,13 +3155,13 @@ ni_retcode_t ni_encoder_session_open(ni_session_context_t* p_ctx) * * \return *******************************************************************************/ -ni_retcode_t ni_encoder_session_flush(ni_session_context_t* p_ctx) +ni_retcode_t ni_encoder_session_send_eos(ni_session_context_t* p_ctx) { ni_retcode_t retval; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -2392,27 +3169,28 @@ ni_retcode_t ni_encoder_session_flush(ni_session_context_t* p_ctx) if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } retval = ni_config_instance_eos(p_ctx, NI_DEVICE_TYPE_ENCODER); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); - if(NI_RETCODE_SUCCESS != retval) +END: + + if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: %s(), return\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): %d, return\n", __func__, retval); } -END: + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); - ni_log(NI_LOG_TRACE, "%s(): success exit\n", __func__); - return retval; + return retval; } /*!****************************************************************************** @@ -2427,42 +3205,71 @@ ni_retcode_t ni_encoder_session_close(ni_session_context_t* p_ctx, int eos_recie ni_retcode_t retval = NI_RETCODE_SUCCESS; void* p_buffer = NULL; uint32_t ui32LBA = 0; - int counter = 0; - int ret = 0; + int i = 0; + ni_xcoder_params_t *p_param = NULL; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - return NI_RETCODE_INVALID_PARAM; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + + if (p_ctx->device_type == NI_DEVICE_TYPE_ENCODER) + { + ni_log2(p_ctx, NI_LOG_INFO, + "Encoder_complete_info:session_id 0x%x, total frames input:%u " + "buffered: %u completed: %u output: %u dropped: %u error: %u\n", + p_ctx->session_id, p_ctx->session_statistic.ui32FramesInput, + p_ctx->session_statistic.ui32FramesBuffered, + p_ctx->session_statistic.ui32FramesCompleted, + p_ctx->session_statistic.ui32FramesOutput, + p_ctx->session_statistic.ui32FramesDropped, + p_ctx->session_statistic.ui32InstErrors); } //malloc data buffer if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + if (p_ctx->p_session_config) + { + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + if (p_param->ddr_priority_mode > NI_DDR_PRIORITY_NONE) + { + retval = ni_device_set_ddr_configuration(p_ctx, NI_DDR_PRIORITY_RESET); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): ddr priority setting failure for %s\n", + __func__, strerror(NI_ERRNO)); + LRETURN; + } + } + } + ui32LBA = CLOSE_SESSION_R(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); int retry = 0; while (retry < NI_SESSION_CLOSE_RETRY_MAX) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_ctx->blk_io_handle=%" PRIx64 ", p_ctx->hw_id=%d, " "p_ctx->session_id=%d, close_mode=1\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, @@ -2471,16 +3278,17 @@ ni_retcode_t ni_encoder_session_close(ni_session_context_t* p_ctx, int eos_recie if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): command failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + p_ctx->session_id = NI_INVALID_SESSION_ID; break; } else - { - //Close should always succeed - retval = NI_RETCODE_SUCCESS; - p_ctx->session_id = NI_INVALID_SESSION_ID; - break; - } + { + //Close should always succeed + retval = NI_RETCODE_SUCCESS; + p_ctx->session_id = NI_INVALID_SESSION_ID; + break; + } /* else if(((ni_session_closed_status_t *)p_buffer)->session_closed) { @@ -2490,7 +3298,7 @@ ni_retcode_t ni_encoder_session_close(ni_session_context_t* p_ctx, int eos_recie } else { - ni_log(NI_LOG_DEBUG, "%s(): wait for close\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): wait for close\n"); ni_usleep(NI_SESSION_CLOSE_RETRY_INTERVAL_US); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } @@ -2512,45 +3320,34 @@ ni_retcode_t ni_encoder_session_close(ni_session_context_t* p_ctx, int eos_recie if (p_ctx->pts_table) { ni_queue_free(&p_ctx->pts_table->list, p_ctx->buffer_pool); - ni_aligned_free(p_ctx->pts_table); - ni_log(NI_LOG_DEBUG, "ni_timestamp_done: success\n"); + ni_memfree(p_ctx->pts_table); + ni_log2(p_ctx, NI_LOG_DEBUG, "ni_timestamp_done: success\n"); } if (p_ctx->dts_queue) { ni_queue_free(&p_ctx->dts_queue->list, p_ctx->buffer_pool); - ni_aligned_free(p_ctx->dts_queue); - ni_log(NI_LOG_DEBUG, "ni_timestamp_done: success\n"); + ni_memfree(p_ctx->dts_queue); + ni_log2(p_ctx, NI_LOG_DEBUG, "ni_timestamp_done: success\n"); } ni_buffer_pool_free(p_ctx->buffer_pool); p_ctx->buffer_pool = NULL; - int i; for (i = 0; i < NI_FIFO_SZ; i++) { - ni_aligned_free(p_ctx->pkt_custom_sei_set[i]); + ni_memfree(p_ctx->pkt_custom_sei_set[i]); } - ni_log(NI_LOG_DEBUG, "%s(): CTX[Card:%" PRIx64 " / HW:%d / INST:%d]\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): CTX[Card:%" PRIx64 " / HW:%d / INST:%d]\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, p_ctx->session_id); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); -#ifdef XCODER_DUMP_ENABLED - if (p_ctx->p_dump[0]) - { - fclose(p_ctx->p_dump[0]); - p_ctx->p_dump[0] = NULL; - } - if (p_ctx->p_dump[1]) - { - fclose(p_ctx->p_dump[1]); - p_ctx->p_dump[1] = NULL; - } -#endif + low_delay_signal(p_ctx); + ni_pthread_mutex_unlock(&p_ctx->mutex); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -2565,49 +3362,62 @@ ni_retcode_t ni_encoder_session_close(ni_session_context_t* p_ctx, int eos_recie *******************************************************************************/ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) { - bool ishwframe = p_ctx->hw_action & NI_CODEC_HW_ENABLE; + bool ishwframe = false; uint32_t size = 0; - uint32_t metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE; uint32_t send_count = 0; uint32_t i = 0; - uint32_t tx_size = 0, aligned_tx_size = 0; uint32_t sent_size = 0; uint32_t frame_size_bytes = 0; int retval = 0; ni_instance_buf_info_t buf_info = { 0 }; -#ifdef MEASURE_LATENCY - uint64_t abs_time_ns; -#endif - - ni_log(NI_LOG_TRACE, "%s(): enter hw=%d\n", __func__, ishwframe); - //niFrameSurface1_t* p_data3 = (niFrameSurface1_t*)((uint8_t*)p_frame->p_data[3]); - ////p_data3->rsvd = p_meta->hwdesc->rsvd; - //ni_log(NI_LOG_DEBUG, "%s:mar16 HW=%d ui16FrameIdx=%d i8InstID=%d device_handle=%d\n", - // ishwframe, p_data3->ui16FrameIdx, p_data3->i8InstID, p_data3->device_handle); - //ni_log(NI_LOG_DEBUG, "%s:Jun 29 device_handle=%d\n", p_ctx->device_handle); + ni_session_statistic_t sessionStatistic = {0}; if (!p_ctx || !p_frame) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; + return NI_RETCODE_INVALID_PARAM; + } + ishwframe = p_ctx->hw_action & NI_CODEC_HW_ENABLE; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter hw=%d\n", __func__, ishwframe); + + if (ishwframe && !p_frame->end_of_stream) + { + // check if the hw input frame is valid + uint16_t input_frame_idx = ((niFrameSurface1_t*)(p_frame->p_data[3]))->ui16FrameIdx; + if (!((input_frame_idx > 0 && + input_frame_idx < NI_GET_MAX_HWDESC_FRAME_INDEX(p_ctx->ddr_config)) || + (input_frame_idx > NI_GET_MIN_HWDESC_P2P_BUF_ID(p_ctx->ddr_config) && + input_frame_idx <= NI_GET_MAX_HWDESC_P2P_BUF_ID(p_ctx->ddr_config)))) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): got invalid frameIdx [%u]\n", + __func__, input_frame_idx); + return NI_RETCODE_INVALID_PARAM; + } } + ni_pthread_mutex_lock(&p_ctx->mutex); + + uint8_t separate_metadata = p_frame->separate_metadata; + + uint8_t separate_start = (p_frame->separate_start && p_frame->total_start_len) ? 1 : 0; + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } + low_delay_wait(p_ctx); + #ifdef MEASURE_LATENCY if ((p_frame->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) { - abs_time_ns = ni_gettime_ns(); - ni_lat_meas_q_add_entry((ni_lat_meas_q_t *)p_ctx->frame_time_q, - abs_time_ns, p_frame->dts); + uint64_t abs_time_ns = ni_gettime_ns(); + ni_lat_meas_q_t *frame_time_q = (ni_lat_meas_q_t *)p_ctx->frame_time_q; + ni_lat_meas_q_add_entry(frame_time_q, abs_time_ns, p_frame->dts); } #endif @@ -2623,13 +3433,13 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) } else if (p_frame->video_width) { - ni_log(NI_LOG_DEBUG, "WARNING: passed video_height is not valid!, return\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "WARNING: passed video_height is not valid!, return\n"); p_ctx->active_video_height = p_frame->data_len[0] / p_frame->video_width; p_ctx->active_video_width = p_frame->video_width; } else { - ni_log(NI_LOG_ERROR, "ERROR: passed video_height and video_width are not valid!, return\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: passed video_height and video_width are not valid!, return\n"); retval = NI_RETCODE_PARAM_INVALID_VALUE; LRETURN; } @@ -2640,7 +3450,7 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) /*!********************************************************************/ frame_size_bytes = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + p_frame->data_len[3] + p_frame->extra_data_len; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: data_len[0] %u data_len[1] %u " "data_len[2] %u extra_data_len %u frame_size_bytes %u\n", __func__, p_frame->data_len[0], p_frame->data_len[1], @@ -2651,37 +3461,71 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) { for (;;) { - retval = ni_query_instance_buf_info( - p_ctx, INST_BUF_INFO_RW_WRITE, NI_DEVICE_TYPE_ENCODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + query_sleep(p_ctx); - if (NI_RETCODE_SUCCESS != retval || + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "65") >= 0) + { + retval = ni_query_session_statistic_info( + p_ctx, NI_DEVICE_TYPE_ENCODER, &sessionStatistic); + CHECK_ERR_RC(p_ctx, retval, &sessionStatistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + CHECK_VPU_RECOVERY(retval); + buf_info.buf_avail_size = sessionStatistic.ui32WrBufAvailSize; + } else + { + retval = + ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, + NI_DEVICE_TYPE_ENCODER, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + } + + if (NI_RETCODE_FAILURE == retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() line-%d retrun %d\n", __func__, __LINE__, retval); + LRETURN; + } + else if (NI_RETCODE_SUCCESS != retval || buf_info.buf_avail_size < frame_size_bytes) { - ni_log(NI_LOG_TRACE, + ni_log2(p_ctx, NI_LOG_TRACE, "Enc write query retry %d. rc=%d. Available buf size %u < " "frame size %u\n", retval, send_count, buf_info.buf_avail_size, frame_size_bytes); - // extend to 5000 retries for 8K encode on FPGA if (send_count >= NI_MAX_ENCODER_QUERY_RETRIES) { - ni_log(NI_LOG_ERROR, - "ERROR enc query buf info exceeding max retries: " - "%d, ", - NI_MAX_ENCODER_QUERY_RETRIES); + int retval_backup = retval; + retval = ni_query_instance_buf_info( + p_ctx, INST_BUF_INFO_RW_WRITE_BY_EP, NI_DEVICE_TYPE_ENCODER, &buf_info); + if(NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION != retval) + { + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + } + else + retval = NI_RETCODE_SUCCESS; + + ni_log2(p_ctx, NI_LOG_DEBUG, + "Enc write query buf info exceeded max retries: " + "%d, rc=%d. Available buf size %u < frame size %u\n", + NI_MAX_ENCODER_QUERY_RETRIES, retval_backup, + buf_info.buf_avail_size, frame_size_bytes); p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; - retval = NI_RETCODE_SUCCESS; + LRETURN; } send_count++; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); - ni_usleep(100); - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); } else { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Info enc write query success, available buf " "size %u >= frame size %u !\n", buf_info.buf_avail_size, frame_size_bytes); @@ -2691,9 +3535,17 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) } // fill in metadata such as timestamp - ni_metadata_enc_frame_t *p_meta = - (ni_metadata_enc_frame_t *)((uint8_t *)p_frame->p_data[2 + ishwframe] + - p_frame->data_len[2 + ishwframe]); + ni_metadata_enc_frame_t *p_meta; + if (separate_metadata) + { + p_meta = (ni_metadata_enc_frame_t *)p_frame->p_metadata_buffer; + } else + { + p_meta = (ni_metadata_enc_frame_t *)((uint8_t *) + p_frame->p_data[2 + ishwframe] + + p_frame->data_len[2 + ishwframe]); + } + if (p_meta) //When hwframe xcoding reaches eos, frame looks like swframe but no allocation for p_meta { p_meta->metadata_common.ui64_data.frame_tstamp = (uint64_t)p_frame->pts; @@ -2703,7 +3555,7 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_frame->use_cur_src_as_long_term_pic; p_meta->use_long_term_ref = p_frame->use_long_term_ref; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: p_meta " "use_cur_src_as_long_term_pic %d use_long_term_ref %d\n", __func__, p_meta->use_cur_src_as_long_term_pic, @@ -2719,7 +3571,7 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_meta->frame_force_type_enable = 1; p_meta->frame_force_type = p_frame->ni_pict_type; } - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): ctx->force_frame_type" " %d frame->force_key_frame %d force frame_num %" PRIu64 "" " type to %d\n", @@ -2741,14 +3593,29 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_meta->frame_roi_avg_qp = p_ctx->roi_avg_qp; p_meta->enc_reconfig_data_size = p_frame->reconf_len; - ni_log( + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6Q") >= 0) + { + if (separate_start) + { + for (i = 0; i < NI_MAX_NUM_SW_FRAME_DATA_POINTERS; i++) + p_meta->start_len[i] = p_frame->start_len[i]; + } + else + { + memset(p_meta->start_len, 0, sizeof(p_meta->start_len)); + } + p_meta->inconsecutive_transfer = p_frame->inconsecutive_transfer; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): %d.%u p_ctx->frame_num=%" PRIu64 ", " "p_frame->start_of_stream=%u, p_frame->end_of_stream=%u, " "p_frame->video_width=%u, p_frame->video_height=%u, pts=0x%08x 0x%08x, " "dts=0x%08x 0x%08x, sei_len=%u, roi size=%u avg_qp=%u reconf_len=%u " "force_pic_qp=%u use_cur_src_as_long_term_pic %u use_long_term_ref " - "%u\n", + "%u start_len [%u,%u,%u] inconsecutive_transfer %u\n", __func__, p_ctx->hw_id, p_ctx->session_id, p_ctx->frame_num, p_frame->start_of_stream, p_frame->end_of_stream, p_frame->video_width, p_frame->video_height, (uint32_t)((p_frame->pts >> 32) & 0xFFFFFFFF), @@ -2757,15 +3624,17 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) (uint32_t)(p_frame->dts & 0xFFFFFFFF), p_meta->frame_sei_data_size, p_meta->frame_roi_map_size, p_meta->frame_roi_avg_qp, p_meta->enc_reconfig_data_size, p_meta->force_pic_qp_i, - p_meta->use_cur_src_as_long_term_pic, p_meta->use_long_term_ref); + p_meta->use_cur_src_as_long_term_pic, p_meta->use_long_term_ref, + p_meta->start_len[0], p_meta->start_len[1], p_meta->start_len[2], + p_meta->inconsecutive_transfer); } if (p_frame->start_of_stream) { //Send Start of stream p_config command here retval = ni_config_instance_sos(p_ctx, NI_DEVICE_TYPE_ENCODER); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { @@ -2779,8 +3648,8 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) if (p_frame->end_of_stream) { retval = ni_config_instance_eos(p_ctx, NI_DEVICE_TYPE_ENCODER); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { @@ -2795,41 +3664,149 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) p_frame->dts, 0); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): " "ni_timestamp_register() for dts returned: %d\n", __func__, retval); } - uint32_t ui32LBA = - WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); - ni_log(NI_LOG_DEBUG, - "Encoder session write: p_data = %p, p_frame->buffer_size " - "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", - __func__, p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, - ui32LBA); - sent_size = frame_size_bytes; - if (sent_size % NI_MEM_PAGE_ALIGNMENT) + if (separate_metadata) { + uint32_t ui32LBA_metadata = + WRITE_METADATA_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_metadata_buffer = %p, metadata_buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_metadata_buffer, + p_frame->metadata_buffer_size, p_ctx->frame_num, + ui32LBA_metadata); + sent_size = - ((sent_size / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT) + - NI_MEM_PAGE_ALIGNMENT; + ((p_frame->metadata_buffer_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd( + p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_metadata_buffer, sent_size, + ui32LBA_metadata); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", + __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } } - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_frame->p_buffer, sent_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_write, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - if (retval < 0) + if (separate_start) { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + uint32_t ui32LBA = + WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_start_buffer = %p, p_frame->start_buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_start_buffer, p_frame->start_buffer_size, p_ctx->frame_num, + ui32LBA); + + sent_size = + ((p_frame->start_buffer_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_start_buffer, sent_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } + + if (p_frame->inconsecutive_transfer) + { + uint32_t ui32LBA = + WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + + for (i = 0; i < NI_MAX_NUM_SW_FRAME_DATA_POINTERS; i++) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_data = %p, p_frame->buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, + ui32LBA); + + if (p_frame->data_len[i]) + { + sent_size = p_frame->data_len[i]; + if (separate_start) + sent_size -= p_frame->start_len[i]; + + sent_size = + ((sent_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_data[i]+p_frame->start_len[i], sent_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } + } + } + else + { + uint32_t ui32LBA = + WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_data = %p, p_frame->buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, + ui32LBA); + + sent_size = frame_size_bytes; + if (separate_metadata) + sent_size -= p_frame->extra_data_len; + if (separate_start) + sent_size -= p_frame->total_start_len; + + sent_size = + ((sent_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_buffer+p_frame->total_start_len, sent_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } } + if (ishwframe) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): session=0x%x ui16FrameIdx=%u\n", + __func__, + p_ctx->session_id, + ((niFrameSurface1_t*)(p_frame->p_data[3]))->ui16FrameIdx); + } + + p_ctx->status = 0; p_ctx->frame_num++; size = frame_size_bytes; + p_ctx->low_delay_sync_flag = 1; #ifdef XCODER_DUMP_DATA char dump_file[256]; @@ -2849,7 +3826,9 @@ int ni_encoder_session_write(ni_session_context_t* p_ctx, ni_frame_t* p_frame) END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -2860,9 +3839,6 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) uint32_t actual_read_size = 0; uint32_t to_read_size = 0; int size = 0; - uint32_t query_return_size = 0; - uint32_t partial_data = 0; - uint8_t* p_data = NULL; static long long encq_count = 0LL; int retval = NI_RETCODE_SUCCESS; int query_retry = 0; @@ -2871,30 +3847,32 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) ni_metadata_enc_bstream_t *p_meta = NULL; ni_metadata_enc_bstream_rev61_t *p_meta_rev61 = NULL; ni_instance_buf_info_t buf_info = { 0 }; -#ifdef MEASURE_LATENCY - uint64_t abs_time_ns; -#endif - - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_session_statistic_t sessionStatistic = {0}; + int low_delay_notify = 0; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx || !p_packet || !p_packet->p_data) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; - LRETURN; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - ni_log(NI_LOG_DEBUG, "frame_num=%" PRIu64 ", pkt_num=%" PRIu64 "\n", - p_ctx->frame_num, p_ctx->pkt_num); + ni_log2(p_ctx, NI_LOG_DEBUG, "frame_num=%" PRIu64 ", pkt_num=%" PRIu64 ", av1_pkt_num=%" PRIu64 "\n", + p_ctx->frame_num, p_ctx->pkt_num, p_ctx->av1_pkt_num); if (((ni_xcoder_params_t *)p_ctx->p_session_config)->low_delay_mode) { query_type = INST_BUF_INFO_RW_READ_BUSY; @@ -2906,26 +3884,59 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) } else { //nothing to query, leave retval = NI_RETCODE_SUCCESS; + low_delay_notify = 1; LRETURN; } } } for (;;) { - retval = ni_query_instance_buf_info(p_ctx, query_type, - NI_DEVICE_TYPE_ENCODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + query_sleep(p_ctx); + + query_retry++; + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "65") >= 0) + { + retval = ni_query_session_statistic_info( + p_ctx, NI_DEVICE_TYPE_ENCODER, &sessionStatistic); + CHECK_ERR_RC(p_ctx, retval, &sessionStatistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + CHECK_VPU_RECOVERY(retval); + + buf_info.buf_avail_size = sessionStatistic.ui32RdBufAvailSize; + + if (((ni_xcoder_params_t *)p_ctx->p_session_config)->cfg_enc_params.lookAheadDepth) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rX") >= 0) + { + if (p_ctx->current_frame_delay < (int)sessionStatistic.ui8AdditionalFramesDelay + p_ctx->initial_frame_delay) + { + p_ctx->current_frame_delay = (int)sessionStatistic.ui8AdditionalFramesDelay + p_ctx->initial_frame_delay; // extend frames delay by FW estimated additional number of frames + } + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: initial_frame_delay %d max_frame_delay %d ui8AdditionalFramesDelay %u current_frame_delay %d\n", + __FUNCTION__, p_ctx->initial_frame_delay, p_ctx->max_frame_delay, sessionStatistic.ui8AdditionalFramesDelay, p_ctx->current_frame_delay); + } + } + } else + { + retval = ni_query_instance_buf_info( + p_ctx, query_type, NI_DEVICE_TYPE_ENCODER, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + } - ni_log(NI_LOG_DEBUG, "Info enc read query rc %d, available buf size %u, " - "frame_num=%" PRIu64 ", pkt_num=%" PRIu64 "\n", - retval, buf_info.buf_avail_size, p_ctx->frame_num, - p_ctx->pkt_num); + ni_log2(p_ctx, NI_LOG_TRACE, + "Info enc read query rc %d, available buf size %u, " + "frame_num=%" PRIu64 ", pkt_num=%" PRIu64 "\n", + retval, buf_info.buf_avail_size, p_ctx->frame_num, p_ctx->pkt_num); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "Buffer info query failed in encoder read!!!!\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "Buffer info query failed in encoder read!!!!\n"); LRETURN; } else if (0 == buf_info.buf_avail_size) { @@ -2933,14 +3944,14 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) if (p_ctx->ready_to_close) { retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_ENCODER, &data); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "Stream info query failed in encoder read!!!!\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "Stream info query failed in encoder read!!!!\n"); LRETURN; } @@ -2949,19 +3960,45 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) p_packet->end_of_stream = 1; } } - ni_log(NI_LOG_DEBUG, "Info enc read available buf size %u, eos %u !\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Info enc read available buf size %u, eos %u !\n", buf_info.buf_avail_size, p_packet->end_of_stream); - if (((ni_xcoder_params_t *)p_ctx->p_session_config)->low_delay_mode && + if ((((ni_xcoder_params_t *)p_ctx->p_session_config)->low_delay_mode || + (NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == p_ctx->status)) && !p_packet->end_of_stream && p_ctx->frame_num >= p_ctx->pkt_num) { - ni_log(NI_LOG_DEBUG, "Encoder low latency mode, eos not sent, frame_num " - "%" PRIu64 " >= %" PRIu64 " pkt_num, keep querying\n", - p_ctx->frame_num, p_ctx->pkt_num); - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); - ni_usleep(200); - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); - continue; + ni_log2(p_ctx, NI_LOG_DEBUG, "Encoder low latency mode, eos not sent, frame_num " + "%" PRIu64 " >= %" PRIu64 " pkt_num, keep querying p_ctx->status %d\n", + p_ctx->frame_num, p_ctx->pkt_num, p_ctx->status); + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_200US); + ni_pthread_mutex_lock(&p_ctx->mutex); + if (query_retry >= NI_MAX_ENCODER_QUERY_RETRIES && + NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == p_ctx->status) + { + low_delay_notify = 1; + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; + } + else + { + continue; + } + } + else if (((ni_xcoder_params_t *)p_ctx->p_session_config)->minFramesDelay) + { + if (p_ctx->pkt_num) // do not busy read until header is received + { + uint64_t pkt_num = (p_ctx->codec_format == NI_CODEC_FORMAT_AV1) ? p_ctx->av1_pkt_num : p_ctx->pkt_num - 1; // deduct header from pkt_num + if (p_ctx->frame_num - pkt_num >= p_ctx->current_frame_delay && + !p_packet->end_of_stream) + { + ni_log2(p_ctx, NI_LOG_TRACE, "%s: low delay mode 2, keep reading send frame %d receive pkt %d gop %d current_frame_delay %d\n", + __FUNCTION__, p_ctx->frame_num, pkt_num, + p_ctx->last_gop_size, p_ctx->current_frame_delay); + continue; + } + } } retval = NI_RETCODE_SUCCESS; LRETURN; @@ -2970,7 +4007,7 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) break; } } - ni_log(NI_LOG_DEBUG, "Encoder read buf_avail_size %u\n", buf_info.buf_avail_size); + ni_log2(p_ctx, NI_LOG_DEBUG, "Encoder read buf_avail_size %u\n", buf_info.buf_avail_size); to_read_size = buf_info.buf_avail_size; @@ -2991,7 +4028,7 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) { if (ni_packet_buffer_alloc(p_packet, actual_read_size)) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): packet buffer size %u allocation " "failed\n", __func__, actual_read_size); @@ -3002,18 +4039,19 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_packet->p_data, actual_read_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_read, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (retval < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } - // SSIM is supported if fw_rev is higher than major 6 minor 1. - if (is_fw_rev_higher(p_ctx, (uint8_t)'6', (uint8_t)'1')) + // SSIM is supported if fw_rev is >= 6.2 + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "62") >= 0) { p_meta = (ni_metadata_enc_bstream_t *)p_packet->p_data; p_packet->pts = (int64_t)(p_meta->frame_tstamp); @@ -3021,7 +4059,43 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) p_packet->avg_frame_qp = p_meta->avg_frame_qp; p_packet->recycle_index = p_meta->recycle_index; p_packet->av1_show_frame = p_meta->av1_show_frame; - ni_log(NI_LOG_DEBUG, "%s RECYCLE INDEX = %u!!!\n", __FUNCTION__, p_meta->recycle_index); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s RECYCLE INDEX = %u!!!\n", __FUNCTION__, p_meta->recycle_index); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s MetaDataSize %d FrameType %d AvgFrameQp %d ssim %d %d %d\n", + __FUNCTION__, p_meta->metadata_size, p_meta->frame_type, p_meta->avg_frame_qp, p_meta->ssimY, p_meta->ssimU, p_meta->ssimV); + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r2") >= 0) + { + if (((ni_xcoder_params_t *)p_ctx->p_session_config)->cfg_enc_params.lookAheadDepth) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rX") < 0) + { + if (p_meta->gop_size) // ignore frame 0 gop size 0 (other I-frame gop size 1) + { + if ((int)p_meta->gop_size < p_ctx->last_gop_size) + { + p_ctx->current_frame_delay = p_ctx->max_frame_delay; // shortening gop (including I-frame) causes lookahead queue increase, currently assume worst case frame delay + } + } + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: current gop_size %u last_gop_size %d initial_frame_delay %d max_frame_delay %d current_frame_delay %d\n", + __FUNCTION__, p_meta->gop_size, p_ctx->last_gop_size, p_ctx->initial_frame_delay, p_ctx->max_frame_delay, p_ctx->current_frame_delay); + } + p_ctx->last_gop_size = p_meta->gop_size; + } + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: current gop_size %u\n", + __FUNCTION__, p_meta->gop_size); + } + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6p") >= 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "max_mv x[0] %d x[1] %d y[0] %d y[1] %d min_mv x[0] %d x[1] %d y[0] %d y[1] %d frame_size %u inter_total_count %u intra_total_count %u\n", + __FUNCTION__, + p_meta->max_mv_x[0], p_meta->max_mv_x[1], p_meta->max_mv_y[0], p_meta->max_mv_y[1], + p_meta->min_mv_x[0], p_meta->min_mv_x[1], p_meta->min_mv_y[0], p_meta->min_mv_y[1], + p_meta->frame_size, p_meta->inter_total_count, p_meta->intra_total_count); + } p_ctx->meta_size = p_meta->metadata_size; @@ -3029,8 +4103,16 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) { // The SSIM Y, U, V values returned by FW are 4 decimal places multiplied by 10000. //Divide by 10000 to get the original value. - ni_log(NI_LOG_DEBUG, "%s: ssim Y %.4f U %.4f V %.4f\n", __FUNCTION__, - (float)p_meta->ssimY/10000, (float)p_meta->ssimU/10000, (float)p_meta->ssimV/10000); + ni_log2(p_ctx, +#ifdef NI_LOG_SSIM_AT_INFO + NI_LOG_INFO, +#else + NI_LOG_DEBUG, +#endif + "%s: pkt #%" PRId64 " pts %" PRId64 " ssim " + "Y %.4f U %.4f V %.4f\n", __FUNCTION__, p_ctx->pkt_num, + p_packet->pts, (float)p_meta->ssimY/10000, + (float)p_meta->ssimU/10000, (float)p_meta->ssimV/10000); } } else @@ -3042,7 +4124,7 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) p_packet->avg_frame_qp = p_meta_rev61->avg_frame_qp; p_packet->recycle_index = p_meta_rev61->recycle_index; p_packet->av1_show_frame = p_meta_rev61->av1_show_frame; - ni_log(NI_LOG_DEBUG, "%s RECYCLE INDEX = %u!!!\n", __FUNCTION__, p_meta_rev61->recycle_index); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s RECYCLE INDEX = %u!!!\n", __FUNCTION__, p_meta_rev61->recycle_index); } @@ -3054,11 +4136,21 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) { if (p_ctx->pkt_num >= 1) { - if (ni_timestamp_get_with_threshold(p_ctx->dts_queue, 0, (int64_t*)& p_packet->dts, 0, encq_count % 500 == 0, p_ctx->buffer_pool) != NI_RETCODE_SUCCESS) + if (NI_CODEC_FORMAT_AV1 != p_ctx->codec_format + || p_packet->av1_show_frame) { - p_packet->dts = NI_NOPTS_VALUE; + if (ni_timestamp_get_with_threshold(p_ctx->dts_queue, 0, (int64_t*)& p_packet->dts, 0, encq_count % 500 == 0, p_ctx->buffer_pool) != NI_RETCODE_SUCCESS) + { + p_packet->dts = NI_NOPTS_VALUE; + } } + p_ctx->pkt_num++; + if (p_ctx->codec_format == NI_CODEC_FORMAT_AV1 && p_packet->recycle_index != (uint32_t) NI_AV1_INVALID_BUFFER_INDEX) // av1 invalid buffer index indicates show_existing_frame header packet + { + p_ctx->av1_pkt_num++; + } + low_delay_notify = 1; } encq_count++; @@ -3076,7 +4168,7 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) #endif } - ni_log( + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): %d.%u p_packet->start_of_stream=%u, " "p_packet->end_of_stream=%u, p_packet->video_width=%u, " @@ -3090,12 +4182,12 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) (uint32_t)(p_packet->pts & 0xFFFFFFFF), p_packet->frame_type, p_packet->avg_frame_qp, p_packet->av1_show_frame); - ni_log(NI_LOG_DEBUG, "%s(): p_packet->data_len=%u, size=%d\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_packet->data_len=%u, size=%d\n", __func__, p_packet->data_len, size); if (encq_count % 500 == 0) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Encoder pts queue size = %u dts queue size = %u\n\n", p_ctx->pts_table->list.count, p_ctx->dts_queue->list.count); } @@ -3105,21 +4197,32 @@ int ni_encoder_session_read(ni_session_context_t* p_ctx, ni_packet_t* p_packet) #ifdef MEASURE_LATENCY if ((p_packet->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) { - abs_time_ns = ni_gettime_ns(); - ni_log(NI_LOG_INFO, "DTS:%lld,DELTA:%lu,eLAT:%lu;\n", p_packet->dts, - abs_time_ns - p_ctx->prev_read_frame_time, - ni_lat_meas_q_check_latency((ni_lat_meas_q_t *)p_ctx->frame_time_q, - abs_time_ns, p_packet->dts)); - p_ctx->prev_read_frame_time = abs_time_ns; + if (NI_CODEC_FORMAT_AV1 != p_ctx->codec_format + || p_packet->av1_show_frame) + { + uint64_t abs_time_ns = ni_gettime_ns(); + ni_lat_meas_q_t *q = (ni_lat_meas_q_t *)p_ctx->frame_time_q; + ni_log2(p_ctx, NI_LOG_INFO, "DTS:%" PRId64 ",DELTA:%" PRId64 ",eLAT:%" PRIu64 ";\n", + p_packet->dts, abs_time_ns - q->last_benchmark_time, + ni_lat_meas_q_check_latency(q, abs_time_ns, p_packet->dts)); + q->last_benchmark_time = abs_time_ns; + } } #endif END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); - return retval; -} + if (low_delay_notify) + { + low_delay_signal(p_ctx); + } + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} /*!****************************************************************************** * \brief Send sequnce change to a xcoder encoder instance @@ -3132,25 +4235,31 @@ ni_retcode_t ni_encoder_session_sequence_change(ni_session_context_t* p_ctx, ni_ { ni_retcode_t retval = NI_RETCODE_SUCCESS; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + // re-init last_gop_size and av1_pkt_num for minFramesDelay frame delay estimiation + int lookAheadEnable = !!(((ni_xcoder_params_t *)p_ctx->p_session_config)->cfg_enc_params.lookAheadDepth); + int gop_preset_index = ((ni_xcoder_params_t *)p_ctx->p_session_config)->cfg_enc_params.gop_preset_index; + p_ctx->last_gop_size = g_map_preset_to_gopsize[lookAheadEnable][gop_preset_index + 1]; + p_ctx->av1_pkt_num = 0; //Configure encoder sequence change retval = ni_config_instance_set_sequence_change(p_ctx, NI_DEVICE_TYPE_ENCODER, p_resolution); - CHECK_ERR_RC(p_ctx, retval, nvme_config_xcoder_config_set_sequence_change, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_config_xcoder_config_set_sequence_change, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (retval < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): config encoder sequence change command failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): config encoder sequence change command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -3170,8 +4279,9 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) ni_retcode_t retval = NI_RETCODE_SUCCESS; void* p_buffer = NULL; uint32_t ui32LBA = 0; + char fmt_fw_api_ver1[5], fmt_fw_api_ver2[5]; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { @@ -3181,15 +4291,30 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) if (p_ctx->scaler_operation == NI_SCALER_OPCODE_STACK) { - if ((p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] < '6') || - ((p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] == '6') && - (p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX] < '4'))) + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "64") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot use stack filter on device with FW API version < 6.4\n"); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + } + + if (p_ctx->scaler_operation == NI_SCALER_OPCODE_ROTATE) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "67") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot use rotate filter on device with FW API version < 6.7\n"); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + } + + if (p_ctx->scaler_operation == NI_SCALER_OPCODE_IPOVLY) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6L") < 0) { - ni_log(NI_LOG_ERROR, "ERROR: " - "FW revision %c%c is less then the minimum required 64\n", - p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX] - ); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot use in-place overlay filter on device with FW API version < 6.L\n"); return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; } } @@ -3216,7 +4341,7 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -3226,7 +4351,7 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) //malloc data buffer if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -3244,17 +4369,18 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); LRETURN; } //Open will return a session status structure with a valid session id if it worked. //Otherwise the invalid session id set before the open command will stay p_ctx->session_id = ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); - p_ctx->session_timestamp = - ni_htonll(((ni_session_stats_t *)p_buffer)->ui64Session_timestamp); + p_ctx->session_timestamp = ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_high); + p_ctx->session_timestamp = (p_ctx->session_timestamp << 32) | + ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_low); if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, @@ -3262,8 +4388,8 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - ni_log(NI_LOG_DEBUG, "Scaler open session ID:0x%x\n",p_ctx->session_id); - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Scaler open session ID:0x%x\n",p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, @@ -3274,18 +4400,18 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) p_ctx->keep_alive_timeout * 1000000; //send us to FW memset(p_buffer, 0, NI_DATA_BUFFER_LEN); memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); - ni_log(NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, keep_alive_timeout); ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme write keep_alive_timeout command " "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); @@ -3293,27 +4419,27 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) LRETURN; } - // Send SW version to FW if FW version is higher than major 6 minor 1 - if (is_fw_rev_higher(p_ctx, (uint8_t)'6', (uint8_t)'1')) + // Send SW version to FW if FW API version is >= 6.2 + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "62") >= 0) { // Send SW version to session manager memset(p_buffer, 0, NI_DATA_BUFFER_LEN); memcpy(p_buffer, NI_XCODER_REVISION, sizeof(uint64_t)); - ni_log(NI_LOG_DEBUG, "%s sw_version major %c minor %c fw_rev major %c minor %c\n", __func__, - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - p_ctx->fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX]); + ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &fmt_fw_api_ver1[0]); + ni_fmt_fw_api_ver_str((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &fmt_fw_api_ver2[0]); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s libxcoder FW API ver %s, FW FW API ver %s\n", + __func__, fmt_fw_api_ver1, fmt_fw_api_ver2); ui32LBA = CONFIG_SESSION_SWVersion_W(p_ctx->session_id); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme write sw_version command " "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); @@ -3334,91 +4460,11 @@ int ni_scaler_session_open(ni_session_context_t* p_ctx) #ifndef _WIN32 if (p_ctx->isP2P) { - int ret; - char line[256]; - char syspath[256]; - struct stat bstat; - char *block_dev; - char *dom, *bus, *dev, *fnc; - FILE *fp; - - p_ctx->netint_fd = open("/dev/netint", O_RDWR); - if (p_ctx->netint_fd < 0) - { - ni_log(NI_LOG_ERROR, "ERROR: Can't open device /dev/netint\n"); - return NI_RETCODE_FAILURE; - } - - block_dev = &p_ctx->blk_xcoder_name[0]; - if (stat(block_dev, &bstat) < 0) - { - ni_log(NI_LOG_ERROR, "failed to get stat of file %s\n", block_dev); - return NI_RETCODE_FAILURE; - } - - if ((bstat.st_mode & S_IFMT) != S_IFBLK) - { - ni_log(NI_LOG_ERROR, "%s is not a block device\n", block_dev); - return NI_RETCODE_FAILURE; - } - - ret = snprintf(syspath, sizeof(syspath) - 1, - "/sys/block/%s/device/address", block_dev + 5); - syspath[ret] = '\0'; - - fp = fopen(syspath, "r"); - - if (fp == NULL) - { - ni_log(NI_LOG_ERROR, "Failed to read address\n"); - return NI_RETCODE_FAILURE; - } - - if (fgets(line, 256, fp) == NULL) - { - ni_log(NI_LOG_ERROR, "Failed to read line from address\n"); - fclose(fp); - return NI_RETCODE_FAILURE; - } - - fclose(fp); - - errno = 0; - p_ctx->domain = strtoul(line, &dom, 16); - if (errno < 0) - { - ni_log(NI_LOG_ERROR, "Failed to read PCI domain\n"); - return NI_RETCODE_FAILURE; - } - - errno = 0; - p_ctx->bus = strtoul(dom + 1, &bus, 16); - if (errno < 0) - { - ni_log(NI_LOG_ERROR, "Failed to read PCI bus\n"); - return NI_RETCODE_FAILURE; - } - - errno = 0; - p_ctx->dev = strtoul(bus + 1, &dev, 16); - - if (errno < 0) - { - ni_log(NI_LOG_ERROR, "Failed to read PCI device\n"); - return NI_RETCODE_FAILURE; - } - - errno = 0; - p_ctx->fn = strtoul(dev + 1, &fnc, 16); - - if (errno < 0) + retval = p2p_fill_pcie_address(p_ctx); + if(retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "Falied to read PCI function\n"); - return NI_RETCODE_FAILURE; + LRETURN; } - - ni_log(NI_LOG_DEBUG, "PCI slot = %d:%d:%d:%d\n", p_ctx->domain, - p_ctx->bus, p_ctx->dev, p_ctx->fn); } #endif @@ -3446,21 +4492,24 @@ ni_retcode_t ni_scaler_session_close(ni_session_context_t* p_ctx, int eos_receiv if (!p_ctx) { - return NI_RETCODE_INVALID_PARAM; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if (p_ctx->session_id == NI_INVALID_SESSION_ID) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_SUCCESS; LRETURN; } //malloc data buffer if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() malloc data buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() malloc data buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -3472,7 +4521,7 @@ ni_retcode_t ni_scaler_session_close(ni_session_context_t* p_ctx, int eos_receiv int retry = 0; while (retry < NI_SESSION_CLOSE_RETRY_MAX) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_ctx->blk_io_handle=%" PRIx64 ", p_ctx->hw_id=%d, " "p_ctx->session_id=%d, close_mode=1\n", __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, @@ -3481,8 +4530,9 @@ ni_retcode_t ni_scaler_session_close(ni_session_context_t* p_ctx, int eos_receiv if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, NI_DATA_BUFFER_LEN, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): command failed!\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): command failed!\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + p_ctx->session_id = NI_INVALID_SESSION_ID; break; } else { @@ -3506,8 +4556,11 @@ ni_retcode_t ni_scaler_session_close(ni_session_context_t* p_ctx, int eos_receiv END: + ni_aligned_free(p_buffer); ni_aligned_free(p_ctx->p_all_zero_buf); + ni_pthread_mutex_unlock(&p_ctx->mutex); + return retval; } @@ -3528,11 +4581,11 @@ ni_retcode_t ni_config_instance_set_scaler_params(ni_session_context_t *p_ctx, ni_retcode_t retval = NI_RETCODE_SUCCESS; uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx || !p_params) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -3540,7 +4593,7 @@ ni_retcode_t ni_config_instance_set_scaler_params(ni_session_context_t *p_ctx, if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -3551,7 +4604,7 @@ ni_retcode_t ni_config_instance_set_scaler_params(ni_session_context_t *p_ctx, NI_MEM_PAGE_ALIGNMENT; if (ni_posix_memalign(&p_scaler_config, sysconf(_SC_PAGESIZE), buffer_size)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() malloc p_scaler_config buffer failed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() malloc p_scaler_config buffer failed\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -3567,10 +4620,11 @@ ni_retcode_t ni_config_instance_set_scaler_params(ni_session_context_t *p_ctx, p_cfg->filterblit = p_params->filterblit; p_cfg->numInputs = p_params->nb_inputs; - if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_scaler_config, buffer_size, ui32LBA) < 0) + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_scaler_config, buffer_size, ui32LBA); + if ((int32_t)retval < 0) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_write_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %d, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); @@ -3578,20 +4632,24 @@ ni_retcode_t ni_config_instance_set_scaler_params(ni_session_context_t *p_ctx, retval = ni_scaler_session_close(p_ctx, 0); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s failed: blk_io_handle: %" PRIx64 "," "hw_id, %d, xcoder_inst_id: %d\n", + __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); } retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; } + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); END: ni_aligned_free(p_scaler_config); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -3632,6 +4690,7 @@ ni_retcode_t ni_scaler_alloc_frame(ni_session_context_t* p_ctx, ni_instance_mgr_allocation_info_t *p_data; uint32_t dataLen; uint32_t ui32LBA = 0; + uint32_t query_retry = 0; /* Round up to nearest 4096 bytes */ dataLen = @@ -3645,14 +4704,80 @@ ni_retcode_t ni_scaler_alloc_frame(ni_session_context_t* p_ctx, if (p_ctx->session_id == NI_INVALID_SESSION_ID) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); return NI_RETCODE_ERROR_INVALID_SESSION; } + if (((options & NI_SCALER_FLAG_IO) && (options & NI_SCALER_FLAG_PC))) + { + // this operation is to free/allocate scaler frame pool + if (rgba_color == 0) + { + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r3") < 0) + { + ni_log2(p_ctx, NI_LOG_INFO, + "WARNING: Allocate framepool size 0 for session 0x%x\n", p_ctx->session_id); + return NI_RETCODE_SUCCESS; + } + else if (p_ctx->pool_type == NI_POOL_TYPE_NONE) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() try to free session 0x%x framepool while it's not allocated\n", + __func__, p_ctx->session_id); + return NI_RETCODE_INVALID_PARAM; + } + else if ((options & NI_SCALER_FLAG_P2) == p_ctx->pool_type) + { + ni_log2(p_ctx, NI_LOG_INFO, "Free framepool of scaler 0x%x\n", p_ctx->session_id); + } + else + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() try to free session 0x%x framepool of type %u while " + "passing type %u\n", + __func__, p_ctx->session_id, p_ctx->pool_type, + (options & NI_SCALER_FLAG_P2)); + } + } + else + { + if (p_ctx->pool_type != NI_POOL_TYPE_NONE) + { + // try to expand the framepool + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r3") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: allocate framepool multiple times for session 0x%x " + "not supported in FW API version < 6r3\n", + p_ctx->session_id); + return NI_RETCODE_INVALID_PARAM; + } + if ((options & NI_SCALER_FLAG_P2) == p_ctx->pool_type) + { + ni_log2(p_ctx, NI_LOG_INFO, + "Expand frame pool of scaler 0x%x with %u more frames\n", + p_ctx->session_id, rgba_color); + } + else + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: try to expand session 0x%x framepool with type %u " + "while pool type is %u\n", + p_ctx->session_id, options & NI_SCALER_FLAG_P2, p_ctx->pool_type); + return NI_RETCODE_INVALID_PARAM; + } + } + } + } + if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); return NI_RETCODE_ERROR_MEM_ALOC; } @@ -3669,30 +4794,65 @@ ni_retcode_t ni_scaler_alloc_frame(ni_session_context_t* p_ctx, p_data->rectangle_y = rectangle_y; p_data->rgba_color = rgba_color; p_data->frame_index = frame_index; - - ni_log(NI_LOG_DEBUG, - "Dev alloc frame: W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", + bool isrgb = ((GC620_RGBA8888 == format) || (GC620_BGRX8888 == format) || + (GC620_ARGB8888 == format) || (GC620_ABGR8888 == format)); + if(width > NI_MAX_RESOLUTION_WIDTH || height > NI_MAX_RESOLUTION_HEIGHT || + width < NI_MIN_RESOLUTION_WIDTH_SCALER || height < NI_MIN_RESOLUTION_HEIGHT_SCALER || + ((width > NI_MAX_RESOLUTION_RGBA_WIDTH || height > NI_MAX_RESOLUTION_RGBA_HEIGHT) && isrgb)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Resolution %d x %d not supported for %d format!\n", width, height, format); + ni_aligned_free(p_data); + return NI_RETCODE_NVME_SC_INVALID_PARAMETER; + } + ni_log2(p_ctx, NI_LOG_DEBUG, + "Session=0x%x: Dev alloc frame: FrameIndex=%d; W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", + p_ctx->session_id, frame_index, p_data->picture_width, p_data->picture_height, p_data->picture_format, p_data->rectangle_width, p_data->rectangle_height, p_data->rectangle_x, p_data->rectangle_y); + ui32LBA = CONFIG_INSTANCE_SetScalerAlloc_W(p_ctx->session_id, NI_DEVICE_TYPE_SCALER); - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_data, dataLen, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); + for (;;) + { + query_retry++; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_data, dataLen, ui32LBA); + + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_3); + + if (retval == NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE) + { + if (query_retry >= 1000 || (options & NI_SCALER_FLAG_PC)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Warning: 2D could not acquire frame\n"); + retval = NI_RETCODE_FAILURE; + LRETURN; + } + ni_usleep(NI_RETRY_INTERVAL_100US); + continue; + } + else + { + p_ctx->pool_type = ((options & NI_SCALER_FLAG_IO) && (options & NI_SCALER_FLAG_PC)) ? + (options & NI_SCALER_FLAG_P2) : (p_ctx->pool_type); + break; + } + } + if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: " "blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed!\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed!\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } -// cppcheck-suppress unusedLabel END: ni_aligned_free(p_data); @@ -3730,14 +4890,14 @@ ni_retcode_t ni_scaler_config_frame(ni_session_context_t *p_ctx, if (p_ctx->session_id == NI_INVALID_SESSION_ID) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); return NI_RETCODE_ERROR_INVALID_SESSION; } if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); return NI_RETCODE_ERROR_MEM_ALOC; } @@ -3757,33 +4917,62 @@ ni_retcode_t ni_scaler_config_frame(ni_session_context_t *p_ctx, p_data->frame_index = p_cfg->frame_index; p_data->session_id = p_cfg->session_id; p_data->output_index = p_cfg->output_index; + switch (p_cfg->orientation) + { + case 0: + case 2: + case 4: + case 5: + p_data->orientation = p_cfg->orientation; + break; + case 1: + p_data->orientation = 3; + break; + case 3: + p_data->orientation = 1; + break; + default: + ni_log2(p_ctx, NI_LOG_ERROR, "Bad orientation: %u\n", p_cfg->orientation); + return NI_RETCODE_PARAM_INVALID_VALUE; + } + bool isrgb = ((GC620_RGBA8888 == p_data->picture_format) || (GC620_BGRX8888 == p_data->picture_format) || + (GC620_ARGB8888 == p_data->picture_format) || (GC620_ABGR8888 == p_data->picture_format)); + if(p_data->picture_width > NI_MAX_RESOLUTION_WIDTH || p_data->picture_height > NI_MAX_RESOLUTION_HEIGHT || + p_data->picture_width < NI_MIN_RESOLUTION_WIDTH_SCALER || p_data->picture_height < NI_MIN_RESOLUTION_HEIGHT_SCALER || + ((p_data->picture_width > NI_MAX_RESOLUTION_RGBA_WIDTH || p_data->picture_height > NI_MAX_RESOLUTION_RGBA_HEIGHT) && isrgb)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Resolution %d x %d not supported for %d format!\n", p_data->picture_width, p_data->picture_height, p_data->picture_format); + ni_aligned_free(p_data); + return NI_RETCODE_NVME_SC_INVALID_PARAMETER; + } - ni_log(NI_LOG_DEBUG, - "Dev config frame: W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", + ni_log2(p_ctx, NI_LOG_DEBUG, + "Session=0x%x: Dev config frame: FrameIndex=%u; W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d; O=%d\n", + p_ctx->session_id, p_cfg->frame_index, p_data->picture_width, p_data->picture_height, p_data->picture_format, p_data->rectangle_width, - p_data->rectangle_height, p_data->rectangle_x, p_data->rectangle_y); + p_data->rectangle_height, p_data->rectangle_x, + p_data->rectangle_y, p_data->orientation); ui32LBA = CONFIG_INSTANCE_SetScalerAlloc_W(p_ctx->session_id, NI_DEVICE_TYPE_SCALER); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_data, dataLen, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR ni_scaler_config(): nvme command failed!\n"); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } -// cppcheck-suppress unusedLabel END: ni_aligned_free(p_data); @@ -3826,14 +5015,14 @@ ni_retcode_t ni_scaler_multi_config_frame(ni_session_context_t *p_ctx, if (p_ctx->session_id == NI_INVALID_SESSION_ID) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); return NI_RETCODE_ERROR_INVALID_SESSION; } if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); return NI_RETCODE_ERROR_MEM_ALOC; } @@ -3858,9 +5047,11 @@ ni_retcode_t ni_scaler_multi_config_frame(ni_session_context_t *p_ctx, p_data->session_id = p_cfg_in[i].session_id; p_data->output_index = p_cfg_in[i].output_index; - ni_log(NI_LOG_DEBUG, - "Dev in config frame %d: W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", - i, p_data->picture_width, p_data->picture_height, + ni_log2(p_ctx, NI_LOG_DEBUG, + "Session=0x%x: Dev in config frame %d: FrameIndex=%u; Session=0x%x; W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", + p_ctx->session_id, i, + p_data->frame_index, p_data->session_id, + p_data->picture_width, p_data->picture_height, p_data->picture_format, p_data->rectangle_width, p_data->rectangle_height, p_data->rectangle_x, p_data->rectangle_y); @@ -3881,34 +5072,40 @@ ni_retcode_t ni_scaler_multi_config_frame(ni_session_context_t *p_ctx, p_data->rgba_color = p_cfg_out->rgba_color; p_data->frame_index = p_cfg_out->frame_index; - ni_log(NI_LOG_DEBUG, - "Dev out config frame: W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", + ni_log2(p_ctx, NI_LOG_DEBUG, + "Session=0x%x: Dev out config frame: FrameIndex=%u; W=%d; H=%d; C=%d; RW=%d; RH=%d; RX=%d; RY=%d\n", + p_ctx->session_id, p_data->frame_index, p_data->picture_width, p_data->picture_height, p_data->picture_format, p_data->rectangle_width, p_data->rectangle_height, p_data->rectangle_x, p_data->rectangle_y); } + if(p_data->picture_width > NI_MAX_RESOLUTION_WIDTH || p_data->picture_height > NI_MAX_RESOLUTION_HEIGHT || ((p_data->picture_width > NI_MAX_RESOLUTION_RGBA_WIDTH || p_data->picture_height> NI_MAX_RESOLUTION_RGBA_HEIGHT) && ((GC620_RGBA8888 == p_data->picture_format) || (GC620_BGRX8888 == p_data->picture_format) || (GC620_ARGB8888 == p_data->picture_format) || (GC620_ABGR8888 == p_data->picture_format)))) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Resolution %d x %d not supported for %d format!\n", p_data->picture_width, p_data->picture_height, p_data->picture_format); + ni_aligned_free(p_data); + return NI_RETCODE_NVME_SC_INVALID_PARAMETER; + } ui32LBA = CONFIG_INSTANCE_SetScalerAlloc_W(p_ctx->session_id, NI_DEVICE_TYPE_SCALER); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_data_orig, dataLen, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - ni_log(NI_LOG_ERROR, + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR ni_scaler_config(): nvme command failed!\n"); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } -// cppcheck-suppress unusedLabel END: ni_aligned_free(p_data_orig); @@ -3932,11 +5129,11 @@ int ni_query_general_status(ni_session_context_t* p_ctx, ni_device_type_t device uint32_t ui32LBA = 0; uint32_t dataLen = ((sizeof(ni_instance_mgr_general_status_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if ((!p_ctx) || (!p_gen_status)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -3944,7 +5141,7 @@ int ni_query_general_status(ni_session_context_t* p_ctx, ni_device_type_t device if (!IS_XCODER_DEVICE_TYPE(device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -3954,7 +5151,7 @@ int ni_query_general_status(ni_session_context_t* p_ctx, ni_device_type_t device if (ni_posix_memalign((void **)&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -3964,7 +5161,7 @@ int ni_query_general_status(ni_session_context_t* p_ctx, ni_device_type_t device if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, dataLen, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -3972,13 +5169,94 @@ int ni_query_general_status(ni_session_context_t* p_ctx, ni_device_type_t device //No need to flip the bytes since the datastruct has only uint8_t datatypes memcpy((void*)p_gen_status, p_buffer, sizeof(ni_instance_mgr_general_status_t)); - ni_log(NI_LOG_DEBUG, "%s(): model_load:%u qc:%d percent:%d\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): model_load:%u qc:%d percent:%d\n", __func__, p_gen_status->fw_model_load, p_gen_status->cmd_queue_count, p_gen_status->process_load_percent); END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} + +/*!****************************************************************************** + * \brief Query a particular xcoder instance to get DetailStatus data + * + * \param ni_session_context_t p_ctx - xcoder Context + * \param ni_device_type_t device_type - xcoder type Encoder or Decoder + * \param ni_instance_mgr_detail_status_t *out - Struct preallocated from the caller where the + * resulting data will be placed + * + * \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_MEM_ALOC or NI_RETCODE_ERROR_NVME_CMD_FAILED on failure + *******************************************************************************/ +int ni_query_detail_status(ni_session_context_t* p_ctx, ni_device_type_t device_type, void* p_detail_status, int ver) +{ + void* p_buffer = NULL; + int retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + uint32_t dataLen = 0; + uint32_t copyLen = 0; + if(ver == 0) + { + ui32LBA = QUERY_DETAIL_GET_STATUS_R(device_type); + copyLen = sizeof(ni_instance_mgr_detail_status_t) * NI_MAX_CONTEXTS_PER_HW_INSTANCE; + dataLen = ((copyLen + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + } + else if(ver == 1) + { + ui32LBA = QUERY_DETAIL_GET_STATUS_V1_R(device_type); + copyLen = sizeof(ni_instance_mgr_detail_status_v1_t); + dataLen = (copyLen + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT * NI_MEM_PAGE_ALIGNMENT; + } + else + { + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if ((!p_ctx) || (!p_detail_status)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (!IS_XCODER_DEVICE_TYPE(device_type)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + __func__, device_type); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (ni_posix_memalign((void **)&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + + memset(p_buffer, 0, dataLen); + + if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, dataLen, ui32LBA) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + + //No need to flip the bytes since the datastruct has only uint8_t datatypes + memcpy(p_detail_status, p_buffer, copyLen); + +END: + + ni_aligned_free(p_buffer); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4001,11 +5279,11 @@ ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t uint32_t ui32LBA = 0; uint32_t dataLen = ((sizeof(ni_instance_mgr_stream_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if ((!p_ctx) || (!p_stream_info)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4014,7 +5292,7 @@ ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t if (! (NI_DEVICE_TYPE_DECODER == device_type || NI_DEVICE_TYPE_ENCODER == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4022,7 +5300,7 @@ ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4032,7 +5310,7 @@ ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4041,7 +5319,7 @@ ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, dataLen, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -4054,13 +5332,13 @@ ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t p_stream_info->frame_rate = ni_htons(p_stream_info->frame_rate); p_stream_info->is_flushed = ni_htons(p_stream_info->is_flushed); p_stream_info->transfer_frame_stride = ni_htons(p_stream_info->transfer_frame_stride); - ni_log(NI_LOG_DEBUG, "%s(): pix_format = %d\n", __func__, + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): pix_format = %d\n", __func__, p_stream_info->pix_format); //temp END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4084,6 +5362,7 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, { ni_retcode_t retval = NI_RETCODE_SUCCESS; void* p_buffer = NULL; + uint64_t session_timestamp; uint32_t ui32LBA = 0; uint32_t dataLen = ((sizeof(ni_session_stats_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; @@ -4091,11 +5370,11 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, (device_type != NI_DEVICE_TYPE_UPLOAD ? device_type : NI_DEVICE_TYPE_ENCODER); - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if ((!p_ctx) || (!p_session_stats)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4103,7 +5382,7 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, if (!IS_XCODER_DEVICE_TYPE(xc_device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4111,7 +5390,7 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4121,7 +5400,7 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4137,7 +5416,7 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, dataLen, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): read command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): read command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -4148,53 +5427,87 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, // all query commands are guaranteed success once a session is opened p_session_stats->ui16SessionId = ni_htons(p_session_stats->ui16SessionId); p_session_stats->ui16ErrorCount = ni_htons(p_session_stats->ui16ErrorCount); - p_session_stats->ui32LastTransactionId = ni_htons(p_session_stats->ui32LastTransactionId); - p_session_stats->ui32LastTransactionCompletionStatus = ni_htons(p_session_stats->ui32LastTransactionCompletionStatus); + p_session_stats->ui32LastTransactionId = + ni_htonl(p_session_stats->ui32LastTransactionId); + p_session_stats->ui32LastTransactionCompletionStatus = + ni_htonl(p_session_stats->ui32LastTransactionCompletionStatus); p_session_stats->ui32LastErrorTransactionId = ni_htonl(p_session_stats->ui32LastErrorTransactionId); p_session_stats->ui32LastErrorStatus = ni_htonl(p_session_stats->ui32LastErrorStatus); - p_session_stats->ui64Session_timestamp = - ni_htonll(p_session_stats->ui64Session_timestamp); + p_session_stats->ui32Session_timestamp_high = ni_htonl(p_session_stats->ui32Session_timestamp_high); + p_session_stats->ui32Session_timestamp_low = ni_htonl(p_session_stats->ui32Session_timestamp_low); + + session_timestamp = p_session_stats->ui32Session_timestamp_high; + session_timestamp <<= 32; + session_timestamp |= p_session_stats->ui32Session_timestamp_low; // get the session timestamp when open session // check the timestamp during transcoding - if ((p_ctx->session_timestamp != p_session_stats->ui64Session_timestamp) && + if ((p_ctx->session_timestamp != session_timestamp) && (ni_xcoder_resource_recovery != p_session_stats->ui32LastErrorStatus)) // if VPU recovery, the session timestamp will be reset. { p_session_stats->ui32LastErrorStatus = NI_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE; - ni_log(NI_LOG_DEBUG, "instance id invalid:%u, timestamp:%" PRIu64 - ", query timestamp:%" PRIu64 "\n", - p_ctx->session_id, p_ctx->session_timestamp, - p_session_stats->ui64Session_timestamp); + ni_log2(p_ctx, NI_LOG_DEBUG, "instance id invalid:%u, timestamp:%" PRIu64 ", " + "query timestamp:%" PRIu64 "\n", p_ctx->session_id, + p_ctx->session_timestamp, session_timestamp); } // check rc here, if rc != NI_RETCODE_SUCCESS, it means that last read/write command failed // failures may be link layer errors, such as physical link errors or ERROR_WRITE_PROTECT in windows. if (NI_RETCODE_SUCCESS != rc) { - ni_log(NI_LOG_ERROR, "%s():last command Failed: rc %d\n", __func__, rc); + ni_log2(p_ctx, NI_LOG_ERROR, "%s():last command Failed: rc %d\n", __func__, rc); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): session id %u ts %lu hw_id %d device_type %u codec_format %u frame_num %lu pkt_num %lu " + "ready_to_close %u session_run_state %d active_video_width %u active_video_height %u\n", + __func__, + p_ctx->session_id, + p_ctx->session_timestamp, + p_ctx->hw_id, + p_ctx->device_type, + p_ctx->codec_format, + p_ctx->frame_num, + p_ctx->pkt_num, + p_ctx->ready_to_close, + p_ctx->session_run_state, + p_ctx->active_video_width, + p_ctx->active_video_height); + +#if __linux__ || __APPLE__ +#ifndef _ANDROID +#ifndef DISABLE_BACKTRACE_PRINT + ni_print_backtrace(); // log backtrace +#endif +#endif +#endif + p_session_stats->ui32LastTransactionCompletionStatus = NI_RETCODE_ERROR_NVME_CMD_FAILED; p_session_stats->ui32LastErrorStatus = NI_RETCODE_ERROR_NVME_CMD_FAILED; retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } else if (p_ctx->session_id != p_session_stats->ui16SessionId) { - ni_log(NI_LOG_ERROR, - "%s():last command Failed because " - "session ID 0x%x is invalid\n", - __func__, p_ctx->session_id); + uint64_t ct = ni_gettime_ns(); + uint64_t dt = ct - p_ctx->last_access_time; + ni_log2(p_ctx, NI_LOG_ERROR, + "%s(): device 0x%" PRIx64 " last command Failed due to wrong " + "session ID. Expected 0x%x, got 0x%x keep alive last access " + "time %" PRIu64 ", current %" PRIu64 "\n", __func__, + (int64_t)p_ctx->blk_io_handle, p_ctx->session_id, + p_session_stats->ui16SessionId, p_ctx->last_access_time, ct); + if (dt > 1000000000) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "%s():long delay between last command dt = %" PRId64 " ns, " + "process was possibly blocked.\n", __func__, dt); + } p_session_stats->ui32LastErrorStatus = NI_RETCODE_ERROR_INVALID_SESSION; // Mark session id to INVALID so that all commands afterward are blocked p_ctx->session_id = NI_INVALID_SESSION_ID; - } else - { - // Acknowledge the total error count here - p_ctx->rc_error_count = p_session_stats->ui16ErrorCount; } - ni_log(NI_LOG_TRACE, "%s(): error count %u last rc 0x%x inst_err_no 0x%x\n", + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): error count %u last rc 0x%x inst_err_no 0x%x\n", __func__, p_session_stats->ui16ErrorCount, p_session_stats->ui32LastTransactionCompletionStatus, p_session_stats->ui32LastErrorStatus); @@ -4202,7 +5515,7 @@ ni_retcode_t ni_query_session_stats(ni_session_context_t *p_ctx, END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4225,11 +5538,11 @@ int ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_i uint32_t ui32LBA = 0; uint32_t dataLen = ((sizeof(ni_instance_mgr_stream_complete_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx || !p_stream_complete) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4238,7 +5551,7 @@ int ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_i if (! (NI_DEVICE_TYPE_DECODER == device_type || NI_DEVICE_TYPE_ENCODER == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4246,7 +5559,7 @@ int ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_i if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4256,7 +5569,7 @@ int ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_i if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR: Cannot allocate buffer.\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot allocate buffer.\n"); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } @@ -4265,7 +5578,7 @@ int ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_i if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, dataLen, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -4278,42 +5591,235 @@ int ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_i END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } +static const char* ni_get_device_type_str(int type) +{ + if (type < NI_DEVICE_TYPE_DECODER || type > NI_DEVICE_TYPE_AI) + { + return "Invalid device type"; + } + return g_device_type_str[type]; +} + +static void +ni_parse_session_statistic_info(ni_session_context_t *p_ctx, + ni_session_statistic_t *p_session_statistic, + void *p_buffer) +{ + memcpy((void *)p_session_statistic, p_buffer, + sizeof(ni_session_statistic_t)); + + //flip the bytes to host order + p_session_statistic->ui32RdBufAvailSize = + ni_htonl(p_session_statistic->ui32RdBufAvailSize); + p_session_statistic->ui32WrBufAvailSize = + ni_htonl(p_session_statistic->ui32WrBufAvailSize); + + p_session_statistic->ui32FramesInput = + ni_htonl(p_session_statistic->ui32FramesInput); + p_session_statistic->ui32FramesBuffered = + ni_htonl(p_session_statistic->ui32FramesBuffered); + p_session_statistic->ui32FramesCompleted = + ni_htonl(p_session_statistic->ui32FramesCompleted); + p_session_statistic->ui32FramesOutput = + ni_htonl(p_session_statistic->ui32FramesOutput); + p_session_statistic->ui32FramesDropped = + ni_htonl(p_session_statistic->ui32FramesDropped); + p_session_statistic->ui32InstErrors = + ni_htonl(p_session_statistic->ui32InstErrors); + + p_session_statistic->ui16SessionId = + ni_htons(p_session_statistic->ui16SessionId); + p_session_statistic->ui16ErrorCount = + ni_htons(p_session_statistic->ui16ErrorCount); + p_session_statistic->ui32LastTransactionId = + ni_htonl(p_session_statistic->ui32LastTransactionId); + p_session_statistic->ui32LastTransactionCompletionStatus = + ni_htonl(p_session_statistic->ui32LastTransactionCompletionStatus); + p_session_statistic->ui32LastErrorTransactionId = + ni_htonl(p_session_statistic->ui32LastErrorTransactionId); + p_session_statistic->ui32LastErrorStatus = + ni_htonl(p_session_statistic->ui32LastErrorStatus); + p_session_statistic->ui32Session_timestamp_high = + ni_htonl(p_session_statistic->ui32Session_timestamp_high); + p_session_statistic->ui32Session_timestamp_low = + ni_htonl(p_session_statistic->ui32Session_timestamp_low); + + // p_session_statistic->ui8AdditionalFramesDelay does not require endian conversion + + if (p_ctx->session_id != p_session_statistic->ui16SessionId) + { + uint64_t ct = ni_gettime_ns(); + uint64_t dt = ct - p_ctx->last_access_time; + ni_log2(p_ctx, NI_LOG_ERROR, + "%s(): %s device 0x%" PRIx64 " last command Failed due to wrong " + "session ID. Expected 0x%x, got 0x%x w_r <%u %u> keep alive " + "last access time %" PRIu64 ", current %" PRIu64 "\n", __func__, + ni_get_device_type_str(p_ctx->device_type), + (int64_t)p_ctx->device_handle, p_ctx->session_id, + p_session_statistic->ui16SessionId, + p_session_statistic->ui32WrBufAvailSize, + p_session_statistic->ui32RdBufAvailSize, p_ctx->last_access_time, + ct); + if (dt > 1000000000) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "%s():long delay between last command dt = %" PRId64 " ns, " + "process was possibly blocked.\n", __func__, dt); + } + p_session_statistic->ui32LastErrorStatus = + NI_RETCODE_ERROR_INVALID_SESSION; + //Mark session id to INVALID so that all commands afterward are blocked + p_ctx->session_id = NI_INVALID_SESSION_ID; + } else + { + //Acknowledge that total error count here + } + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): error count %u last rc 0x%x inst_err_no 0x%x\n", + __func__, p_session_statistic->ui16ErrorCount, + p_session_statistic->ui32LastTransactionCompletionStatus, + p_session_statistic->ui32LastErrorStatus); +} + /*!***************************************************************************** - * \brief Query a particular xcoder instance to get buffer/data Info data + * \brief Query a particular xcoder session to get session statistics * * \param ni_session_context_t p_ctx - xcoder Context - * \param ni_instance_buf_info_rw_type_t rw_type * \param ni_device_type_t device_type - xcoder type Encoder or Decoder - * \param ni_instance_buf_info_t *out - Struct preallocated from the caller + * \param ni_session_statistic_t*out - Struct preallocated from the caller * where the resulting data will be placed * * \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, * NI_RETCODE_ERROR_MEM_ALOC or NI_RETCODE_ERROR_NVME_CMD_FAILED on * failure ******************************************************************************/ -ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, - ni_instance_buf_info_rw_type_t rw_type, - ni_device_type_t device_type, - ni_instance_buf_info_t *p_inst_buf_info) +ni_retcode_t +ni_query_session_statistic_info(ni_session_context_t *p_ctx, + ni_device_type_t device_type, + ni_session_statistic_t *p_session_statistic) { - void* p_buffer = NULL; - ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t ui32LBA = 0; - uint32_t dataLen = - ((sizeof(ni_instance_buf_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / - NI_MEM_PAGE_ALIGNMENT) * - NI_MEM_PAGE_ALIGNMENT; + void *p_buffer = NULL; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + uint32_t dataLen = + ((sizeof(ni_session_statistic_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / + NI_MEM_PAGE_ALIGNMENT) * + NI_MEM_PAGE_ALIGNMENT; + + if (!p_ctx || !p_session_statistic) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() passed parameters are null!, return\n", __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "65") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() not supported on device with FW api version < 6.5\n", __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } + + if (!(NI_DEVICE_TYPE_DECODER == device_type || + NI_DEVICE_TYPE_ENCODER == device_type || + NI_DEVICE_TYPE_AI == device_type)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + __func__, device_type); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + ui32LBA = QUERY_INSTANCE_CUR_STATUS_INFO_R(p_ctx->session_id, device_type); + + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_buffer, 0, dataLen); + + // Set session ID to be invalid. In case, the last command fails because the invalid session ID was submitted + // with the command, the session id would remain invalid. + // If the Last command is processed successfully in session manager, the session id would become valid. + ((ni_session_statistic_t *)p_buffer)->ui16SessionId = + (uint16_t)NI_INVALID_SESSION_ID; + + if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, dataLen, ui32LBA) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): NVME command Failed\n", __func__); + p_session_statistic->ui32LastTransactionCompletionStatus = + NI_RETCODE_ERROR_NVME_CMD_FAILED; + p_session_statistic->ui32LastErrorStatus = + NI_RETCODE_ERROR_NVME_CMD_FAILED; + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + + ni_parse_session_statistic_info(p_ctx, p_session_statistic, p_buffer); + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + retval = NI_RETCODE_ERROR_INVALID_SESSION; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, %s return.\n", + __func__, ni_get_device_type_str(p_ctx->device_type)); + LRETURN; + } + p_ctx->session_statistic = *p_session_statistic; + +END: + ni_aligned_free(p_buffer); + ni_log2(p_ctx, NI_LOG_TRACE, "%s():exit\n", __func__); + + return retval; +} +/*!***************************************************************************** + * \brief Query a particular xcoder instance to get buffer/data Info data + * + * \param ni_session_context_t p_ctx - xcoder Context + * \param ni_instance_buf_info_rw_type_t rw_type + * \param ni_device_type_t device_type - xcoder type Encoder or Decoder + * \param ni_instance_buf_info_t *out - Struct preallocated from the caller + * where the resulting data will be placed + * + * \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, + * NI_RETCODE_ERROR_MEM_ALOC or NI_RETCODE_ERROR_NVME_CMD_FAILED on + * failure + ******************************************************************************/ +ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, + ni_instance_buf_info_rw_type_t rw_type, + ni_device_type_t device_type, + ni_instance_buf_info_t *p_inst_buf_info) +{ + void* p_buffer = NULL; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + uint32_t dataLen = + ((sizeof(ni_instance_buf_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / + NI_MEM_PAGE_ALIGNMENT) * + NI_MEM_PAGE_ALIGNMENT; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx || !p_inst_buf_info) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4324,7 +5830,7 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, NI_DEVICE_TYPE_SCALER == device_type || NI_DEVICE_TYPE_AI == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4332,7 +5838,7 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4346,6 +5852,19 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, { ui32LBA = QUERY_INSTANCE_WBUFF_SIZE_R(p_ctx->session_id, device_type); } + else if(INST_BUF_INFO_RW_WRITE_BY_EP == rw_type) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "65") >= 0) + { + ui32LBA = QUERY_INSTANCE_WBUFF_SIZE_R_BY_EP(p_ctx->session_id, device_type); + } + else + { + retval = NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + LRETURN; + } + } else if (INST_BUF_INFO_RW_UPLOAD == rw_type) { ui32LBA = QUERY_INSTANCE_UPLOAD_ID_R(p_ctx->session_id, device_type); @@ -4360,9 +5879,12 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, { ui32LBA = QUERY_INSTANCE_WBUFF_SIZE_BUSY_R(p_ctx->session_id, device_type); + } else if (INST_BUF_INFO_RW_READ_BY_AI == rw_type) + { + ui32LBA = QUERY_INSTANCE_AI_INFO_R(p_ctx->session_id, device_type); } else { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown query type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown query type %d, return\n", __func__, rw_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4370,7 +5892,7 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4380,7 +5902,7 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, dataLen, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -4392,7 +5914,7 @@ ni_retcode_t ni_query_instance_buf_info(ni_session_context_t *p_ctx, END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4422,11 +5944,11 @@ ni_retcode_t ni_config_session_rw(ni_session_context_t *p_ctx, uint32_t buffer_size = 0; ni_session_config_rw_t * rw_config = NULL; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4434,7 +5956,7 @@ ni_retcode_t ni_config_session_rw(ni_session_context_t *p_ctx, if (!((SESSION_READ_CONFIG == rw_type) || (SESSION_WRITE_CONFIG == rw_type))) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown config type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown config type %d, return\n", __func__, rw_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4443,7 +5965,7 @@ ni_retcode_t ni_config_session_rw(ni_session_context_t *p_ctx, buffer_size = ((sizeof(ni_session_config_rw_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), buffer_size)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4461,7 +5983,7 @@ ni_retcode_t ni_config_session_rw(ni_session_context_t *p_ctx, rw_config->uHWAccessField.ui16WriteFrameId = frame_id; break; default: - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown config type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown config type %d, return\n", __func__, rw_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4476,14 +5998,14 @@ ni_retcode_t ni_config_session_rw(ni_session_context_t *p_ctx, ui32LBA = CONFIG_SESSION_Write_W(p_ctx->session_id); break; default: - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown config type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown config type %d, return\n", __func__, rw_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, buffer_size, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } @@ -4491,7 +6013,7 @@ ni_retcode_t ni_config_session_rw(ni_session_context_t *p_ctx, END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4509,11 +6031,11 @@ ni_retcode_t ni_config_instance_sos(ni_session_context_t* p_ctx, ni_device_type_ ni_retcode_t retval = NI_RETCODE_SUCCESS; uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4522,7 +6044,7 @@ ni_retcode_t ni_config_instance_sos(ni_session_context_t* p_ctx, ni_device_type_ if (! (NI_DEVICE_TYPE_DECODER == device_type || NI_DEVICE_TYPE_ENCODER == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4530,7 +6052,7 @@ ni_retcode_t ni_config_instance_sos(ni_session_context_t* p_ctx, ni_device_type_ if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4540,13 +6062,13 @@ ni_retcode_t ni_config_instance_sos(ni_session_context_t* p_ctx, ni_device_type_ if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_ctx->p_all_zero_buf, NI_DATA_BUFFER_LEN, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4563,11 +6085,11 @@ ni_retcode_t ni_config_instance_eos(ni_session_context_t* p_ctx, ni_device_type_ ni_retcode_t retval = NI_RETCODE_SUCCESS; uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4576,7 +6098,7 @@ ni_retcode_t ni_config_instance_eos(ni_session_context_t* p_ctx, ni_device_type_ if (! (NI_DEVICE_TYPE_DECODER == device_type || NI_DEVICE_TYPE_ENCODER == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4584,7 +6106,7 @@ ni_retcode_t ni_config_instance_eos(ni_session_context_t* p_ctx, ni_device_type_ if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4594,13 +6116,13 @@ ni_retcode_t ni_config_instance_eos(ni_session_context_t* p_ctx, ni_device_type_ if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_ctx->p_all_zero_buf, NI_DATA_BUFFER_LEN, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4613,25 +6135,24 @@ ni_retcode_t ni_config_instance_eos(ni_session_context_t* p_ctx, ni_device_type_ * * \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, NI_RETCODE_ERROR_NVME_CMD_FAILED on failure *******************************************************************************/ -ni_retcode_t xcoder_config_instance_flush(ni_session_context_t* p_ctx, ni_device_type_t device_type) +ni_retcode_t ni_config_instance_flush(ni_session_context_t* p_ctx, ni_device_type_t device_type) { ni_retcode_t retval = NI_RETCODE_SUCCESS; uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } - if (! (NI_DEVICE_TYPE_DECODER == device_type || - NI_DEVICE_TYPE_ENCODER == device_type)) + if (NI_DEVICE_TYPE_DECODER != device_type) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4639,7 +6160,7 @@ ni_retcode_t xcoder_config_instance_flush(ni_session_context_t* p_ctx, ni_device if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4649,22 +6170,22 @@ ni_retcode_t xcoder_config_instance_flush(ni_session_context_t* p_ctx, ni_device retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_ctx->p_all_zero_buf, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); CHECK_VPU_RECOVERY(retval); +END: + if (NI_RETCODE_SUCCESS != retval) { retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed with %d\n", __func__, retval); } -END: - - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); - return retval; + return retval; } /*!****************************************************************************** @@ -4683,11 +6204,11 @@ ni_retcode_t ni_config_instance_set_write_len(ni_session_context_t* p_ctx, ni_de void * p_buffer = NULL; uint32_t buffer_size = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4696,7 +6217,7 @@ ni_retcode_t ni_config_instance_set_write_len(ni_session_context_t* p_ctx, ni_de if (!(NI_DEVICE_TYPE_DECODER == device_type || NI_DEVICE_TYPE_ENCODER == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Unknown device type %d, return\n", __func__, device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4704,7 +6225,7 @@ ni_retcode_t ni_config_instance_set_write_len(ni_session_context_t* p_ctx, ni_de if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4713,7 +6234,7 @@ ni_retcode_t ni_config_instance_set_write_len(ni_session_context_t* p_ctx, ni_de buffer_size = ((sizeof(len) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), buffer_size)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4725,14 +6246,14 @@ ni_retcode_t ni_config_instance_set_write_len(ni_session_context_t* p_ctx, ni_de if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, buffer_size, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4753,11 +6274,11 @@ ni_retcode_t ni_config_instance_set_sequence_change(ni_session_context_t* p_ctx, void * p_buffer = NULL; uint32_t buffer_size = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4765,14 +6286,14 @@ ni_retcode_t ni_config_instance_set_sequence_change(ni_session_context_t* p_ctx, if (!(NI_DEVICE_TYPE_ENCODER == device_type)) { - ni_log(NI_LOG_ERROR, "ERROR: Seq Change not supported for device type %d, return\n", device_type); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Seq Change not supported for device type %d, return\n", device_type); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4781,7 +6302,7 @@ ni_retcode_t ni_config_instance_set_sequence_change(ni_session_context_t* p_ctx, buffer_size = ((sizeof(ni_resolution_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), buffer_size)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4793,14 +6314,14 @@ ni_retcode_t ni_config_instance_set_sequence_change(ni_session_context_t* p_ctx, if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_buffer, buffer_size, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } END: ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4818,13 +6339,12 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) ni_encoder_config_t* p_cfg = NULL; uint32_t buffer_size = sizeof(ni_encoder_config_t); ni_retcode_t retval = NI_RETCODE_SUCCESS; - int i = 0; uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4832,7 +6352,7 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -4841,7 +6361,7 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; if (ni_posix_memalign(&p_encoder_config, sysconf(_SC_PAGESIZE), buffer_size)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -4852,12 +6372,12 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) retval = ni_validate_custom_template(p_ctx, p_encoder_config, p_ctx->p_session_config, p_ctx->param_err_msg, sizeof(p_ctx->param_err_msg)); if (NI_RETCODE_PARAM_WARN == retval) { - ni_log(NI_LOG_INFO, "WARNING: ni_validate_custom_template() . %s\n", p_ctx->param_err_msg); + ni_log2(p_ctx, NI_LOG_INFO, "WARNING: ni_validate_custom_template() . %s\n", p_ctx->param_err_msg); fflush(stdout); } else if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: ni_validate_custom_dec_template() failed. %s\n", p_ctx->param_err_msg); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_validate_custom_template() failed. %s\n", p_ctx->param_err_msg); fflush(stdout); retval = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -4865,7 +6385,7 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) //configure the session here ui32LBA = CONFIG_INSTANCE_SetEncPara_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); - //Flip the bytes!! + //Flip the bytes!! any param 16bits in size need ni_htons, 32bit need ni_htonl p_cfg = (ni_encoder_config_t*)p_encoder_config; p_cfg->i32picWidth = ni_htonl(p_cfg->i32picWidth); p_cfg->i32picHeight = ni_htonl(p_cfg->i32picHeight); @@ -4893,25 +6413,32 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) p_cfg->i32tolCtbRcInter = ni_htonl(p_cfg->i32tolCtbRcInter); p_cfg->i32tolCtbRcIntra = ni_htonl(p_cfg->i32tolCtbRcIntra); p_cfg->i16bitrateWindow = ni_htons(p_cfg->i16bitrateWindow); - // flip the NI_MAX_VUI_SIZE bytes of the VUI field using 32 bits pointers - for (i = 0 ; i < (NI_MAX_VUI_SIZE >> 2) ; i++) // apply on 32 bits - { - ((uint32_t*)p_cfg->ui8VuiRbsp)[i] = ni_htonl(((uint32_t*)p_cfg->ui8VuiRbsp)[i]); - } + p_cfg->ui16hdr10_dx0 = ni_htons(p_cfg->ui16hdr10_dx0); + p_cfg->ui16hdr10_dy0 = ni_htons(p_cfg->ui16hdr10_dy0); + p_cfg->ui16hdr10_dx1 = ni_htons(p_cfg->ui16hdr10_dx1); + p_cfg->ui16hdr10_dy1 = ni_htons(p_cfg->ui16hdr10_dy1); + p_cfg->ui16hdr10_dx2 = ni_htons(p_cfg->ui16hdr10_dx2); + p_cfg->ui16hdr10_dy2 = ni_htons(p_cfg->ui16hdr10_dy2); + p_cfg->ui16hdr10_wx = ni_htons(p_cfg->ui16hdr10_wx); + p_cfg->ui16hdr10_wy = ni_htons(p_cfg->ui16hdr10_wy); + p_cfg->ui32hdr10_maxluma = ni_htonl(p_cfg->ui32hdr10_maxluma); + p_cfg->ui32hdr10_minluma = ni_htonl(p_cfg->ui32hdr10_minluma); + p_cfg->ui32lumaLinesize = ni_htons(p_cfg->ui32lumaLinesize); + p_cfg->ui32chromaLinesize = ni_htons(p_cfg->ui32chromaLinesize); retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_encoder_config, buffer_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + &(p_ctx->session_id), OPT_1); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); //Close the session since we can't configure it retval = ni_encoder_session_close(p_ctx, 0); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: ni_encoder_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_encoder_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); } retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; @@ -4920,7 +6447,7 @@ ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx) END: ni_aligned_free(p_encoder_config); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } @@ -4939,18 +6466,18 @@ ni_retcode_t ni_config_instance_set_encoder_frame_params(ni_session_context_t* p ni_retcode_t retval = NI_RETCODE_SUCCESS; uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx || !p_params) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); return NI_RETCODE_INVALID_PARAM; } if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); return NI_RETCODE_ERROR_INVALID_SESSION; } @@ -4958,7 +6485,7 @@ ni_retcode_t ni_config_instance_set_encoder_frame_params(ni_session_context_t* p buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; if (ni_posix_memalign((void **)&p_cfg, sysconf(_SC_PAGESIZE), buffer_size)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", NI_ERRNO, __func__); return NI_RETCODE_ERROR_MEM_ALOC; } @@ -4977,143 +6504,23 @@ ni_retcode_t ni_config_instance_set_encoder_frame_params(ni_session_context_t* p if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_cfg, buffer_size, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %d, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - //Close the session since we can't configure it as per Farhan + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %d, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + //Close the session since we can't configure it retval = ni_encoder_session_close(p_ctx, 0); if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR: ni_encoder_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %d, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_encoder_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %d, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); } retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; } ni_aligned_free(p_cfg); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } -#if 0 // ndef QUADRA_SEI_FMT -// return non-0 if SEI of requested type is found, 0 otherwise -static int find_sei(uint32_t sei_header, ni_sei_user_data_entry_t *pEntry, - ni_h265_sei_user_data_type_t type, - uint32_t *pSeiOffset, uint32_t *pSeiSize) -{ - int ret = 0; - - - if( (!pEntry) || (!pSeiOffset) || (!pSeiSize) ) - { - return ret; - } - - - if (sei_header & (1 << type)) - { - *pSeiOffset = pEntry[type].offset; - *pSeiSize = pEntry[type].size; - ni_log(NI_LOG_DEBUG, "find_sei sei type %d, offset: %u size: %u\n", - type, *pSeiOffset, *pSeiSize); - ret = 1; - } - - return ret; -} - -// return non-0 if prefix or suffix T.35 message is found -static int find_prefix_suffix_t35(uint32_t sei_header, - ni_t35_sei_mesg_type_t t35_type, - ni_sei_user_data_entry_t *pEntry, - ni_h265_sei_user_data_type_t type, - uint32_t *pCcOffset, uint32_t *pCcSize) -{ - int ret = 0; - uint8_t *ptr; - - - if( (!pEntry) || (!pCcOffset) || (!pCcSize) ) - { - return ret; - } - - - // Find first t35 message with CEA708 close caption (first 7 - // bytes are itu_t_t35_country_code 0xB5 0x00 (181), - // itu_t_t35_provider_code = 0x31 (49), - // ATSC_user_identifier = 0x47 0x41 0x39 0x34 ("GA94") - // or HDR10+ header bytes - if (sei_header & (1 << type)) - { - ptr = (uint8_t*)pEntry + pEntry[type].offset; - if (NI_T35_SEI_CLOSED_CAPTION == t35_type && - ptr[0] == NI_CC_SEI_BYTE0 && ptr[1] == NI_CC_SEI_BYTE1 && - ptr[2] == NI_CC_SEI_BYTE2 && ptr[3] == NI_CC_SEI_BYTE3 && - ptr[4] == NI_CC_SEI_BYTE4 && ptr[5] == NI_CC_SEI_BYTE5 && - ptr[6] == NI_CC_SEI_BYTE6) - { - *pCcOffset = pEntry[type].offset; - *pCcSize = pEntry[type].size; - ni_log(NI_LOG_DEBUG, "find_prefix_suffix_t35: close Caption SEI found in T.35 type %d, offset: %u size: %u\n", type, *pCcOffset, *pCcSize); - ret = 1; - } - else if (NI_T35_SEI_HDR10_PLUS == t35_type && - ptr[0] == NI_HDR10P_SEI_BYTE0 && ptr[1] == NI_HDR10P_SEI_BYTE1 && - ptr[2] == NI_HDR10P_SEI_BYTE2 && ptr[3] == NI_HDR10P_SEI_BYTE3 && - ptr[4] == NI_HDR10P_SEI_BYTE4 && ptr[5] == NI_HDR10P_SEI_BYTE5 && - ptr[6] == NI_HDR10P_SEI_BYTE6) - { - *pCcOffset = pEntry[type].offset; - *pCcSize = pEntry[type].size; - ni_log(NI_LOG_DEBUG, "find_prefix_suffix_t35: HDR10+ SEI found in T.35 type %d, offset: %u size: %u\n", type, *pCcOffset, *pCcSize); - ret = 1; - } - } - - return ret; -} - -// return non-0 when HDR10+/close-caption is found, 0 otherwise -static int find_t35_sei(uint32_t sei_header, ni_t35_sei_mesg_type_t t35_type, - ni_sei_user_data_entry_t *pEntry, - uint32_t *pCcOffset, uint32_t *pCcSize) -{ - int ret = 0; - - if( (!pEntry) || (!pCcOffset) || (!pCcSize) ) - { - return ret; - } - - *pCcOffset = *pCcSize = 0; - - // Check up to 3 T35 Prefix and Suffix SEI for close captions - if (find_prefix_suffix_t35(sei_header, t35_type, pEntry, - NI_H265_USERDATA_FLAG_ITU_T_T35_PRE, - pCcOffset, pCcSize) || - find_prefix_suffix_t35(sei_header, t35_type, pEntry, - NI_H265_USERDATA_FLAG_ITU_T_T35_PRE_1, - pCcOffset, pCcSize) || - find_prefix_suffix_t35(sei_header, t35_type, pEntry, - NI_H265_USERDATA_FLAG_ITU_T_T35_PRE_2, - pCcOffset, pCcSize) || - find_prefix_suffix_t35(sei_header, t35_type, pEntry, - NI_H265_USERDATA_FLAG_ITU_T_T35_SUF, - pCcOffset, pCcSize) || - find_prefix_suffix_t35(sei_header, t35_type, pEntry, - NI_H265_USERDATA_FLAG_ITU_T_T35_SUF_1, - pCcOffset, pCcSize) || - find_prefix_suffix_t35(sei_header, t35_type, pEntry, - NI_H265_USERDATA_FLAG_ITU_T_T35_SUF_2, - pCcOffset, pCcSize) - ) - { - ret = 1; - } - return ret; -} -#endif // QUADRA_SEI_FMT - /*!****************************************************************************** * \brief Get info from received p_frame * @@ -5384,6 +6791,16 @@ int ni_create_frame(ni_frame_t* p_frame, uint32_t read_length, uint64_t* p_frame } break; + case 200: // Custom SEI not included in HEVC_SEI_Type + if (ui32Size) + { + p_frame->vui_len = ui32Size; + p_frame->vui_offset = + video_data_size + metadata_size + ui32Offset; + p_frame->sei_total_len += ui32Size; + } + break; + default: ni_log(NI_LOG_ERROR, "Error %s: SEI message dropped (unsupported - check " @@ -5582,7 +6999,58 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p if ((p_id_data->ui16Vid != NETINT_PCI_VENDOR_ID) || (p_id_data->ui16Ssvid != NETINT_PCI_VENDOR_ID)) { - LRETURN; + if (g_device_in_ctxt) + { + ni_log(NI_LOG_ERROR, + "ERROR: Previously in context device got an invalid vendor ID 0x%X SSVID 0x%X. Netint " + "ID 0x%X. Retrying\n", + p_id_data->ui16Vid, p_id_data->ui16Ssvid, NETINT_PCI_VENDOR_ID); + //print some other fields as a test to see if they are invalid too + ni_log(NI_LOG_ERROR, "Model Number: %.*s\n", + (int)sizeof(p_id_data->ai8Sn), p_id_data->ai8Sn); + ni_log(NI_LOG_ERROR, "Serial Number: %.*s\n", + (int)sizeof(p_id_data->ai8Mn), p_id_data->ai8Mn); + ni_log(NI_LOG_ERROR, "Firmware Revision: %.*s\n", + (int)sizeof(p_id_data->ai8Fr), p_id_data->ai8Fr); + ni_log(NI_LOG_ERROR, "xcoder_num_elements: %d\n", + p_id_data->xcoder_num_elements); + + ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; + uint32_t ui32LBA = IDENTIFY_DEVICE_R; + if (ni_nvme_send_read_cmd(g_dev_handle, event_handle, p_data, + NI_NVME_IDENTITY_CMD_DATA_SZ, ui32LBA) < 0) + { + LRETURN; + } + if ((p_id_data->ui16Vid != NETINT_PCI_VENDOR_ID) || + (p_id_data->ui16Ssvid != NETINT_PCI_VENDOR_ID)) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Retry got an invalid vendor ID too 0x%X SSVID " + "0x%X!\n", + __func__, p_id_data->ui16Vid, p_id_data->ui16Ssvid); + //print some other fields as a test to see if they are invalid too + ni_log(NI_LOG_ERROR, "Model Number: %.*s\n", + (int)sizeof(p_id_data->ai8Sn), p_id_data->ai8Sn); + ni_log(NI_LOG_ERROR, "Serial Number: %.*s\n", + (int)sizeof(p_id_data->ai8Mn), p_id_data->ai8Mn); + ni_log(NI_LOG_ERROR, "Firmware Revision: %.*s\n", + (int)sizeof(p_id_data->ai8Fr), p_id_data->ai8Fr); + ni_log(NI_LOG_ERROR, "xcoder_num_elements: %d\n", + p_id_data->xcoder_num_elements); + LRETURN; + } + else + { + ni_log(NI_LOG_ERROR, + "Retry got valid a vendor ID 0x%X SSVID 0x%X. Netint ID 0x%X\n", + p_id_data->ui16Vid, p_id_data->ui16Ssvid, NETINT_PCI_VENDOR_ID); + } + } + else + { + LRETURN; + } } memcpy(p_cap->serial_number, p_id_data->ai8Sn, sizeof(p_cap->serial_number)); @@ -5621,17 +7089,20 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p LRETURN; } - p_cap->device_is_xcoder = NI_XCODER_QUADRA; // data format version 2 + p_cap->device_is_xcoder = NI_XCODER_QUADRA; p_cap->hw_elements_cnt = p_id_data->xcoder_num_elements; p_cap->xcoder_devices_cnt = p_id_data->xcoder_num_devices; memcpy(p_cap->xcoder_cnt, p_id_data->xcoder_cnt, NI_DEVICE_TYPE_XCODER_MAX * sizeof(p_id_data->xcoder_cnt[0])); - for (i = 0; i < total_modules; i++) + for (i = NI_DEVICE_TYPE_DECODER; i < NI_DEVICE_TYPE_XCODER_MAX; i++) { + if (!p_id_data->xcoder_cnt[i]) + continue; + p_cap->xcoder_devices[i].hw_id = p_id_data->xcoder_devices[i].hw_id; p_cap->xcoder_devices[i].max_number_of_contexts = - NI_MAX_CONTEXTS_PER_HW_INSTANCE; + p_id_data->xcoder_devices[i].hw_max_number_of_contexts; p_cap->xcoder_devices[i].max_4k_fps = NI_MAX_4K_FPS_QUADRA; p_cap->xcoder_devices[i].codec_format = p_id_data->xcoder_devices[i].hw_codec_format; @@ -5639,8 +7110,17 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p p_id_data->xcoder_devices[i].hw_codec_type; p_cap->xcoder_devices[i].max_video_width = NI_PARAM_MAX_WIDTH; p_cap->xcoder_devices[i].max_video_height = NI_PARAM_MAX_HEIGHT; - p_cap->xcoder_devices[i].min_video_width = NI_PARAM_MIN_WIDTH; - p_cap->xcoder_devices[i].min_video_height = NI_PARAM_MIN_HEIGHT; + if (i == NI_DEVICE_TYPE_ENCODER) + { + p_cap->xcoder_devices[i].min_video_width = NI_ENC_MIN_RESOLUTION_WIDTH; + p_cap->xcoder_devices[i].min_video_height = NI_ENC_MIN_RESOLUTION_HEIGHT; + } + else + { + p_cap->xcoder_devices[i].min_video_width = NI_MIN_RESOLUTION_WIDTH; + p_cap->xcoder_devices[i].min_video_height = NI_MIN_RESOLUTION_HEIGHT; + } + p_cap->xcoder_devices[i].video_profile = p_id_data->xcoder_devices[i].hw_video_profile; p_cap->xcoder_devices[i].video_level = @@ -5655,7 +7135,15 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p p_cap->device_is_xcoder); if (0 == p_cap->device_is_xcoder) { - LRETURN; + ni_log(NI_LOG_ERROR, "Not an xcoder device !\n"); + + if (g_device_in_ctxt) + { + ni_log(NI_LOG_ERROR, + "ERROR: Previously in context device is not a xcoder device " + "now!\n"); + } + LRETURN; } p_cap->hw_elements_cnt = p_id_data->xcoder_num_hw; @@ -5682,8 +7170,8 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p p_cap->xcoder_devices[0].codec_type = p_id_data->hw0_codec_type; p_cap->xcoder_devices[0].max_video_width = NI_PARAM_MAX_WIDTH; p_cap->xcoder_devices[0].max_video_height = NI_PARAM_MAX_HEIGHT; - p_cap->xcoder_devices[0].min_video_width = NI_PARAM_MIN_WIDTH; - p_cap->xcoder_devices[0].min_video_height = NI_PARAM_MIN_HEIGHT; + p_cap->xcoder_devices[0].min_video_width = NI_MIN_RESOLUTION_WIDTH; + p_cap->xcoder_devices[0].min_video_height = NI_MIN_RESOLUTION_HEIGHT; p_cap->xcoder_devices[0].video_profile = p_id_data->hw0_video_profile; p_cap->xcoder_devices[0].video_level = p_id_data->hw0_video_level; } @@ -5697,8 +7185,8 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p p_cap->xcoder_devices[1].codec_type = p_id_data->hw1_codec_type; p_cap->xcoder_devices[1].max_video_width = NI_PARAM_MAX_WIDTH; p_cap->xcoder_devices[1].max_video_height = NI_PARAM_MAX_HEIGHT; - p_cap->xcoder_devices[1].min_video_width = NI_PARAM_MIN_WIDTH; - p_cap->xcoder_devices[1].min_video_height = NI_PARAM_MIN_HEIGHT; + p_cap->xcoder_devices[1].min_video_width = NI_ENC_MIN_RESOLUTION_WIDTH; + p_cap->xcoder_devices[1].min_video_height = NI_ENC_MIN_RESOLUTION_HEIGHT; p_cap->xcoder_devices[1].video_profile = p_id_data->hw1_video_profile; p_cap->xcoder_devices[1].video_level = p_id_data->hw1_video_level; } @@ -5712,8 +7200,8 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p p_cap->xcoder_devices[2].codec_type = p_id_data->hw2_codec_type; p_cap->xcoder_devices[2].max_video_width = NI_PARAM_MAX_WIDTH; p_cap->xcoder_devices[2].max_video_height = NI_PARAM_MAX_HEIGHT; - p_cap->xcoder_devices[2].min_video_width = NI_PARAM_MIN_WIDTH; - p_cap->xcoder_devices[2].min_video_height = NI_PARAM_MIN_HEIGHT; + p_cap->xcoder_devices[2].min_video_width = NI_MIN_RESOLUTION_WIDTH; + p_cap->xcoder_devices[2].min_video_height = NI_MIN_RESOLUTION_HEIGHT; p_cap->xcoder_devices[2].video_profile = p_id_data->hw2_video_profile; p_cap->xcoder_devices[2].video_level = p_id_data->hw2_video_level; } @@ -5727,8 +7215,8 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void* p p_cap->xcoder_devices[3].codec_type = p_id_data->hw3_codec_type; p_cap->xcoder_devices[3].max_video_width = NI_PARAM_MAX_WIDTH; p_cap->xcoder_devices[3].max_video_height = NI_PARAM_MAX_HEIGHT; - p_cap->xcoder_devices[3].min_video_width = NI_PARAM_MIN_WIDTH; - p_cap->xcoder_devices[3].min_video_height = NI_PARAM_MIN_HEIGHT; + p_cap->xcoder_devices[3].min_video_width = NI_MIN_RESOLUTION_WIDTH; + p_cap->xcoder_devices[3].min_video_height = NI_MIN_RESOLUTION_HEIGHT; p_cap->xcoder_devices[3].video_profile = p_id_data->hw3_video_profile; p_cap->xcoder_devices[3].video_level = p_id_data->hw3_video_level; } @@ -5851,13 +7339,14 @@ void ni_set_custom_dec_template(ni_session_context_t *p_ctx, uint32_t max_pkt_size) { int i,j; - ni_decoder_input_params_t* p_dec = &p_src->dec_input_params; + ni_decoder_input_params_t* p_dec = NULL; if ((!p_ctx) || (!p_cfg) || (!p_src)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", - __func__); - return; + ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", + __func__); + return; } + p_dec = &p_src->dec_input_params; int w = p_src->source_width; int h = p_src->source_height; bool shift_params = false; @@ -5866,13 +7355,18 @@ void ni_set_custom_dec_template(ni_session_context_t *p_ctx, p_cfg->ui8MCMode = p_dec->mcmode; p_cfg->ui8UduSeiEnabled = p_ctx->enable_user_data_sei_passthru; p_cfg->ui16MaxSeiDataSize = NI_MAX_SEI_DATA; + p_cfg->ui8DisablePictureReordering = p_dec->decoder_low_delay > 0; + p_ctx->force_low_delay = p_dec->force_low_delay; + p_cfg->ui8EnablelowDelayCheck = p_dec->enable_low_delay_check == 1; + p_cfg->ui32SourceWidth = w; + p_cfg->ui32SourceHeight = h; if (max_pkt_size) { p_cfg->ui32MaxPktSize = max_pkt_size; } else { // p_cfg->ui32MaxPktSize = width x height x 3/2 x min compression ratio(QP=0); - // temp: set min compression ratio = 1/2, so MaxPktSize = w * h * 3/4 + // set min compression ratio = 1/2, so MaxPktSize = w * h * 3/4 p_cfg->ui32MaxPktSize = w * h * 3 / 4; } // packet buffer aligned to NI_MAX_PACKET_SZ(128k) @@ -5882,7 +7376,9 @@ void ni_set_custom_dec_template(ni_session_context_t *p_ctx, p_cfg->fps_number = ((ni_xcoder_params_t *)p_ctx->p_session_config)->fps_number; p_cfg->fps_denominator = - ((ni_xcoder_params_t *)p_ctx->p_session_config)->fps_denominator, + ((ni_xcoder_params_t *)p_ctx->p_session_config)->fps_denominator; + ni_log2(p_ctx, NI_LOG_INFO, "%s height %d width %d fps_number %d fps_denominator %d\n", + __func__, h, w, p_cfg->fps_number, p_cfg->fps_denominator); p_cfg->asOutputConfig[0].ui8Enabled = 1; // always enabled p_cfg->asOutputConfig[1].ui8Enabled = p_dec->enable_out1; @@ -5892,7 +7388,7 @@ void ni_set_custom_dec_template(ni_session_context_t *p_ctx, p_cfg->asOutputConfig[1].ui8Enabled = 1; p_cfg->asOutputConfig[2].ui8Enabled = 0; shift_params = true; - ni_log(NI_LOG_DEBUG, "Output 2 used before output 1, Shifting output2 settings to output1 and disabling output 2\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "Output 2 used before output 1, Shifting output2 settings to output1 and disabling output 2\n"); } for (i = 0; i < NI_MAX_NUM_OF_DECODER_OUTPUTS; i++) @@ -5927,10 +7423,50 @@ void ni_set_custom_dec_template(ni_session_context_t *p_ctx, p_cfg->asOutputConfig[i].sCroppingRectable.ui16Y = h - p_cfg->asOutputConfig[i].sCroppingRectable.ui16H; } + if (p_dec->enable_ppu_scale_adapt) + { + p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt = p_dec->enable_ppu_scale_adapt; + } + else if (p_dec->scale_long_short_edge[j] == 1) + { + p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt = 3; + } + else if (p_dec->scale_long_short_edge[j] == 2) + { + p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt = 4; + } + else + { + p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt = 0; + } + p_cfg->asOutputConfig[i].ui8EnablePpuScaleLimit = p_dec->enable_ppu_scale_limit; + + if (p_dec->scale_round[j] == -1) + { + if (p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt == 1 || + p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt == 2) + { + p_cfg->asOutputConfig[i].ui8ScaleResCeil = p_dec->scale_resolution_ceil[j] - 1; + } + else + { + p_cfg->asOutputConfig[i].ui8ScaleResCeil = p_dec->scale_resolution_ceil[j]; + } + } + else if (p_dec->scale_round[j] == 0) + { + p_cfg->asOutputConfig[i].ui8ScaleResCeil = p_dec->scale_resolution_ceil[j]; + } + else + { + p_cfg->asOutputConfig[i].ui8ScaleResCeil = p_dec->scale_resolution_ceil[j] - 1; + } + p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width = (uint16_t)((p_dec->scale_wh[j][0]+1) & 0xFFFE); p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height = (uint16_t)((p_dec->scale_wh[j][1]+1) & 0xFFFE); + if (p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width || p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height) { @@ -5940,32 +7476,65 @@ void ni_set_custom_dec_template(ni_session_context_t *p_ctx, { p_cfg->asOutputConfig[i].ui8ScaleEnabled = 0; } + + if (p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt == 0 && + p_cfg->asOutputConfig[i].ui8EnablePpuScaleLimit == 1) + { + ni_log2(p_ctx, NI_LOG_ERROR, "WARN: set ui8EnablePpuScaleLimit to 0 when ui8EnablePpuScaleAdapt is disabled.\n"); + p_cfg->asOutputConfig[i].ui8EnablePpuScaleLimit = 0; + } + } + + p_cfg->ui8MaxExtraHwFrameCnt = p_dec->max_extra_hwframe_cnt; + if (p_cfg->ui8MaxExtraHwFrameCnt != 255 && + ni_cmp_fw_api_ver((char *)&p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6rB") < 0) + { + ni_log2(p_ctx, NI_LOG_INFO, "Warning %s(): maxExtraHwFrameCnt is not support for FW < 6rB\n", __func__); + } + p_cfg->ui8EcPolicy = p_dec->ec_policy; + p_cfg->ui8EnableAdvancedEc = p_dec->enable_advanced_ec; + if (p_cfg->ui8EnableAdvancedEc == 2 && + ni_cmp_fw_api_ver((char *)&p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6rO") < 0) + { + ni_log2(p_ctx, NI_LOG_INFO, "Warning %s(): (enableAdvancedEc == 2) is not support for FW < 6rO\n", __func__); + p_cfg->ui8EnableAdvancedEc = 1; + ni_log2(p_ctx, NI_LOG_INFO, "Warning %s(): reset enableAdvancedEc to %d\n", __func__, p_cfg->ui8EnableAdvancedEc); } + p_cfg->ui8DisableAdaptiveBuffers = p_dec->disable_adaptive_buffers; //print it all out - ni_log(NI_LOG_DEBUG, "ui8HWFrame = %d\n", p_cfg->ui8HWFrame); - ni_log(NI_LOG_DEBUG, "ui8MCMode = %d\n", p_cfg->ui8MCMode); - ni_log(NI_LOG_DEBUG, "ui8UduSeiEnabled = %d\n", p_cfg->ui8UduSeiEnabled); - ni_log(NI_LOG_DEBUG, "ui16MaxSeiDataSize = %d\n", p_cfg->ui16MaxSeiDataSize); - ni_log(NI_LOG_DEBUG, "ui8Enabled0 = %d\n", p_cfg->asOutputConfig[0].ui8Enabled); - ni_log(NI_LOG_DEBUG, "ui8Enabled1 = %d\n", p_cfg->asOutputConfig[1].ui8Enabled); - ni_log(NI_LOG_DEBUG, "ui8Enabled2 = %d\n", p_cfg->asOutputConfig[2].ui8Enabled); - ni_log(NI_LOG_DEBUG, "ui32MaxPktSize = %u\n", p_cfg->ui32MaxPktSize); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8HWFrame = %d\n", p_cfg->ui8HWFrame); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8MCMode = %d\n", p_cfg->ui8MCMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8UduSeiEnabled = %d\n", p_cfg->ui8UduSeiEnabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16MaxSeiDataSize = %d\n", p_cfg->ui16MaxSeiDataSize); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8DisablePictureReordering = %d\n", p_cfg->ui8DisablePictureReordering); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8Enabled0 = %d\n", p_cfg->asOutputConfig[0].ui8Enabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8Enabled1 = %d\n", p_cfg->asOutputConfig[1].ui8Enabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8Enabled2 = %d\n", p_cfg->asOutputConfig[2].ui8Enabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32MaxPktSize = %u\n", p_cfg->ui32MaxPktSize); for (i = 0; i < NI_MAX_NUM_OF_DECODER_OUTPUTS; i++) { - ni_log(NI_LOG_DEBUG, "[%d] ui8Force8Bit %d\n", i, p_cfg->asOutputConfig[i].ui8Force8Bit); - ni_log(NI_LOG_DEBUG, "[%d] ui8SemiPlanarEnabled %d\n", i, p_cfg->asOutputConfig[i].ui8SemiPlanarEnabled); - ni_log(NI_LOG_DEBUG, "[%d] ui8CropMode %d\n", i, p_cfg->asOutputConfig[i].ui8CropMode); - ni_log(NI_LOG_DEBUG, "[%d] sCroppingRectable.ui16XYWH %d,%d - %d x %d\n", i, + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8Force8Bit %d\n", i, p_cfg->asOutputConfig[i].ui8Force8Bit); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8SemiPlanarEnabled %d\n", i, p_cfg->asOutputConfig[i].ui8SemiPlanarEnabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8CropMode %d\n", i, p_cfg->asOutputConfig[i].ui8CropMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] sCroppingRectable.ui16XYWH %d,%d - %d x %d\n", i, p_cfg->asOutputConfig[i].sCroppingRectable.ui16X, p_cfg->asOutputConfig[i].sCroppingRectable.ui16Y, p_cfg->asOutputConfig[i].sCroppingRectable.ui16W, p_cfg->asOutputConfig[i].sCroppingRectable.ui16H); - ni_log(NI_LOG_DEBUG, "[%d] sOutputPictureSize.ui16Width x height %d x %d\n", i, + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] sOutputPictureSize.ui16Width x height %d x %d\n", i, p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width, p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height); - ni_log(NI_LOG_DEBUG, "[%d] ui8ScaleEnabled %d\n", i, p_cfg->asOutputConfig[i].ui8ScaleEnabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8ScaleEnabled %d\n", i, p_cfg->asOutputConfig[i].ui8ScaleEnabled); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8EnablePpuScaleAdapt %u\n", i, p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8EnablePpuScaleLimit %u\n", i, p_cfg->asOutputConfig[i].ui8EnablePpuScaleLimit); + ni_log2(p_ctx, NI_LOG_DEBUG, "[%d] ui8ScaleResCeil %u\n", i, p_cfg->asOutputConfig[i].ui8ScaleResCeil); } + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8MaxExtraHwFrameCnt %u\n", p_cfg->ui8MaxExtraHwFrameCnt); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8EcPolicy = %u\n", p_cfg->ui8EcPolicy); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8EnableAdvancedEc = %u\n", p_cfg->ui8EnableAdvancedEc); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8EnablelowDelayCheck = %u\n", p_cfg->ui8EnablelowDelayCheck); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8DisableAdaptiveBuffers = %u\n", p_cfg->ui8DisableAdaptiveBuffers); } @@ -5981,38 +7550,74 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, ni_encoder_config_t *p_cfg, ni_xcoder_params_t *p_src) { - - ni_t408_config_t* p_t408 = &(p_cfg->niParamT408); - ni_encoder_cfg_params_t *p_enc = &p_src->cfg_enc_params; + ni_t408_config_t* p_t408 = NULL; + ni_encoder_cfg_params_t *p_enc = NULL; int i = 0; if ((!p_ctx) || (!p_cfg) || (!p_src)) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", - __func__); - return; + ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", + __func__); + return; } + p_t408 = &(p_cfg->niParamT408); + p_enc = &p_src->cfg_enc_params; ni_set_default_template(p_ctx, p_cfg); - p_cfg->i32picWidth = p_src->source_width; - p_cfg->i32picHeight = p_src->source_height; - p_t408->gop_preset_index = p_enc->gop_preset_index; - p_t408->use_recommend_enc_params = p_enc->use_recommend_enc_params; - p_t408->cu_size_mode = p_enc->cu_size_mode; - p_t408->max_num_merge = p_enc->max_num_merge; + p_cfg->i32picWidth = p_src->source_width; + p_cfg->i32picHeight = p_src->source_height; + p_t408->tier = p_enc->high_tier; + p_t408->gop_preset_index = p_enc->gop_preset_index; + p_t408->use_recommend_enc_params = p_enc->use_recommend_enc_params; + p_t408->cu_size_mode = p_enc->cu_size_mode; + p_t408->max_num_merge = p_enc->max_num_merge; + p_cfg->ui8AiEnhanceMode = p_src->enable_ai_enhance; + p_cfg->ui8enable2PassGopPatern = p_src->enable2PassGop; + // enhance_level is in range [1,3] set level when paramters is valid, otherwise make it to 1. + if(p_cfg->ui8AiEnhanceMode && p_src->ai_enhance_level > 0 && p_src->ai_enhance_level < 4){ + p_cfg->ui8AiEnhanceLevel = p_src->ai_enhance_level; + }else{ + p_cfg->ui8AiEnhanceLevel = 1; + } + p_cfg->i8statisticOutputLevel = p_enc->statistic_output_level; + p_cfg->i8skipFrameEnable = p_enc->skip_frame_enable; + p_cfg->i8maxConsecutiveSkipFrameNum = p_enc->max_consecutive_skip_num; + p_cfg->u8skipFrameInterval = p_enc->skip_frame_interval; + p_cfg->ui16iFrameSizeRatio = p_enc->iframe_size_ratio; + p_cfg->ui8EnableAcqLimit = p_enc->enable_acq_limit; // enable_dynamic_8x8_merge, enable_dynamic_16x16_merge, enable_dynamic_32x32_merge, // trans_rate, enable_hvs_qp_scale: // are not present in Rev B p_config - p_cfg->ui8rcEnable = p_enc->rc.enable_rate_control; + p_cfg->ui8rcEnable = p_enc->rc.enable_rate_control; + + if(p_ctx->last_bitrate != 0) + { + // Slow sequence change happened. Retain the last bitrate. + ni_log2(p_ctx, NI_LOG_DEBUG, "### %s: Slow sequence happened retain last_bitrate %d. assigned bitrate %d\n", + __FUNCTION__, p_ctx->last_bitrate, p_src->bitrate); + p_src->bitrate = p_ctx->last_bitrate; + } if (p_src->bitrate != 0) { p_cfg->i32bitRate = p_src->bitrate; } + // Update the bitrate to be used after Slow sequence change + p_ctx->last_bitrate = p_cfg->i32bitRate; + +#if 0 + if ((p_enc->rc.enable_rate_control == 0) && + ((p_enc->rc.enable_mb_level_rc == 1) || (p_enc->rc.enable_cu_level_rate_control == 1))) + { + p_enc->rc.enable_mb_level_rc = p_enc->rc.enable_cu_level_rate_control = 0; + ni_log2(p_ctx, NI_LOG_DEBUG, "force enable_mb_level_rc & enable_cu_level_rate_control to 0 because rate control is disabled\n"); + } +#endif + p_t408->enable_cu_level_rate_control = p_enc->rc.enable_cu_level_rate_control; p_t408->enable_hvs_qp = p_enc->rc.enable_hvs_qp; p_t408->hvs_qp_scale = p_enc->rc.hvs_qp_scale; @@ -6023,16 +7628,24 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, p_t408->maxQpP = p_enc->rc.max_qp; p_t408->maxQpB = p_enc->rc.max_qp; - // TBD intraMinQp and intraMaxQp are not configurable in Rev A; should it - // be in Rev B? - p_t408->max_delta_qp = p_enc->rc.max_delta_qp; - p_cfg->i32vbvBufferSize = p_enc->rc.vbv_buffer_size; - p_cfg->i8intraQpDelta = p_enc->rc.intra_qp_delta; - p_cfg->ui8fillerEnable = p_enc->rc.enable_filler; - p_cfg->ui8picSkipEnable = p_enc->rc.enable_pic_skip; - p_cfg->ui16maxFrameSize = p_enc->maxFrameSize / 2000; - p_t408->intra_period = p_enc->intra_period; + if (p_enc->rc.vbv_buffer_size != -1) + { + p_cfg->i32vbvBufferSize = p_enc->rc.vbv_buffer_size; + } + else + { + if (p_enc->rc.enable_rate_control) + p_cfg->i32vbvBufferSize = 3000; // enable CBR (default vbv buffer size 3000) even if user does not set vbvBufferSize + else + p_cfg->i32vbvBufferSize = 0; // if user sets CRF but not vbvBufferSize, do not eanble capped CRF + } + p_cfg->ui32vbvMaxRate = p_enc->rc.vbv_max_rate; + p_cfg->i8intraQpDelta = p_enc->rc.intra_qp_delta; + p_cfg->ui8fillerEnable = p_enc->rc.enable_filler; + p_cfg->ui8picSkipEnable = p_enc->rc.enable_pic_skip; + p_cfg->ui16maxFrameSize = p_enc->maxFrameSize / 2000; + p_t408->intra_period = p_enc->intra_period; p_t408->roiEnable = p_enc->roi_enable; p_t408->useLongTerm = p_enc->long_term_ref_enable; if (QUADRA) @@ -6048,6 +7661,20 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, if (QUADRA) { + if(p_ctx->last_framerate.framerate_num != 0) + { + // Slow sequence change happened. Retain the last framerate. + ni_log2(p_ctx, NI_LOG_DEBUG, "### %s: Slow sequence happened retain last_framerate num %d den %d. assigned num %d den %d\n", + __FUNCTION__, p_ctx->last_framerate.framerate_num, p_ctx->last_framerate.framerate_denom, + p_cfg->i32frameRateInfo, p_cfg->i32frameRateDenominator); + p_src->fps_number = p_ctx->last_framerate.framerate_num; + p_src->fps_denominator = p_ctx->last_framerate.framerate_denom; + + if (!p_src->enable_vfr) { + p_enc->frame_rate = (int)(p_src->fps_number / p_src->fps_denominator); + } + } + if (p_cfg->i32frameRateInfo != p_enc->frame_rate) { p_cfg->i32frameRateInfo = p_enc->frame_rate; @@ -6061,6 +7688,10 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, p_cfg->i32frameRateInfo *= numUnitsInTick; } } + + // Update the framerate to be used after Slow sequence change + p_ctx->last_framerate.framerate_num = p_cfg->i32frameRateInfo; + p_ctx->last_framerate.framerate_denom = p_cfg->i32frameRateDenominator; } else { @@ -6128,19 +7759,19 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, } // Rev. B: H.264 only parameters. - p_t408->enable_transform_8x8 = p_enc->enable_transform_8x8; - p_t408->avc_slice_mode = p_enc->avc_slice_mode; - p_t408->avc_slice_arg = p_enc->avc_slice_arg; - p_t408->entropy_coding_mode = p_enc->entropy_coding_mode; + p_t408->enable_transform_8x8 = p_enc->enable_transform_8x8; + p_t408->entropy_coding_mode = p_enc->entropy_coding_mode; // Rev. B: shared between HEVC and H.264 + p_t408->slice_mode = p_enc->slice_mode; + p_t408->slice_arg = p_enc->slice_arg; if (p_t408->intra_mb_refresh_mode != p_enc->intra_mb_refresh_mode) { p_t408->intra_mb_refresh_mode = p_enc->intra_mb_refresh_mode; if (1 != p_t408->intra_mb_refresh_mode) { p_t408->intra_mb_refresh_mode = 1; - ni_log(NI_LOG_DEBUG, "force intraRefreshMode to 1 because quadra only supports intra refresh by rows\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "force intraRefreshMode to 1 because quadra only supports intra refresh by rows\n"); } } @@ -6149,13 +7780,15 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, p_t408->intra_mb_refresh_arg = p_enc->intra_mb_refresh_arg; if (1 == p_t408->intra_mb_refresh_mode) { - p_cfg->ui16gdrDuration = (p_cfg->i32picHeight / ((p_cfg->ui8bitstreamFormat == STD_AVC) ? 16 : 64)) / p_t408->intra_mb_refresh_arg; - if (!p_cfg->ui16gdrDuration) - p_cfg->ui16gdrDuration = p_cfg->i32picHeight / ((p_cfg->ui8bitstreamFormat == STD_AVC) ? 16 : 64); + int mbHeight = (p_cfg->ui8bitstreamFormat == STD_AVC) ? 16 : 64; + int mbRows = (p_cfg->i32picHeight + mbHeight - 1) / mbHeight; + p_cfg->ui16gdrDuration = (mbRows + p_t408->intra_mb_refresh_arg - 1) / p_t408->intra_mb_refresh_arg; } } - // TBD Rev. B: could be shared for HEVC and H.264 + p_cfg->ui8intraResetRefresh = p_enc->intra_reset_refresh; + + // Rev. B: could be shared for HEVC and H.264 p_t408->enable_mb_level_rc = p_enc->rc.enable_mb_level_rc; // profile setting: if user specified profile @@ -6177,12 +7810,12 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, if (2 == p_t408->profile) { p_t408->enable_transform_8x8 = 0; - ni_log(NI_LOG_DEBUG, "enable_transform_8x8 set to 0 for profile 2 (main)\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "enable_transform_8x8 set to 0 for profile 2 (main)\n"); } else if (3 == p_t408->profile || 1 == p_t408->profile) { p_t408->entropy_coding_mode = p_t408->enable_transform_8x8 = 0; - ni_log(NI_LOG_DEBUG, "entropy_coding_mode and enable_transform_8x8 set to 0 " + ni_log2(p_ctx, NI_LOG_DEBUG, "entropy_coding_mode and enable_transform_8x8 set to 0 " "for profile 3 (extended) or 1 (baseline)\n"); } } @@ -6191,7 +7824,7 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, { if (0 == p_t408->entropy_coding_mode && 1 == p_enc->EnableRdoQuant) { - ni_log(NI_LOG_DEBUG, "RDOQ does not support entropy_coding_mode 0 (CAVLC) " + ni_log2(p_ctx, NI_LOG_DEBUG, "RDOQ does not support entropy_coding_mode 0 (CAVLC) " "force EnableRdoQuant 0 to accommodate HW limiation\n"); p_enc->EnableRdoQuant = 0; } @@ -6276,20 +7909,21 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, } p_cfg->ui16rootBufId = p_src->rootBufId; - //set VUI info - p_cfg->ui32VuiDataSizeBits = p_src->ui32VuiDataSizeBits; - p_cfg->ui32VuiDataSizeBytes = p_src->ui32VuiDataSizeBytes; - memcpy(p_cfg->ui8VuiRbsp, p_src->ui8VuiRbsp, NI_MAX_VUI_SIZE); - if ((p_src->pos_num_units_in_tick > p_src->ui32VuiDataSizeBits) || (p_src->pos_time_scale > p_src->ui32VuiDataSizeBits)) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() VUI filling error\n", __func__); - return; - } - else - { - ni_fix_VUI(p_cfg->ui8VuiRbsp, p_src->pos_num_units_in_tick, p_t408->numUnitsInTick); - ni_fix_VUI(p_cfg->ui8VuiRbsp, p_src->pos_time_scale, p_t408->timeScale); - } + //set VUI info deprecated + //p_cfg->ui32VuiDataSizeBits = p_src->ui32VuiDataSizeBits; + //p_cfg->ui32VuiDataSizeBytes = p_src->ui32VuiDataSizeBytes; + //memcpy(p_cfg->ui8VuiRbsp, p_src->ui8VuiRbsp, NI_MAX_VUI_SIZE); + //if ((p_src->pos_num_units_in_tick > p_src->ui32VuiDataSizeBits) || (p_src->pos_time_scale > p_src->ui32VuiDataSizeBits)) + //{ + // ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() VUI filling error\n", __func__); + // return; + //} + //else + //{ + // ni_fix_VUI(p_cfg->ui8VuiRbsp, p_src->pos_num_units_in_tick, p_t408->numUnitsInTick); + // ni_fix_VUI(p_cfg->ui8VuiRbsp, p_src->pos_time_scale, p_t408->timeScale); + //} + if (p_src->enable_vfr) { p_cfg->ui8fixedframerate = 0; @@ -6327,6 +7961,21 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, { p_cfg->ui8HDR10CLLEnable = p_enc->HDR10CLLEnable; } + if (p_enc->HDR10Enable != 0) + { + p_cfg->ui8hdr10_enable = p_enc->HDR10Enable; + p_cfg->ui16hdr10_dx0 = p_enc->HDR10dx0; + p_cfg->ui16hdr10_dy0 = p_enc->HDR10dy0; + p_cfg->ui16hdr10_dx1 = p_enc->HDR10dx1; + p_cfg->ui16hdr10_dy1 = p_enc->HDR10dy1; + p_cfg->ui16hdr10_dx2 = p_enc->HDR10dx2; + p_cfg->ui16hdr10_dy2 = p_enc->HDR10dy2; + p_cfg->ui16hdr10_wx = p_enc->HDR10wx; + p_cfg->ui16hdr10_wy = p_enc->HDR10wy; + p_cfg->ui32hdr10_maxluma = p_enc->HDR10maxluma; + p_cfg->ui32hdr10_minluma = p_enc->HDR10minluma; + } + if (p_enc->EnableRdoQuant != 0) { p_cfg->ui8EnableRdoQuant = p_enc->EnableRdoQuant; @@ -6420,6 +8069,16 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, p_cfg->ui8rcQpDeltaRange = p_enc->rcQpDeltaRange; } + if (p_enc->ctbRowQpStep != 0) + { + p_cfg->i16ctbRowQpStep = p_enc->ctbRowQpStep; + } + + if (p_enc->newRcEnable != -1) + { + p_cfg->ui8NewRCEnable = p_enc->newRcEnable; + } + // convert enable_mb_level_rc, enable_cu_level_rate_control, and enable_hvs_qp to ctbRcMode if (QUADRA) { @@ -6428,11 +8087,15 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, { if (p_t408->enable_mb_level_rc || p_t408->enable_cu_level_rate_control) { - if (p_t408->enable_hvs_qp) - { - p_cfg->ui8ctbRcMode = 3; - } - else + if (p_t408->enable_hvs_qp) + { + p_cfg->ui8ctbRcMode = 3; + // If hvsQP is enabled, disable strongIntraSmooth to apply one filtering at a time for better VQ. + p_t408->strongIntraSmoothEnable = 0; + ni_log(NI_LOG_INFO, + "Turning off strongIntraSmoothing because hvsQPEnable=1 " + "for better subjective VQ\n"); + } else { p_cfg->ui8ctbRcMode = 2; } @@ -6440,13 +8103,18 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, else if (p_t408->enable_hvs_qp) { p_cfg->ui8ctbRcMode = 1; + // If hvsQP is enabled, disable strongIntraSmooth to apply one filtering at a time for better VQ. + p_t408->strongIntraSmoothEnable = 0; + ni_log(NI_LOG_INFO, + "Turning off strongIntraSmoothing because hvsQPEnable=1 for " + "better subjective VQ\n"); } } } if (p_src->low_delay_mode != 0) { - p_cfg->ui8LowDelay = p_src->low_delay_mode; + p_cfg->ui8LowDelay = !!(p_src->low_delay_mode); } if (p_enc->enable_ssim != 0) @@ -6454,106 +8122,311 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, p_cfg->ui8enableSSIM = p_enc->enable_ssim; } - ni_log(NI_LOG_DEBUG, "lowDelay=%d\n", p_src->low_delay_mode); - ni_log(NI_LOG_DEBUG, "ui8bitstreamFormat=%d\n", p_cfg->ui8bitstreamFormat); - ni_log(NI_LOG_DEBUG, "i32picWidth=%d\n", p_cfg->i32picWidth); - ni_log(NI_LOG_DEBUG, "i32picHeight=%d\n", p_cfg->i32picHeight); - ni_log(NI_LOG_DEBUG, "i32meBlkMode=%d\n", p_cfg->i32meBlkMode); - ni_log(NI_LOG_DEBUG, "ui8sliceMode=%d\n", p_cfg->ui8sliceMode); - ni_log(NI_LOG_DEBUG, "i32frameRateInfo=%d\n", p_cfg->i32frameRateInfo); - ni_log(NI_LOG_DEBUG, "i32vbvBufferSize=%d\n", p_cfg->i32vbvBufferSize); - ni_log(NI_LOG_DEBUG, "i32userQpMax=%d\n", p_cfg->i32userQpMax); - ni_log(NI_LOG_DEBUG, "enableSSIM=%d\n", p_cfg->ui8enableSSIM); + if (p_enc->av1_error_resilient_mode != 0) + { + p_cfg->ui8av1ErrResilientMode = p_enc->av1_error_resilient_mode; + } + + if (p_enc->temporal_layers_enable != 0) + { + p_cfg->ui8temporalLayersEnable = p_enc->temporal_layers_enable; + } + + if (p_ctx->pixel_format != NI_PIX_FMT_YUV420P) + { + p_cfg->ui8PixelFormat = p_ctx->pixel_format; + } + + if (p_src->zerocopy_mode == -1) // zero copy auto mode - disable zero copy for low resolution + { + bool is_rgba = (p_ctx->pixel_format == NI_PIX_FMT_RGBA || + p_ctx->pixel_format == NI_PIX_FMT_BGRA || + p_ctx->pixel_format == NI_PIX_FMT_ARGB || + p_ctx->pixel_format == NI_PIX_FMT_ABGR) ? true : false; + if (is_rgba || + ((ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6Q") >= 0) && + p_src->source_width*p_src->source_height >= NI_NUM_OF_PIXELS_1080P)) + p_src->zerocopy_mode = 1; + else + p_src->zerocopy_mode = 0; + } + + if (p_src->zerocopy_mode) + { + p_cfg->ui32lumaLinesize = p_src->luma_linesize; + p_cfg->ui32chromaLinesize = p_src->chroma_linesize; + } + else + { + p_cfg->ui32lumaLinesize = p_src->luma_linesize = 0; + p_cfg->ui32chromaLinesize = p_src->chroma_linesize = 0; + } + // for fast sequence change linesize check + p_ctx->ori_luma_linesize = p_src->luma_linesize; + p_ctx->ori_chroma_linesize = p_src->chroma_linesize; + + // calculate number for frames delay for minFramesDelay + int lookAheadEnable = !!p_cfg->ui8LookAheadDepth; + int gopSize = g_map_preset_to_gopsize[lookAheadEnable][p_t408->gop_preset_index + 1]; + int mulitcoreDelay = p_cfg->ui8multicoreJointMode ? 3 : 0; + + if (p_t408->gop_preset_index == 0) // Custom GOP + gopSize = p_t408->custom_gop_params.custom_gop_size; + + if (lookAheadEnable) + { + int firstGopEnd = gopSize + 1 + mulitcoreDelay; // first I-frame gopSize is 1 + int lookaheadGopEnd = mulitcoreDelay ? + p_cfg->ui8LookAheadDepth + mulitcoreDelay + (gopSize - ((p_cfg->ui8LookAheadDepth-1+mulitcoreDelay) % gopSize)) : + p_cfg->ui8LookAheadDepth + (gopSize - ((p_cfg->ui8LookAheadDepth-1) % gopSize)); // lookAheadDepth-1 because lookahead queue includes first I-frame + int initialDelayNum = (firstGopEnd > lookaheadGopEnd) ? firstGopEnd : lookaheadGopEnd; + int maxDelayNum = p_cfg->ui8LookAheadDepth + 1 + gopSize / 2 + mulitcoreDelay; + int maxLookaheadQueue = initialDelayNum + (gopSize - 1) + mulitcoreDelay; // assume worst case scenario - gop size changes from initial gop to gop size 1 + + p_ctx->initial_frame_delay = initialDelayNum + (mulitcoreDelay ? 4 : 0); // for multicore pass-2, need to add 4 more frames before pass-2 could output frame + p_ctx->max_frame_delay = ((maxDelayNum > maxLookaheadQueue) ? maxDelayNum : maxLookaheadQueue) + (mulitcoreDelay ? 4 : 0); // for multicore pass-2, need to add 4 more frames before pass-2 could output frame + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r2") >= 0) + { + p_ctx->last_gop_size = gopSize; // for adaptive gop, gop size change can happen in pass-1, causing the first non-IDR output to carrry gop size 4 insetad of 8 and increase lookahead queue + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rX") >= 0) + { + if (p_t408->gop_preset_index == GOP_PRESET_IDX_DEFAULT || mulitcoreDelay) // for adaptive gop or multicore, just set max frame delay to workaround encoding stuck + p_ctx->current_frame_delay = p_ctx->max_frame_delay; + else + p_ctx->current_frame_delay = p_ctx->initial_frame_delay; + } + else + { + p_ctx->current_frame_delay = p_ctx->max_frame_delay; + } + } + else + { + p_ctx->last_gop_size = gopSize; + p_ctx->current_frame_delay = p_ctx->max_frame_delay; + } + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: firstGopEnd %d lookaheadGopEnd %d initialDelayNum %d maxDelayNum %d maxLookaheadQueue %d\n", + __FUNCTION__, firstGopEnd, lookaheadGopEnd, initialDelayNum, maxDelayNum, maxLookaheadQueue); + } + else + { + p_ctx->last_gop_size = gopSize; + p_ctx->initial_frame_delay = p_ctx->max_frame_delay = p_ctx->current_frame_delay = gopSize + mulitcoreDelay; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: preset %d lookAheadDepth %d gopSize %d mulitcoreDelay %d " + "last_gop_size %d linitial_frame_delay %d current_frame_delay %d max_frame_delay %d\n", + __FUNCTION__, p_t408->gop_preset_index, p_cfg->ui8LookAheadDepth, gopSize, mulitcoreDelay, + p_ctx->last_gop_size, p_ctx->initial_frame_delay, p_ctx->current_frame_delay, p_ctx->max_frame_delay); + + if (p_enc->crop_width != 0 && p_enc->crop_height != 0) + { + p_cfg->ui32cropWidth = p_enc->crop_width; + p_cfg->ui32cropHeight = p_enc->crop_height; + p_cfg->ui32horOffset = p_enc->hor_offset; + p_cfg->ui32verOffset = p_enc->ver_offset; + } + + if (p_enc->crfMax != -1) + { + p_cfg->i8crfMax = (int8_t)(p_enc->crfMax) + 1; // for old libxcoder backward compatibility, use 1 to represent 0 + } + + if (p_enc->qcomp != 0.6) + { + p_cfg->i32qcomp = (int32_t)(p_enc->qcomp * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + } + + if (p_enc->noMbtree != 0) + { + p_cfg->ui8noMbtree = p_enc->noMbtree; + } + + if (p_enc->noHWMultiPassSupport != 0) + { + p_cfg->ui8noHWMultiPassSupport = p_enc->noHWMultiPassSupport; + } + + if (p_enc->cuTreeFactor != 5) + { + p_cfg->i8cuTreeFactor = p_enc->cuTreeFactor; + } + + if (p_enc->ipRatio != 1.4) + { + p_cfg->i32ipRatio = (int32_t)(p_enc->ipRatio * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + } + + if (p_enc->pbRatio != 1.3) + { + p_cfg->i32pbRatio = (int32_t)(p_enc->pbRatio * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + } + + if (p_enc->cplxDecay != 0.5) + { + p_cfg->i32cplxDecay = (int32_t)(p_enc->cplxDecay * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + } + + if (p_enc->pps_init_qp != -1) + { + p_cfg->i8ppsInitQp = (int8_t)(p_enc->pps_init_qp) + 1; // for old libxcoder backward compatibility, use 1 to represent 0 + } + + if (p_enc->bitrateMode != -1) + { + p_cfg->ui8bitrateMode = p_enc->bitrateMode; + } + + if (p_enc->pass1_qp != -1) + { + p_cfg->i8pass1Qp = (int8_t)(p_enc->pass1_qp) + 1; // for old libxcoder backward compatibility, use 1 to represent 0 + } + + if (p_enc->crfFloat != -1.0) + { + // for old libxcoder backward compatibility + p_cfg->i8crf = (int8_t)(p_enc->crfFloat); + p_cfg->i8crfDecimal = (int8_t)((p_enc->crfFloat - (float)p_cfg->i8crf) * 100); + } + + if (p_enc->hvsBaseMbComplexity != 15) + { + p_cfg->i8hvsBaseMbComplexity = (int8_t)p_enc->hvsBaseMbComplexity - 15; // for old libxcoder backward compatibility, use -15 to represent 0 + } + + if (p_enc->enableipRatio != 0 && p_cfg->i32vbvBufferSize != 0) //vbvBufferSize !=0 for CBR not for ABR + { + p_cfg->i8enableipRatio = p_enc->enableipRatio; + } + + if (p_enc->crf_max_iframe_enable != 0) + { + p_cfg->ui8crfMaxIframeEnable = p_enc->crf_max_iframe_enable; + } + + if (p_enc->vbv_min_rate != 0) + { + p_cfg->ui32vbvMinRate = p_enc->vbv_min_rate; + } + + if (p_enc->disableBframeRdoq != 0) + { + p_cfg->ui8disableBframeRDOQ = p_enc->disableBframeRdoq; + } + + if (p_enc->forceBframeQpfactor != -1.0) + { + p_cfg->i32forceBframeQpFactor = (int32_t)(p_enc->forceBframeQpfactor * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + } + + if (p_enc->tune_bframe_visual != 0) + { + p_cfg->ui8tuneBframeVisual = p_enc->tune_bframe_visual; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "lowDelay=%d\n", p_src->low_delay_mode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8bitstreamFormat=%d\n", p_cfg->ui8bitstreamFormat); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32picWidth=%d\n", p_cfg->i32picWidth); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32picHeight=%d\n", p_cfg->i32picHeight); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32meBlkMode=%d\n", p_cfg->i32meBlkMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8sliceMode=%d\n", p_cfg->ui8sliceMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32frameRateInfo=%d\n", p_cfg->i32frameRateInfo); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32vbvBufferSize=%d\n", p_cfg->i32vbvBufferSize); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32userQpMax=%d\n", p_cfg->i32userQpMax); + ni_log2(p_ctx, NI_LOG_DEBUG, "enableSSIM=%d\n", p_cfg->ui8enableSSIM); // AVC only - ni_log(NI_LOG_DEBUG, "i32maxIntraSize=%d\n", p_cfg->i32maxIntraSize); - ni_log(NI_LOG_DEBUG, "i32userMaxDeltaQp=%d\n", p_cfg->i32userMaxDeltaQp); - ni_log(NI_LOG_DEBUG, "i32userMinDeltaQp=%d\n", p_cfg->i32userMinDeltaQp); - ni_log(NI_LOG_DEBUG, "i32userQpMin=%d\n", p_cfg->i32userQpMin); - ni_log(NI_LOG_DEBUG, "i32bitRate=%d\n", p_cfg->i32bitRate); - ni_log(NI_LOG_DEBUG, "i32bitRateBL=%d\n", p_cfg->i32bitRateBL); - ni_log(NI_LOG_DEBUG, "ui8rcEnable=%d\n", p_cfg->ui8rcEnable); - ni_log(NI_LOG_DEBUG, "i32srcBitDepth=%d\n", p_cfg->i32srcBitDepth); - ni_log(NI_LOG_DEBUG, "ui8enablePTS=%d\n", p_cfg->ui8enablePTS); - ni_log(NI_LOG_DEBUG, "ui8lowLatencyMode=%d\n", p_cfg->ui8lowLatencyMode); - ni_log(NI_LOG_DEBUG, "ui32sourceEndian=%u\n", p_cfg->ui32sourceEndian); - ni_log(NI_LOG_DEBUG, "hdrEnableVUI=%u\n", p_cfg->hdrEnableVUI); - ni_log(NI_LOG_DEBUG, "i32hwframes=%i\n", p_cfg->i32hwframes); - - ni_log(NI_LOG_DEBUG, "** ni_t408_config_t: \n"); - ni_log(NI_LOG_DEBUG, "profile=%d\n", p_t408->profile); - ni_log(NI_LOG_DEBUG, "level=%d\n", p_t408->level); - ni_log(NI_LOG_DEBUG, "tier=%d\n", p_t408->tier); - - ni_log(NI_LOG_DEBUG, "internalBitDepth=%d\n", p_t408->internalBitDepth); - ni_log(NI_LOG_DEBUG, "losslessEnable=%d\n", p_t408->losslessEnable); - ni_log(NI_LOG_DEBUG, "constIntraPredFlag=%d\n", p_t408->constIntraPredFlag); - - ni_log(NI_LOG_DEBUG, "decoding_refresh_type=%d\n", p_t408->decoding_refresh_type); - ni_log(NI_LOG_DEBUG, "intra_qp=%d\n", p_t408->intra_qp); - ni_log(NI_LOG_DEBUG, "intra_period=%d\n", p_t408->intra_period); - ni_log(NI_LOG_DEBUG, "roi_enable=%d\n", p_t408->roiEnable); - - ni_log(NI_LOG_DEBUG, "useLongTerm=%u\n", p_t408->useLongTerm); - ni_log(NI_LOG_DEBUG, "setLongTermInterval=%u\n", p_cfg->ui32setLongTermInterval); - ni_log(NI_LOG_DEBUG, "setLongTermCount=%u\n", p_cfg->ui8setLongTermCount); - - ni_log(NI_LOG_DEBUG, "conf_win_top=%d\n", p_t408->conf_win_top); - ni_log(NI_LOG_DEBUG, "conf_win_bottom=%d\n", p_t408->conf_win_bottom); - ni_log(NI_LOG_DEBUG, "conf_win_left=%d\n", p_t408->conf_win_left); - ni_log(NI_LOG_DEBUG, "conf_win_right=%d\n", p_t408->conf_win_right); - - ni_log(NI_LOG_DEBUG, "independSliceMode=%d\n", p_t408->independSliceMode); - ni_log(NI_LOG_DEBUG, "independSliceModeArg=%d\n", p_t408->independSliceModeArg); - - ni_log(NI_LOG_DEBUG, "dependSliceMode=%d\n", p_t408->dependSliceMode); - ni_log(NI_LOG_DEBUG, "dependSliceModeArg=%d\n", p_t408->dependSliceModeArg); - - ni_log(NI_LOG_DEBUG, "intraRefreshMode=%d\n", p_t408->intraRefreshMode); - - ni_log(NI_LOG_DEBUG, "intraRefreshArg=%d\n", p_t408->intraRefreshArg); - - ni_log(NI_LOG_DEBUG, "use_recommend_enc_params=%d\n", p_t408->use_recommend_enc_params); - ni_log(NI_LOG_DEBUG, "scalingListEnable=%d\n", p_t408->scalingListEnable); - - ni_log(NI_LOG_DEBUG, "cu_size_mode=%d\n", p_t408->cu_size_mode); - ni_log(NI_LOG_DEBUG, "tmvpEnable=%d\n", p_t408->tmvpEnable); - ni_log(NI_LOG_DEBUG, "wppEnable=%d\n", p_t408->wppEnable); - ni_log(NI_LOG_DEBUG, "max_num_merge=%d\n", p_t408->max_num_merge); - ni_log(NI_LOG_DEBUG, "disableDeblk=%d\n", p_t408->disableDeblk); - ni_log(NI_LOG_DEBUG, "lfCrossSliceBoundaryEnable=%d\n", p_t408->lfCrossSliceBoundaryEnable); - ni_log(NI_LOG_DEBUG, "betaOffsetDiv2=%d\n", p_t408->betaOffsetDiv2); - ni_log(NI_LOG_DEBUG, "tcOffsetDiv2=%d\n", p_t408->tcOffsetDiv2); - ni_log(NI_LOG_DEBUG, "skipIntraTrans=%d\n", p_t408->skipIntraTrans); - ni_log(NI_LOG_DEBUG, "saoEnable=%d\n", p_t408->saoEnable); - ni_log(NI_LOG_DEBUG, "intraNxNEnable=%d\n", p_t408->intraNxNEnable); - ni_log(NI_LOG_DEBUG, "bitAllocMode=%d\n", p_t408->bitAllocMode); - - ni_log(NI_LOG_DEBUG, "enable_cu_level_rate_control=%d\n", p_t408->enable_cu_level_rate_control); - - ni_log(NI_LOG_DEBUG, "enable_hvs_qp=%d\n", p_t408->enable_hvs_qp); - - ni_log(NI_LOG_DEBUG, "hvs_qp_scale=%d\n", p_t408->hvs_qp_scale); - - ni_log(NI_LOG_DEBUG, "max_delta_qp=%d\n", p_t408->max_delta_qp); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32maxIntraSize=%d\n", p_cfg->i32maxIntraSize); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32userMaxDeltaQp=%d\n", p_cfg->i32userMaxDeltaQp); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32userMinDeltaQp=%d\n", p_cfg->i32userMinDeltaQp); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32userQpMin=%d\n", p_cfg->i32userQpMin); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32bitRate=%d\n", p_cfg->i32bitRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32bitRateBL=%d\n", p_cfg->i32bitRateBL); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8rcEnable=%d\n", p_cfg->ui8rcEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32srcBitDepth=%d\n", p_cfg->i32srcBitDepth); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8enablePTS=%d\n", p_cfg->ui8enablePTS); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8lowLatencyMode=%d\n", p_cfg->ui8lowLatencyMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32sourceEndian=%u\n", p_cfg->ui32sourceEndian); + ni_log2(p_ctx, NI_LOG_DEBUG, "hdrEnableVUI=%u\n", p_cfg->hdrEnableVUI); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32hwframes=%i\n", p_cfg->i32hwframes); + + ni_log2(p_ctx, NI_LOG_DEBUG, "** ni_t408_config_t: \n"); + ni_log2(p_ctx, NI_LOG_DEBUG, "profile=%d\n", p_t408->profile); + ni_log2(p_ctx, NI_LOG_DEBUG, "level=%d\n", p_t408->level); + ni_log2(p_ctx, NI_LOG_DEBUG, "tier=%d\n", p_t408->tier); + + ni_log2(p_ctx, NI_LOG_DEBUG, "internalBitDepth=%d\n", p_t408->internalBitDepth); + ni_log2(p_ctx, NI_LOG_DEBUG, "losslessEnable=%d\n", p_t408->losslessEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "constIntraPredFlag=%d\n", p_t408->constIntraPredFlag); + + ni_log2(p_ctx, NI_LOG_DEBUG, "decoding_refresh_type=%d\n", p_t408->decoding_refresh_type); + ni_log2(p_ctx, NI_LOG_DEBUG, "intra_qp=%d\n", p_t408->intra_qp); + ni_log2(p_ctx, NI_LOG_DEBUG, "intra_period=%d\n", p_t408->intra_period); + ni_log2(p_ctx, NI_LOG_DEBUG, "roi_enable=%d\n", p_t408->roiEnable); + + ni_log2(p_ctx, NI_LOG_DEBUG, "useLongTerm=%u\n", p_t408->useLongTerm); + ni_log2(p_ctx, NI_LOG_DEBUG, "setLongTermInterval=%u\n", p_cfg->ui32setLongTermInterval); + ni_log2(p_ctx, NI_LOG_DEBUG, "setLongTermCount=%u\n", p_cfg->ui8setLongTermCount); + + ni_log2(p_ctx, NI_LOG_DEBUG, "conf_win_top=%d\n", p_t408->conf_win_top); + ni_log2(p_ctx, NI_LOG_DEBUG, "conf_win_bottom=%d\n", p_t408->conf_win_bottom); + ni_log2(p_ctx, NI_LOG_DEBUG, "conf_win_left=%d\n", p_t408->conf_win_left); + ni_log2(p_ctx, NI_LOG_DEBUG, "conf_win_right=%d\n", p_t408->conf_win_right); + + ni_log2(p_ctx, NI_LOG_DEBUG, "independSliceMode=%d\n", p_t408->independSliceMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "independSliceModeArg=%d\n", p_t408->independSliceModeArg); + + ni_log2(p_ctx, NI_LOG_DEBUG, "dependSliceMode=%d\n", p_t408->dependSliceMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "dependSliceModeArg=%d\n", p_t408->dependSliceModeArg); + + ni_log2(p_ctx, NI_LOG_DEBUG, "intraRefreshMode=%d\n", p_t408->intraRefreshMode); + + ni_log2(p_ctx, NI_LOG_DEBUG, "intraRefreshArg=%d\n", p_t408->intraRefreshArg); + + ni_log2(p_ctx, NI_LOG_DEBUG, "use_recommend_enc_params=%d\n", p_t408->use_recommend_enc_params); + ni_log2(p_ctx, NI_LOG_DEBUG, "scalingListEnable=%d\n", p_t408->scalingListEnable); + + ni_log2(p_ctx, NI_LOG_DEBUG, "cu_size_mode=%d\n", p_t408->cu_size_mode); + ni_log2(p_ctx, NI_LOG_DEBUG, "tmvpEnable=%d\n", p_t408->tmvpEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "wppEnable=%d\n", p_t408->wppEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "max_num_merge=%d\n", p_t408->max_num_merge); + ni_log2(p_ctx, NI_LOG_DEBUG, "disableDeblk=%d\n", p_t408->disableDeblk); + ni_log2(p_ctx, NI_LOG_DEBUG, "lfCrossSliceBoundaryEnable=%d\n", p_t408->lfCrossSliceBoundaryEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "betaOffsetDiv2=%d\n", p_t408->betaOffsetDiv2); + ni_log2(p_ctx, NI_LOG_DEBUG, "tcOffsetDiv2=%d\n", p_t408->tcOffsetDiv2); + ni_log2(p_ctx, NI_LOG_DEBUG, "skipIntraTrans=%d\n", p_t408->skipIntraTrans); + ni_log2(p_ctx, NI_LOG_DEBUG, "saoEnable=%d\n", p_t408->saoEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "intraNxNEnable=%d\n", p_t408->intraNxNEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "bitAllocMode=%d\n", p_t408->bitAllocMode); + + ni_log2(p_ctx, NI_LOG_DEBUG, "enable_cu_level_rate_control=%d\n", p_t408->enable_cu_level_rate_control); + + ni_log2(p_ctx, NI_LOG_DEBUG, "enable_hvs_qp=%d\n", p_t408->enable_hvs_qp); + + ni_log2(p_ctx, NI_LOG_DEBUG, "hvs_qp_scale=%d\n", p_t408->hvs_qp_scale); + + ni_log2(p_ctx, NI_LOG_DEBUG, "max_delta_qp=%d\n", p_t408->max_delta_qp); // CUSTOM_GOP - ni_log(NI_LOG_DEBUG, "gop_preset_index=%d\n", p_t408->gop_preset_index); + ni_log2(p_ctx, NI_LOG_DEBUG, "gop_preset_index=%d\n", p_t408->gop_preset_index); #ifndef QUADRA if (!QUADRA) { if (p_t408->gop_preset_index == GOP_PRESET_IDX_CUSTOM) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_t408->custom_gop_params.custom_gop_size); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_t408->custom_gop_params.custom_gop_size); for (i = 0; i < 8; i++) //for (i = 0; i < p_t408->custom_gop_params.custom_gop_size; i++) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_t408->custom_gop_params.pic_param[i].pic_type); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_t408->custom_gop_params.pic_param[i].poc_offset); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_qp=%d\n", i, p_t408->custom_gop_params.pic_param[i].pic_qp); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pic_L0=%d\n", i, p_t408->custom_gop_params.pic_param[i].num_ref_pic_L0); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L0=%d\n", i, p_t408->custom_gop_params.pic_param[i].ref_poc_L0); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L1=%d\n", i, p_t408->custom_gop_params.pic_param[i].ref_poc_L1); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_t408->custom_gop_params.pic_param[i].temporal_id); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_t408->custom_gop_params.pic_param[i].pic_type); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_t408->custom_gop_params.pic_param[i].poc_offset); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_qp=%d\n", i, p_t408->custom_gop_params.pic_param[i].pic_qp); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pic_L0=%d\n", i, p_t408->custom_gop_params.pic_param[i].num_ref_pic_L0); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L0=%d\n", i, p_t408->custom_gop_params.pic_param[i].ref_poc_L0); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L1=%d\n", i, p_t408->custom_gop_params.pic_param[i].ref_poc_L1); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_t408->custom_gop_params.pic_param[i].temporal_id); } } } @@ -6563,150 +8436,197 @@ void ni_set_custom_template(ni_session_context_t *p_ctx, if (p_t408->custom_gop_params.custom_gop_size) { int j; - ni_log(NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_t408->custom_gop_params.custom_gop_size); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_t408->custom_gop_params.custom_gop_size); for (i = 0; i < NI_MAX_GOP_NUM; i++) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_t408->custom_gop_params.pic_param[i].poc_offset); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_offset=%d\n", i, p_t408->custom_gop_params.pic_param[i].qp_offset); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_factor=%f\n", i, p_t408->custom_gop_params.pic_param[i].qp_factor); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_t408->custom_gop_params.pic_param[i].temporal_id); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_t408->custom_gop_params.pic_param[i].pic_type); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pics=%d\n", i, p_t408->custom_gop_params.pic_param[i].num_ref_pics); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_t408->custom_gop_params.pic_param[i].poc_offset); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_offset=%d\n", i, p_t408->custom_gop_params.pic_param[i].qp_offset); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_factor=%f\n", i, p_t408->custom_gop_params.pic_param[i].qp_factor); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_t408->custom_gop_params.pic_param[i].temporal_id); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_t408->custom_gop_params.pic_param[i].pic_type); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pics=%d\n", i, p_t408->custom_gop_params.pic_param[i].num_ref_pics); for (j = 0; j < NI_MAX_REF_PIC; j++) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic=%d\n", i, j, p_t408->custom_gop_params.pic_param[i].rps[j].ref_pic); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic_used=%d\n", i, j, p_t408->custom_gop_params.pic_param[i].rps[j].ref_pic_used); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic=%d\n", i, j, p_t408->custom_gop_params.pic_param[i].rps[j].ref_pic); + ni_log2(p_ctx, NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic_used=%d\n", i, j, p_t408->custom_gop_params.pic_param[i].rps[j].ref_pic_used); } } } } - ni_log(NI_LOG_DEBUG, "roiEnable=%d\n", p_t408->roiEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "roiEnable=%d\n", p_t408->roiEnable); - ni_log(NI_LOG_DEBUG, "numUnitsInTick=%u\n", p_t408->numUnitsInTick); - ni_log(NI_LOG_DEBUG, "timeScale=%u\n", p_t408->timeScale); - ni_log(NI_LOG_DEBUG, "numTicksPocDiffOne=%u\n", p_t408->numTicksPocDiffOne); + ni_log2(p_ctx, NI_LOG_DEBUG, "numUnitsInTick=%u\n", p_t408->numUnitsInTick); + ni_log2(p_ctx, NI_LOG_DEBUG, "timeScale=%u\n", p_t408->timeScale); + ni_log2(p_ctx, NI_LOG_DEBUG, "numTicksPocDiffOne=%u\n", p_t408->numTicksPocDiffOne); - ni_log(NI_LOG_DEBUG, "chromaCbQpOffset=%d\n", p_t408->chromaCbQpOffset); - ni_log(NI_LOG_DEBUG, "chromaCrQpOffset=%d\n", p_t408->chromaCrQpOffset); + ni_log2(p_ctx, NI_LOG_DEBUG, "chromaCbQpOffset=%d\n", p_t408->chromaCbQpOffset); + ni_log2(p_ctx, NI_LOG_DEBUG, "chromaCrQpOffset=%d\n", p_t408->chromaCrQpOffset); - ni_log(NI_LOG_DEBUG, "initialRcQp=%d\n", p_t408->initialRcQp); + ni_log2(p_ctx, NI_LOG_DEBUG, "initialRcQp=%d\n", p_t408->initialRcQp); - ni_log(NI_LOG_DEBUG, "nrYEnable=%u\n", p_t408->nrYEnable); - ni_log(NI_LOG_DEBUG, "nrCbEnable=%u\n", p_t408->nrCbEnable); - ni_log(NI_LOG_DEBUG, "nrCrEnable=%u\n", p_t408->nrCrEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrYEnable=%u\n", p_t408->nrYEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrCbEnable=%u\n", p_t408->nrCbEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrCrEnable=%u\n", p_t408->nrCrEnable); // ENC_NR_WEIGHT - ni_log(NI_LOG_DEBUG, "nrIntraWeightY=%u\n", p_t408->nrIntraWeightY); - ni_log(NI_LOG_DEBUG, "nrIntraWeightCb=%u\n", p_t408->nrIntraWeightCb); - ni_log(NI_LOG_DEBUG, "nrIntraWeightCr=%u\n", p_t408->nrIntraWeightCr); - ni_log(NI_LOG_DEBUG, "nrInterWeightY=%u\n", p_t408->nrInterWeightY); - ni_log(NI_LOG_DEBUG, "nrInterWeightCb=%u\n", p_t408->nrInterWeightCb); - ni_log(NI_LOG_DEBUG, "nrInterWeightCr=%u\n", p_t408->nrInterWeightCr); - - ni_log(NI_LOG_DEBUG, "nrNoiseEstEnable=%u\n", p_t408->nrNoiseEstEnable); - ni_log(NI_LOG_DEBUG, "nrNoiseSigmaY=%u\n", p_t408->nrNoiseSigmaY); - ni_log(NI_LOG_DEBUG, "nrNoiseSigmaCb=%u\n", p_t408->nrNoiseSigmaCb); - ni_log(NI_LOG_DEBUG, "nrNoiseSigmaCr=%u\n", p_t408->nrNoiseSigmaCr); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrIntraWeightY=%u\n", p_t408->nrIntraWeightY); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrIntraWeightCb=%u\n", p_t408->nrIntraWeightCb); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrIntraWeightCr=%u\n", p_t408->nrIntraWeightCr); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrInterWeightY=%u\n", p_t408->nrInterWeightY); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrInterWeightCb=%u\n", p_t408->nrInterWeightCb); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrInterWeightCr=%u\n", p_t408->nrInterWeightCr); + + ni_log2(p_ctx, NI_LOG_DEBUG, "nrNoiseEstEnable=%u\n", p_t408->nrNoiseEstEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrNoiseSigmaY=%u\n", p_t408->nrNoiseSigmaY); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrNoiseSigmaCb=%u\n", p_t408->nrNoiseSigmaCb); + ni_log2(p_ctx, NI_LOG_DEBUG, "nrNoiseSigmaCr=%u\n", p_t408->nrNoiseSigmaCr); // newly added for T408 - ni_log(NI_LOG_DEBUG, "monochromeEnable=%u\n", p_t408->monochromeEnable); - ni_log(NI_LOG_DEBUG, "strongIntraSmoothEnable=%u\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "monochromeEnable=%u\n", p_t408->monochromeEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "strongIntraSmoothEnable=%u\n", p_t408->strongIntraSmoothEnable); - ni_log(NI_LOG_DEBUG, "weightPredEnable=%u\n", p_t408->weightPredEnable); - ni_log(NI_LOG_DEBUG, "bgDetectEnable=%u\n", p_t408->bgDetectEnable); - ni_log(NI_LOG_DEBUG, "bgThrDiff=%u\n", p_t408->bgThrDiff); - ni_log(NI_LOG_DEBUG, "bgThrMeanDiff=%u\n", p_t408->bgThrMeanDiff); - ni_log(NI_LOG_DEBUG, "bgLambdaQp=%u\n", p_t408->bgLambdaQp); - ni_log(NI_LOG_DEBUG, "bgDeltaQp=%d\n", p_t408->bgDeltaQp); - - ni_log(NI_LOG_DEBUG, "customLambdaEnable=%u\n", p_t408->customLambdaEnable); - ni_log(NI_LOG_DEBUG, "customMDEnable=%u\n", p_t408->customMDEnable); - ni_log(NI_LOG_DEBUG, "pu04DeltaRate=%d\n", p_t408->pu04DeltaRate); - ni_log(NI_LOG_DEBUG, "pu08DeltaRate=%d\n", p_t408->pu08DeltaRate); - ni_log(NI_LOG_DEBUG, "pu16DeltaRate=%d\n", p_t408->pu16DeltaRate); - ni_log(NI_LOG_DEBUG, "pu32DeltaRate=%d\n", p_t408->pu32DeltaRate); - ni_log(NI_LOG_DEBUG, "pu04IntraPlanarDeltaRate=%d\n", p_t408->pu04IntraPlanarDeltaRate); - ni_log(NI_LOG_DEBUG, "pu04IntraDcDeltaRate=%d\n", p_t408->pu04IntraDcDeltaRate); - ni_log(NI_LOG_DEBUG, "pu04IntraAngleDeltaRate=%d\n", p_t408->pu04IntraAngleDeltaRate); - ni_log(NI_LOG_DEBUG, "pu08IntraPlanarDeltaRate=%d\n", p_t408->pu08IntraPlanarDeltaRate); - ni_log(NI_LOG_DEBUG, "pu08IntraDcDeltaRate=%d\n", p_t408->pu08IntraDcDeltaRate); - ni_log(NI_LOG_DEBUG, "pu08IntraAngleDeltaRate=%d\n", p_t408->pu08IntraAngleDeltaRate); - ni_log(NI_LOG_DEBUG, "pu16IntraPlanarDeltaRate=%d\n", p_t408->pu16IntraPlanarDeltaRate); - ni_log(NI_LOG_DEBUG, "pu16IntraDcDeltaRate=%d\n", p_t408->pu16IntraDcDeltaRate); - ni_log(NI_LOG_DEBUG, "pu16IntraAngleDeltaRate=%d\n", p_t408->pu16IntraAngleDeltaRate); - ni_log(NI_LOG_DEBUG, "pu32IntraPlanarDeltaRate=%d\n", p_t408->pu32IntraPlanarDeltaRate); - ni_log(NI_LOG_DEBUG, "pu32IntraDcDeltaRate=%d\n", p_t408->pu32IntraDcDeltaRate); - ni_log(NI_LOG_DEBUG, "pu32IntraAngleDeltaRate=%d\n", p_t408->pu32IntraAngleDeltaRate); - ni_log(NI_LOG_DEBUG, "cu08IntraDeltaRate=%d\n", p_t408->cu08IntraDeltaRate); - ni_log(NI_LOG_DEBUG, "cu08InterDeltaRate=%d\n", p_t408->cu08InterDeltaRate); - ni_log(NI_LOG_DEBUG, "cu08MergeDeltaRate=%d\n", p_t408->cu08MergeDeltaRate); - ni_log(NI_LOG_DEBUG, "cu16IntraDeltaRate=%d\n", p_t408->cu16IntraDeltaRate); - ni_log(NI_LOG_DEBUG, "cu16InterDeltaRate=%d\n", p_t408->cu16InterDeltaRate); - ni_log(NI_LOG_DEBUG, "cu16MergeDeltaRate=%d\n", p_t408->cu16MergeDeltaRate); - ni_log(NI_LOG_DEBUG, "cu32IntraDeltaRate=%d\n", p_t408->cu32IntraDeltaRate); - ni_log(NI_LOG_DEBUG, "cu32InterDeltaRate=%d\n", p_t408->cu32InterDeltaRate); - ni_log(NI_LOG_DEBUG, "cu32MergeDeltaRate=%d\n", p_t408->cu32MergeDeltaRate); - ni_log(NI_LOG_DEBUG, "coefClearDisable=%d\n", p_t408->coefClearDisable); - ni_log(NI_LOG_DEBUG, "minQpI=%d\n", p_t408->minQpI); - ni_log(NI_LOG_DEBUG, "maxQpI=%d\n", p_t408->maxQpI); - ni_log(NI_LOG_DEBUG, "minQpP=%d\n", p_t408->minQpP); - ni_log(NI_LOG_DEBUG, "maxQpP=%d\n", p_t408->maxQpP); - ni_log(NI_LOG_DEBUG, "minQpB=%d\n", p_t408->minQpB); - ni_log(NI_LOG_DEBUG, "maxQpB=%d\n", p_t408->maxQpB); + ni_log2(p_ctx, NI_LOG_DEBUG, "weightPredEnable=%u\n", p_t408->weightPredEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "bgDetectEnable=%u\n", p_t408->bgDetectEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "bgThrDiff=%u\n", p_t408->bgThrDiff); + ni_log2(p_ctx, NI_LOG_DEBUG, "bgThrMeanDiff=%u\n", p_t408->bgThrMeanDiff); + ni_log2(p_ctx, NI_LOG_DEBUG, "bgLambdaQp=%u\n", p_t408->bgLambdaQp); + ni_log2(p_ctx, NI_LOG_DEBUG, "bgDeltaQp=%d\n", p_t408->bgDeltaQp); + + ni_log2(p_ctx, NI_LOG_DEBUG, "customLambdaEnable=%u\n", p_t408->customLambdaEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "customMDEnable=%u\n", p_t408->customMDEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu04DeltaRate=%d\n", p_t408->pu04DeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu08DeltaRate=%d\n", p_t408->pu08DeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu16DeltaRate=%d\n", p_t408->pu16DeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu32DeltaRate=%d\n", p_t408->pu32DeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu04IntraPlanarDeltaRate=%d\n", p_t408->pu04IntraPlanarDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu04IntraDcDeltaRate=%d\n", p_t408->pu04IntraDcDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu04IntraAngleDeltaRate=%d\n", p_t408->pu04IntraAngleDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu08IntraPlanarDeltaRate=%d\n", p_t408->pu08IntraPlanarDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu08IntraDcDeltaRate=%d\n", p_t408->pu08IntraDcDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu08IntraAngleDeltaRate=%d\n", p_t408->pu08IntraAngleDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu16IntraPlanarDeltaRate=%d\n", p_t408->pu16IntraPlanarDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu16IntraDcDeltaRate=%d\n", p_t408->pu16IntraDcDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu16IntraAngleDeltaRate=%d\n", p_t408->pu16IntraAngleDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu32IntraPlanarDeltaRate=%d\n", p_t408->pu32IntraPlanarDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu32IntraDcDeltaRate=%d\n", p_t408->pu32IntraDcDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "pu32IntraAngleDeltaRate=%d\n", p_t408->pu32IntraAngleDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu08IntraDeltaRate=%d\n", p_t408->cu08IntraDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu08InterDeltaRate=%d\n", p_t408->cu08InterDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu08MergeDeltaRate=%d\n", p_t408->cu08MergeDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu16IntraDeltaRate=%d\n", p_t408->cu16IntraDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu16InterDeltaRate=%d\n", p_t408->cu16InterDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu16MergeDeltaRate=%d\n", p_t408->cu16MergeDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu32IntraDeltaRate=%d\n", p_t408->cu32IntraDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu32InterDeltaRate=%d\n", p_t408->cu32InterDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "cu32MergeDeltaRate=%d\n", p_t408->cu32MergeDeltaRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "coefClearDisable=%d\n", p_t408->coefClearDisable); + ni_log2(p_ctx, NI_LOG_DEBUG, "minQpI=%d\n", p_t408->minQpI); + ni_log2(p_ctx, NI_LOG_DEBUG, "maxQpI=%d\n", p_t408->maxQpI); + ni_log2(p_ctx, NI_LOG_DEBUG, "minQpP=%d\n", p_t408->minQpP); + ni_log2(p_ctx, NI_LOG_DEBUG, "maxQpP=%d\n", p_t408->maxQpP); + ni_log2(p_ctx, NI_LOG_DEBUG, "minQpB=%d\n", p_t408->minQpB); + ni_log2(p_ctx, NI_LOG_DEBUG, "maxQpB=%d\n", p_t408->maxQpB); // for H.264 on T408 - ni_log(NI_LOG_DEBUG, "avcIdrPeriod=%d\n", p_t408->avcIdrPeriod); - ni_log(NI_LOG_DEBUG, "rdoSkip=%d\n", p_t408->rdoSkip); - ni_log(NI_LOG_DEBUG, "lambdaScalingEnable=%d\n", p_t408->lambdaScalingEnable); - ni_log(NI_LOG_DEBUG, "enable_transform_8x8=%d\n", p_t408->enable_transform_8x8); - ni_log(NI_LOG_DEBUG, "avc_slice_mode=%d\n", p_t408->avc_slice_mode); - ni_log(NI_LOG_DEBUG, "avc_slice_arg=%d\n", p_t408->avc_slice_arg); - ni_log(NI_LOG_DEBUG, "intra_mb_refresh_mode=%d\n", p_t408->intra_mb_refresh_mode); - ni_log(NI_LOG_DEBUG, "intra_mb_refresh_arg=%d\n", p_t408->intra_mb_refresh_arg); - ni_log(NI_LOG_DEBUG, "enable_mb_level_rc=%d\n", p_t408->enable_mb_level_rc); - ni_log(NI_LOG_DEBUG, "entropy_coding_mode=%d\n", p_t408->entropy_coding_mode); - ni_log(NI_LOG_DEBUG, "forcedHeaderEnable=%u\n", p_t408->forcedHeaderEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "avcIdrPeriod=%d\n", p_t408->avcIdrPeriod); + ni_log2(p_ctx, NI_LOG_DEBUG, "rdoSkip=%d\n", p_t408->rdoSkip); + ni_log2(p_ctx, NI_LOG_DEBUG, "lambdaScalingEnable=%d\n", p_t408->lambdaScalingEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "enable_transform_8x8=%d\n", p_t408->enable_transform_8x8); + ni_log2(p_ctx, NI_LOG_DEBUG, "slice_mode=%d\n", p_t408->slice_mode); + ni_log2(p_ctx, NI_LOG_DEBUG, "slice_arg=%d\n", p_t408->slice_arg); + ni_log2(p_ctx, NI_LOG_DEBUG, "intra_mb_refresh_mode=%d\n", p_t408->intra_mb_refresh_mode); + ni_log2(p_ctx, NI_LOG_DEBUG, "intra_mb_refresh_arg=%d\n", p_t408->intra_mb_refresh_arg); + ni_log2(p_ctx, NI_LOG_DEBUG, "enable_mb_level_rc=%d\n", p_t408->enable_mb_level_rc); + ni_log2(p_ctx, NI_LOG_DEBUG, "entropy_coding_mode=%d\n", p_t408->entropy_coding_mode); + ni_log2(p_ctx, NI_LOG_DEBUG, "forcedHeaderEnable=%u\n", p_t408->forcedHeaderEnable); //QUADRA - ni_log(NI_LOG_DEBUG, "ui8EnableAUD=%d\n", p_cfg->ui8EnableAUD); - ni_log(NI_LOG_DEBUG, "ui8LookAheadDepth=%d\n", p_cfg->ui8LookAheadDepth); - ni_log(NI_LOG_DEBUG, "ui8rdoLevel=%d\n", p_cfg->ui8rdoLevel); - ni_log(NI_LOG_DEBUG, "i8crf=%d\n", p_cfg->i8crf); - ni_log(NI_LOG_DEBUG, "ui16HDR10MaxLight=%d\n", p_cfg->ui16HDR10MaxLight); - ni_log(NI_LOG_DEBUG, "ui16HDR10AveLight=%d\n", p_cfg->ui16HDR10AveLight); - ni_log(NI_LOG_DEBUG, "ui8HDR10CLLEnable=%d\n", p_cfg->ui8HDR10CLLEnable); - ni_log(NI_LOG_DEBUG, "ui8EnableRdoQuant=%d\n", p_cfg->ui8EnableRdoQuant); - ni_log(NI_LOG_DEBUG, "ui8ctbRcMode=%d\n", p_cfg->ui8ctbRcMode); - ni_log(NI_LOG_DEBUG, "ui8gopSize=%d\n", p_cfg->ui8gopSize); - ni_log(NI_LOG_DEBUG, "ui8useLowDelayPocType=%d\n", p_cfg->ui8useLowDelayPocType); - ni_log(NI_LOG_DEBUG, "ui8gopLowdelay=%d\n", p_cfg->ui8gopLowdelay); - ni_log(NI_LOG_DEBUG, "ui16gdrDuration=%d\n", p_cfg->ui16gdrDuration); - ni_log(NI_LOG_DEBUG, "ui8hrdEnable=%d\n", p_cfg->ui8hrdEnable); - ni_log(NI_LOG_DEBUG, "ui8colorDescPresent=%d\n", p_cfg->ui8colorDescPresent); - ni_log(NI_LOG_DEBUG, "ui8colorPrimaries=%d\n", p_cfg->ui8colorPrimaries); - ni_log(NI_LOG_DEBUG, "ui8colorTrc=%d\n", p_cfg->ui8colorTrc); - ni_log(NI_LOG_DEBUG, "ui8colorSpace=%d\n", p_cfg->ui8colorSpace); - ni_log(NI_LOG_DEBUG, "ui16aspectRatioWidth=%d\n", p_cfg->ui16aspectRatioWidth); - ni_log(NI_LOG_DEBUG, "ui16aspectRatioHeight=%d\n", p_cfg->ui16aspectRatioHeight); - ni_log(NI_LOG_DEBUG, "ui16rootBufId=%d\n", p_cfg->ui16rootBufId); - ni_log(NI_LOG_DEBUG, "ui8planarFormat=%d\n", p_cfg->ui8planarFormat); - ni_log(NI_LOG_DEBUG, "ui32ltrRefInterval=%u\n", p_cfg->ui32ltrRefInterval); - ni_log(NI_LOG_DEBUG, "i32ltrRefQpOffset=%d\n", p_cfg->i32ltrRefQpOffset); - ni_log(NI_LOG_DEBUG, "ui32ltrFirstGap=%u\n", p_cfg->ui32ltrFirstGap); - ni_log(NI_LOG_DEBUG, "ui32ltrNextInterval=%u\n", p_cfg->ui32ltrNextInterval); - ni_log(NI_LOG_DEBUG, "ui8multicoreJointMode=%d\n", p_cfg->ui8multicoreJointMode); - ni_log(NI_LOG_DEBUG, "ui8videoFullRange=%u\n", p_cfg->ui8videoFullRange); - ni_log(NI_LOG_DEBUG, "ui32QLevel=%u\n", p_cfg->ui32QLevel); - ni_log(NI_LOG_DEBUG, "i8chromaQpOffset=%d\n", p_cfg->i8chromaQpOffset); - ni_log(NI_LOG_DEBUG, "i32tolCtbRcInter=0x%x\n", p_cfg->i32tolCtbRcInter); - ni_log(NI_LOG_DEBUG, "i32tolCtbRcIntra=0x%x\n", p_cfg->i32tolCtbRcIntra); - ni_log(NI_LOG_DEBUG, "i16bitrateWindow=%d\n", p_cfg->i16bitrateWindow); - ni_log(NI_LOG_DEBUG, "ui8inLoopDSRatio=%u\n", p_cfg->ui8inLoopDSRatio); - ni_log(NI_LOG_DEBUG, "ui8blockRCSize=%u\n", p_cfg->ui8blockRCSize); - ni_log(NI_LOG_DEBUG, "ui8rcQpDeltaRange=%u\n", p_cfg->ui8rcQpDeltaRange); - ni_log(NI_LOG_DEBUG, "ui8LowDelay=%d\n", p_cfg->ui8LowDelay); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8EnableAUD=%d\n", p_cfg->ui8EnableAUD); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8LookAheadDepth=%d\n", p_cfg->ui8LookAheadDepth); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8rdoLevel=%d\n", p_cfg->ui8rdoLevel); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8crf=%d\n", p_cfg->i8crf); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8crfDecimal=%d\n", p_cfg->i8crfDecimal); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16HDR10MaxLight=%d\n", p_cfg->ui16HDR10MaxLight); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16HDR10AveLight=%d\n", p_cfg->ui16HDR10AveLight); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8HDR10CLLEnable=%d\n", p_cfg->ui8HDR10CLLEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8EnableRdoQuant=%d\n", p_cfg->ui8EnableRdoQuant); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8ctbRcMode=%d\n", p_cfg->ui8ctbRcMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8gopSize=%d\n", p_cfg->ui8gopSize); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8useLowDelayPocType=%d\n", p_cfg->ui8useLowDelayPocType); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8gopLowdelay=%d\n", p_cfg->ui8gopLowdelay); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16gdrDuration=%d\n", p_cfg->ui16gdrDuration); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8hrdEnable=%d\n", p_cfg->ui8hrdEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8colorDescPresent=%d\n", p_cfg->ui8colorDescPresent); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8colorPrimaries=%d\n", p_cfg->ui8colorPrimaries); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8colorTrc=%d\n", p_cfg->ui8colorTrc); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8colorSpace=%d\n", p_cfg->ui8colorSpace); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16aspectRatioWidth=%d\n", p_cfg->ui16aspectRatioWidth); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16aspectRatioHeight=%d\n", p_cfg->ui16aspectRatioHeight); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16rootBufId=%d\n", p_cfg->ui16rootBufId); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8planarFormat=%d\n", p_cfg->ui8planarFormat); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8PixelFormat=%d\n", p_cfg->ui8PixelFormat); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32ltrRefInterval=%u\n", p_cfg->ui32ltrRefInterval); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32ltrRefQpOffset=%d\n", p_cfg->i32ltrRefQpOffset); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32ltrFirstGap=%u\n", p_cfg->ui32ltrFirstGap); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32ltrNextInterval=%u\n", p_cfg->ui32ltrNextInterval); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8multicoreJointMode=%d\n", p_cfg->ui8multicoreJointMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8videoFullRange=%u\n", p_cfg->ui8videoFullRange); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32QLevel=%u\n", p_cfg->ui32QLevel); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8chromaQpOffset=%d\n", p_cfg->i8chromaQpOffset); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32tolCtbRcInter=0x%x\n", p_cfg->i32tolCtbRcInter); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32tolCtbRcIntra=0x%x\n", p_cfg->i32tolCtbRcIntra); + ni_log2(p_ctx, NI_LOG_DEBUG, "i16bitrateWindow=%d\n", p_cfg->i16bitrateWindow); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8inLoopDSRatio=%u\n", p_cfg->ui8inLoopDSRatio); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8blockRCSize=%u\n", p_cfg->ui8blockRCSize); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8rcQpDeltaRange=%u\n", p_cfg->ui8rcQpDeltaRange); + ni_log2(p_ctx, NI_LOG_DEBUG, "i16ctbRowQpStep=%u\n", p_cfg->i16ctbRowQpStep); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8NewRCEnable=%u\n", p_cfg->ui8NewRCEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8LowDelay=%d\n", p_cfg->ui8LowDelay); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8hdr10_enable=%u\n", p_cfg->ui8hdr10_enable); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_dx0=%u\n", p_cfg->ui16hdr10_dx0); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_dy0=%u\n", p_cfg->ui16hdr10_dy0); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_dx1=%u\n", p_cfg->ui16hdr10_dx1); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_dy1=%u\n", p_cfg->ui16hdr10_dy1); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_dx2=%u\n", p_cfg->ui16hdr10_dx2); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_dy2=%u\n", p_cfg->ui16hdr10_dy2); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_wx=%u\n", p_cfg->ui16hdr10_wx); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16hdr10_wy=%u\n", p_cfg->ui16hdr10_wy); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32hdr10_maxluma=%u\n", p_cfg->ui32hdr10_maxluma); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32hdr10_minluma=%u\n", p_cfg->ui32hdr10_minluma); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8av1ErrResilientMode=%u\n", p_cfg->ui8av1ErrResilientMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8intraResetRefresh=%d\n", p_cfg->ui8intraResetRefresh); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8temporalLayersEnable=%u\n", p_cfg->ui8temporalLayersEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8enable2PassGopPattern=%u\n", p_cfg->ui8enable2PassGopPatern); + ni_log2(p_ctx, NI_LOG_DEBUG, "zerocopy_mode=%d\n", p_src->zerocopy_mode); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32lumaLinesize=%u\n", p_cfg->ui32lumaLinesize); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32chromaLinesize=%u\n", p_cfg->ui32chromaLinesize); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32cropWidth=%u\n", p_cfg->ui32cropWidth); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32cropHeight=%u\n", p_cfg->ui32cropHeight); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32horOffset=%u\n", p_cfg->ui32horOffset); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32verOffset=%u\n", p_cfg->ui32verOffset); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8crfMax=%d\n", p_cfg->i8crfMax); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32qcomp=%d\n", p_cfg->i32qcomp); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8noMbtree=%u\n", p_cfg->ui8noMbtree); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8noHWMultiPassSupport=%u\n", p_cfg->ui8noHWMultiPassSupport); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8cuTreeFactor=%d\n", p_cfg->i8cuTreeFactor); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32ipRatio=%d\n", p_cfg->i32ipRatio); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32pbRatio=%d\n", p_cfg->i32pbRatio); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32cplxDecay=%d\n", p_cfg->i32cplxDecay); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8ppsInitQp=%d\n", p_cfg->i8ppsInitQp); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8bitrateMode=%u\n", p_cfg->ui8bitrateMode); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8pass1Qp=%d\n", p_cfg->i8pass1Qp); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8crfDecimal=%d\n", p_cfg->i8crfDecimal); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8hvsBaseMbComplexity=%u\n", p_cfg->i8hvsBaseMbComplexity); + ni_log2(p_ctx, NI_LOG_DEBUG, "i8enableipRatio=%d\n",p_cfg->i8enableipRatio); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui16iFrameSizeRatio=%u\n",p_cfg->ui16iFrameSizeRatio); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8crfMaxIframeEnable=%u\n", p_cfg->ui8crfMaxIframeEnable); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui32vbvMinRate=%u\n", p_cfg->ui32vbvMinRate); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8disableBframeRDOQ=%u\n", p_cfg->ui8disableBframeRDOQ); + ni_log2(p_ctx, NI_LOG_DEBUG, "i32forceBframeQpFactor=%d\n", p_cfg->i32forceBframeQpFactor); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8tuneBframeVisual=%u\n", p_cfg->ui8tuneBframeVisual); + ni_log2(p_ctx, NI_LOG_DEBUG, "ui8EnableAcqLimit=%u\n", p_cfg->ui8EnableAcqLimit); } /*!****************************************************************************** @@ -6722,10 +8642,8 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p if( (!p_ctx) || (!p_config) ) { - ni_log( - NI_LOG_ERROR, - "ERROR: ni_set_default_template() Null pointer parameters passed\n", - __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", + __func__); return; } @@ -6738,7 +8656,7 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p p_config->ui8sliceMode = 0; // 0 means 1 slice per picture p_config->i32frameRateInfo = 30; p_config->i32frameRateDenominator = 1; - p_config->i32vbvBufferSize = 3000; //0; parameter is ignored if rate control is off, if rate control is on, 0 means do not check vbv constraints + p_config->i32vbvBufferSize = 0; //0; parameter is ignored if rate control is off, if rate control is on, 0 means do not check vbv constraints p_config->i32userQpMax = 51; // this should also be h264-only parameter // AVC only @@ -6751,7 +8669,7 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p } p_config->i32bitRate = 0; - p_config->i32bitRateBL = 0; // no documentation on this parameter in documents + p_config->i32bitRateBL = 0; p_config->ui8rcEnable = 0; p_config->i32srcBitDepth = p_ctx->src_bit_depth; p_config->ui8enablePTS = 0; @@ -6889,7 +8807,7 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p for (j = 0; j < NI_MAX_REF_PIC; j++) { p_config->niParamT408.custom_gop_params.pic_param[i].rps[j].ref_pic = 0; - p_config->niParamT408.custom_gop_params.pic_param[i].rps[j].ref_pic_used = 0; + p_config->niParamT408.custom_gop_params.pic_param[i].rps[j].ref_pic_used = -1; } } } @@ -6979,8 +8897,8 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p p_config->niParamT408.rdoSkip = 0; p_config->niParamT408.lambdaScalingEnable = 0; p_config->niParamT408.enable_transform_8x8 = 1; - p_config->niParamT408.avc_slice_mode = 0; - p_config->niParamT408.avc_slice_arg = 0; + p_config->niParamT408.slice_mode = 0; + p_config->niParamT408.slice_arg = 0; p_config->niParamT408.intra_mb_refresh_mode = 0; p_config->niParamT408.intra_mb_refresh_arg = 0; if (QUADRA) @@ -6993,7 +8911,7 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p //QUADRA p_config->ui8EnableAUD = 0; p_config->ui8LookAheadDepth = 0; - p_config->ui8rdoLevel = 1; + p_config->ui8rdoLevel = (NI_CODEC_FORMAT_JPEG == p_ctx->codec_format) ? 0 : 1; p_config->i8crf = -1; p_config->ui16HDR10MaxLight = 0; p_config->ui16HDR10AveLight = 0; @@ -7006,12 +8924,16 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p p_config->ui16gdrDuration = 0; p_config->ui8hrdEnable = 0; p_config->ui8colorDescPresent = 0; - p_config->ui8colorPrimaries = 0; - p_config->ui8colorTrc = 0; - p_config->ui8colorSpace = 0; + ////AVCOL_PRI_UNSPECIFIED =2 ffmpeg defaults + p_config->ui8colorPrimaries = 2; + //AVCOL_TRC_UNSPECIFIED + p_config->ui8colorTrc = 2; + //AVCOL_SPC_UNSPECIFIED + p_config->ui8colorSpace = 2; p_config->ui16aspectRatioWidth = 0; p_config->ui16aspectRatioHeight = 0; - p_config->ui8planarFormat = 1; + p_config->ui8planarFormat = NI_PIXEL_PLANAR_FORMAT_PLANAR; + p_config->ui8PixelFormat = NI_PIX_FMT_YUV420P; p_config->ui32ltrRefInterval = 0; p_config->i32ltrRefQpOffset = 0; p_config->ui32ltrFirstGap= 0; @@ -7028,9 +8950,50 @@ void ni_set_default_template(ni_session_context_t* p_ctx, ni_encoder_config_t* p p_config->ui8inLoopDSRatio = 1; p_config->ui8blockRCSize = 0; p_config->ui8rcQpDeltaRange = 10; + p_config->i16ctbRowQpStep = 0; + p_config->ui8NewRCEnable = 255; p_config->ui8LowDelay = 0; p_config->ui8fixedframerate = 1; p_config->ui8enableSSIM = 0; + p_config->ui8hdr10_enable = 0; + p_config->ui16hdr10_dx0 = 0; + p_config->ui16hdr10_dy0 = 0; + p_config->ui16hdr10_dx1 = 0; + p_config->ui16hdr10_dy1 = 0; + p_config->ui16hdr10_dx2 = 0; + p_config->ui16hdr10_dy2 = 0; + p_config->ui16hdr10_wx = 0; + p_config->ui16hdr10_wy = 0; + p_config->ui32hdr10_maxluma = 0; + p_config->ui32hdr10_minluma = 0; + p_config->ui8av1ErrResilientMode = 0; + p_config->ui8intraResetRefresh = 0; + p_config->ui8temporalLayersEnable = 0; + p_config->ui8enable2PassGopPatern = 0; + p_config->i8crfMax = (int8_t)(-1) + 1; // for old libxcoder backward compatibility, use 1 to represent 0 + p_config->i32qcomp = (int32_t)(0.6 * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + p_config->ui8noMbtree = 0; + p_config->ui8noHWMultiPassSupport = 0; + p_config->i8cuTreeFactor = 5; + p_config->i32ipRatio = (int32_t)(1.4 * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + p_config->i32pbRatio = (int32_t)(1.3 * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + p_config->i32cplxDecay = (int32_t)(0.5 * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + p_config->ui32vbvMaxRate = 0; + p_config->i8ppsInitQp = (int8_t)(-1) + 1; // for old libxcoder backward compatibility, use 1 to represent 0 + p_config->ui8bitrateMode = 0; // bitrateMode 0 = max bitrate (actual bitrate can be lower than bitrate target), bitrateMode 1 = average bitrate (actual bitrate approximately equal to bitrate target) + p_config->i8pass1Qp = (int8_t)(-1) + 1; // for old libxcoder backward compatibility, use 1 to represent 0 + p_config->i8crfDecimal = 0; + p_config->i8hvsBaseMbComplexity = (int8_t)(15)-15; // for old libxcoder backward compatibility, use -15 to represent 0 + p_config->i8statisticOutputLevel = 0; + p_config->i8enableipRatio = 0; + p_config->ui16iFrameSizeRatio = 100; + p_config->u8skipFrameInterval = 0; + p_config->ui8crfMaxIframeEnable = 0; + p_config->ui32vbvMinRate = 0; + p_config->ui8disableBframeRDOQ = 0; + p_config->i32forceBframeQpFactor = (int32_t)(-1.0 * 1000) + 1000; // for old libxcoder backward compatibility, use 1000 to represent 0 + p_config->ui8tuneBframeVisual = 0; + p_config->ui8EnableAcqLimit = 0; } /*!****************************************************************************** @@ -7055,7 +9018,7 @@ ni_retcode_t ni_validate_custom_dec_template(ni_xcoder_params_t *p_src, if (!p_ctx || !p_cfg || !p_param_err) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", __func__); param_ret = NI_RETCODE_INVALID_PARAM; LRETURN; @@ -7065,7 +9028,7 @@ ni_retcode_t ni_validate_custom_dec_template(ni_xcoder_params_t *p_src, p_param_warn = malloc(sizeof(p_ctx->param_err_msg)); if (!p_param_warn) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() p_param_warn malloc failure\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() p_param_warn malloc failure\n", NI_ERRNO, __func__); param_ret = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; @@ -7090,6 +9053,18 @@ ni_retcode_t ni_validate_custom_dec_template(ni_xcoder_params_t *p_src, LRETURN; } + if (p_src->ddr_priority_mode >= 0) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6e") < 0) + { + strncpy(p_param_err, "ddr_priority_mode not supported on device with FW api version < 6.e", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + LRETURN; + } + } + for (i = 0; i < NI_MAX_NUM_OF_DECODER_OUTPUTS; i++) { //checking cropping param @@ -7143,19 +9118,16 @@ ni_retcode_t ni_validate_custom_dec_template(ni_xcoder_params_t *p_src, //checking scaling param if (p_cfg->asOutputConfig[i].ui8ScaleEnabled) { - if (p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height > h || - p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width > w) - { //may need to revisit if based on cropped input or base input for w/h limit - strncpy(p_param_err, "Invalid scale dimensions: must downscale only", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_OOR; - LRETURN; - } if (p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height == 0 || p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width == 0) - { //may need to revisit if based on cropped input or base input for w/h limit - strncpy(p_param_err, "Invalid scale dimensions: zero", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_TOO_SMALL; - LRETURN; + { + if (p_cfg->asOutputConfig[i].ui8EnablePpuScaleAdapt) + { + //may need to revisit if based on cropped input or base input for w/h limit + strncpy(p_param_err, "Invalid scale dimensions: zero", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_TOO_SMALL; + LRETURN; + } } if (p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height & 1 || p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width & 1 ) @@ -7189,6 +9161,83 @@ ni_retcode_t ni_validate_custom_dec_template(ni_xcoder_params_t *p_src, warning = NI_RETCODE_PARAM_WARN; } } + + //check tiled format compatibility + if (p_cfg->asOutputConfig[i].ui8SemiPlanarEnabled == NI_PIXEL_PLANAR_FORMAT_TILED4X4) + { + if (p_cfg->asOutputConfig[i].ui8Enabled == 0) + { + continue; + } + if (p_cfg->ui8HWFrame == 0) + { + strncpy(p_param_err, + "Invalid pairing: out=HW must be set with tiled format", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + if (p_ctx->codec_format == NI_CODEC_FORMAT_VP9) + { + strncpy(p_param_err, "Invalid pairing: VP9 not compatible with tiled format", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + if (p_cfg->asOutputConfig[i].ui8ScaleEnabled) + { + //only no need to check crop compat if scale is set + if (p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height % 4 || + p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Height < 128) + { + strncpy(p_param_err, + "Invalid scale height: mult of 4 only, >= 128", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + if (p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width % 4 || + p_cfg->asOutputConfig[i].sOutputPictureSize.ui16Width < NI_MIN_WIDTH) + { + //minimum supported dec is 128 but min enc is 144 so round up + strncpy(p_param_err, + "Invalid scale width: mult of 128 only, >= 144", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } + else if (p_cfg->asOutputConfig[i].ui8CropMode == NI_DEC_CROP_MODE_MANUAL) + { + if (p_cfg->asOutputConfig[i].sCroppingRectable.ui16H % 4 || + p_cfg->asOutputConfig[i].sCroppingRectable.ui16H < 128) + { + strncpy(p_param_err, + "Invalid crop height: mult of 4 only, >= 128", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + if (p_cfg->asOutputConfig[i].sCroppingRectable.ui16W % 4 || + p_cfg->asOutputConfig[i].sCroppingRectable.ui16W < NI_MIN_WIDTH) + { + //minimum supported dec is 128 but min enc is 144 so round up + strncpy(p_param_err, + "Invalid crop width: mult of 128 only, >= 144", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } + if (p_cfg->asOutputConfig[i].ui8Force8Bit) + { + strncpy(p_param_err, "Force 8 bit: not supported with tiled format\n", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } + }//end forloop if (warning == NI_RETCODE_PARAM_WARN && param_ret == NI_RETCODE_SUCCESS) { @@ -7198,7 +9247,7 @@ ni_retcode_t ni_validate_custom_dec_template(ni_xcoder_params_t *p_src, END: - ni_aligned_free(p_param_warn); + free(p_param_warn); return param_ret; } @@ -7253,6 +9302,7 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, ni_retcode_t param_ret = NI_RETCODE_SUCCESS; ni_retcode_t warning = NI_RETCODE_SUCCESS; char* p_param_warn = malloc(sizeof(p_ctx->param_err_msg)); + ni_encoder_cfg_params_t *p_enc; int i; if( (!p_ctx) || (!p_cfg) || (!p_src) || (!p_param_err) ) @@ -7264,6 +9314,7 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, } //Zero out the error buffer + p_enc = &p_src->cfg_enc_params; memset(p_param_err, 0, max_err_len); memset(p_param_warn, 0, max_err_len); @@ -7282,6 +9333,13 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, LRETURN; } + if (p_cfg->i32bitRate <= p_cfg->i32frameRateInfo) + { + strncpy(p_param_err, "Invalid i32bitRate: smaller than or equal to frame rate", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_BRATE; + LRETURN; + } + if (p_cfg->i32bitRate > NI_MAX_BITRATE) { strncpy(p_param_err, "Invalid i32bitRate: too big", max_err_len); @@ -7323,68 +9381,269 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, param_ret = NI_RETCODE_PARAM_ERROR_PIC_HEIGHT; LRETURN; } - - if (NI_RETCODE_SUCCESS != - ni_check_level(p_src->cfg_enc_params.level_idc, p_ctx->codec_format)) - { - strncpy(p_param_err, "Invalid Encoder Level: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_OOR; - LRETURN; - } - - if ((p_src->cfg_enc_params.intra_mb_refresh_mode < 0 || - p_src->cfg_enc_params.intra_mb_refresh_mode > 4) || - (NI_CODEC_FORMAT_H264 == p_ctx->codec_format && - p_src->cfg_enc_params.intra_mb_refresh_mode == 4)) - { - strncpy(p_param_err, "Invalid intra_mb_refresh_mode: out of range", - max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_OOR; - LRETURN; - } - - if (!QUADRA) + + if (p_cfg->ui32cropWidth || p_cfg->ui32cropHeight) { - if (GOP_PRESET_IDX_CUSTOM == p_cfg->niParamT408.gop_preset_index) - { - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size < 1) + // check cropping width & height are both non-zero + if (!p_cfg->ui32cropWidth || !p_cfg->ui32cropHeight) { - strncpy(p_param_err, "Invalid custom GOP paramaters: custom_gop_size too small", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + snprintf(p_param_err, max_err_len, "Invalid Crop Width x Height (%u x %u): both need to be specified", + p_cfg->ui32cropWidth, p_cfg->ui32cropHeight); + param_ret = NI_RETCODE_INVALID_PARAM; LRETURN; } - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size > - NI_MAX_GOP_NUM) + // check cropping width & height are even + if ((p_cfg->ui32cropWidth % 2) || (p_cfg->ui32cropHeight % 2)) { - strncpy(p_param_err, "Invalid custom GOP paramaters: custom_gop_size too big", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + snprintf(p_param_err, max_err_len, "Invalid Crop Width x Height (%u x %uu): must be even", + p_cfg->ui32cropWidth, p_cfg->ui32cropHeight); + param_ret = NI_RETCODE_INVALID_PARAM; LRETURN; } - } - } - else // QUADRA - { - if (GOP_PRESET_IDX_CUSTOM == p_cfg->niParamT408.gop_preset_index) + // check cropping width & height meet resoultion constraint (including AV1 max resoultion) + if (p_cfg->ui32cropWidth < NI_MIN_WIDTH) { - if (!p_cfg->niParamT408.custom_gop_params.custom_gop_size) - { - strncpy(p_param_err, - "Invalid custom GOP paramaters: custom gop size must > 0", - max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; - LRETURN; - } + snprintf(p_param_err, max_err_len, "Invalid Crop Width: less than %d", + NI_MIN_WIDTH); + param_ret = NI_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL; + LRETURN; } - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) - { - if (GOP_PRESET_IDX_CUSTOM != p_cfg->niParamT408.gop_preset_index && - GOP_PRESET_IDX_DEFAULT != p_cfg->niParamT408.gop_preset_index) - { - strncpy(p_param_err, - "Invalid custom GOP paramaters: selected gopPresetIdx is " - "not compatible with custom gop", - max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + if (p_cfg->ui32cropHeight < NI_MIN_HEIGHT) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Height: less than %d", + NI_MIN_HEIGHT); + param_ret = NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL; + LRETURN; + } + if (p_cfg->ui32cropWidth > NI_PARAM_MAX_WIDTH) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Width: exceeds %d", + NI_PARAM_MAX_WIDTH); + param_ret = NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG; + LRETURN; + } + if (p_cfg->ui32cropHeight > NI_PARAM_MAX_HEIGHT) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Height: exceeds %d", + NI_PARAM_MAX_HEIGHT); + param_ret = NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG; + LRETURN; + } + if (p_cfg->ui32cropWidth * p_cfg->ui32cropHeight > NI_MAX_RESOLUTION_AREA) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Width x Height: exceeds %d", + NI_MAX_RESOLUTION_AREA); + param_ret = NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG; + LRETURN; + } + + if (NI_CODEC_FORMAT_AV1 == p_ctx->codec_format) + { + if (p_cfg->ui32cropWidth > NI_PARAM_AV1_MAX_WIDTH) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Width: exceeds %d", + NI_PARAM_AV1_MAX_WIDTH); + param_ret = NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG; + LRETURN; + } + if (p_cfg->ui32cropHeight > NI_PARAM_AV1_MAX_HEIGHT) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Height: exceeds %d", + NI_PARAM_AV1_MAX_HEIGHT); + param_ret = NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG; + LRETURN; + } + if (p_cfg->ui32cropWidth * p_cfg->ui32cropHeight > NI_PARAM_AV1_MAX_AREA) + { + snprintf(p_param_err, max_err_len, "Invalid Crop Width x Height: exceeds %d", + NI_PARAM_AV1_MAX_AREA); + param_ret = NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG; + LRETURN; + } + } + + if (p_src->source_width < (p_cfg->ui32horOffset + p_cfg->ui32cropWidth)) + { + strncpy(p_param_err, "Invalid Crop Width: offset + crop width too big", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_PIC_WIDTH; + LRETURN; + } + if (p_src->source_height < (p_cfg->ui32verOffset + p_cfg->ui32cropHeight)) + { + strncpy(p_param_err, "Invalid Crop Height: offset + crop height too big", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_PIC_HEIGHT; + LRETURN; + } + } + else // check source width / height meet AV1 max resoultion constraint if cropping not specified + { + if (NI_CODEC_FORMAT_AV1 == p_ctx->codec_format) + { + if (p_src->source_width > NI_PARAM_AV1_MAX_WIDTH) + { + snprintf(p_param_err, max_err_len, "Invalid Picture Width: exceeds %d", + NI_PARAM_AV1_MAX_WIDTH); + param_ret = NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG; + LRETURN; + } + if (p_src->source_height > NI_PARAM_AV1_MAX_HEIGHT) + { + snprintf(p_param_err, max_err_len, "Invalid Picture Height: exceeds %d", + NI_PARAM_AV1_MAX_HEIGHT); + param_ret = NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG; + LRETURN; + } + if (p_src->source_width * p_src->source_height > NI_PARAM_AV1_MAX_AREA) + { + snprintf(p_param_err, max_err_len, "Invalid Picture Width x Height: exceeds %d", + NI_PARAM_AV1_MAX_AREA); + param_ret = NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG; + LRETURN; + } + } + } + + if (p_cfg->ui8planarFormat >= NI_PIXEL_PLANAR_MAX) + { + strncpy(p_param_err, "Invalid input planar format: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_OOR; + LRETURN; + } + else if (p_cfg->ui8planarFormat == NI_PIXEL_PLANAR_FORMAT_TILED4X4) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "68") < 0) + { + strncpy(p_param_err, "Invalid input planar format for device with FW api version < 6.8", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + LRETURN; + } + if (p_ctx->auto_dl_handle) + { + strncpy(p_param_err, "Invalid Encoder Selected: Tiled format must be on same device", + max_err_len); + param_ret = NI_RETCODE_ERROR_INVALID_HANDLE; + LRETURN; + } + if (p_src->source_height % 4 != 0) + { + strncpy(p_param_err, + "Invalid Picture Height: tiled format only supports " + "multiples of 4", + max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_PIC_HEIGHT; + LRETURN; + } + if (p_src->source_width % 4 != 0) + { + strncpy(p_param_err, + "Invalid Picture Width: tiled format only supports " + "multiples of 4", + max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_PIC_WIDTH; + LRETURN; + } + } + + if (p_cfg->ui8PixelFormat == NI_PIX_FMT_RGBA || + p_cfg->ui8PixelFormat == NI_PIX_FMT_BGRA || + p_cfg->ui8PixelFormat == NI_PIX_FMT_ABGR || + p_cfg->ui8PixelFormat == NI_PIX_FMT_ARGB) + { + if (p_src->zerocopy_mode == 0) + { + strncpy(p_param_err, "zeroCopyMode must not be disabled for RGBA / BGRA / ABGR / ARGB pixel formats", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + if (p_cfg->ui8PixelFormat == NI_PIX_FMT_RGBA || + p_cfg->ui8PixelFormat == NI_PIX_FMT_BGRA) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6Y") < 0) + { + strncpy(p_param_err, "RGBA / BGRA pixel formats not supported on device with FW api version < 6.Y", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + LRETURN; + } + } + } + + if (p_src->ddr_priority_mode >= 0) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6e") < 0) + { + strncpy(p_param_err, "ddr_priority_mode not supported on device with FW api version < 6.e", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + LRETURN; + } + } + + if (NI_RETCODE_SUCCESS != + ni_check_level(p_src->cfg_enc_params.level_idc, p_ctx->codec_format)) + { + strncpy(p_param_err, "Invalid Encoder Level: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_OOR; + LRETURN; + } + + if ((p_src->cfg_enc_params.intra_mb_refresh_mode < 0 || + p_src->cfg_enc_params.intra_mb_refresh_mode > 4) || + (NI_CODEC_FORMAT_H264 == p_ctx->codec_format && + p_src->cfg_enc_params.intra_mb_refresh_mode == 4)) + { + strncpy(p_param_err, "Invalid intra_mb_refresh_mode: out of range", + max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_OOR; + LRETURN; + } + + if (!QUADRA) + { + if (GOP_PRESET_IDX_CUSTOM == p_cfg->niParamT408.gop_preset_index) + { + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size < 1) + { + strncpy(p_param_err, "Invalid custom GOP paramaters: custom_gop_size too small", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size > + NI_MAX_GOP_NUM) + { + strncpy(p_param_err, "Invalid custom GOP paramaters: custom_gop_size too big", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } + } + else // QUADRA + { + if (GOP_PRESET_IDX_CUSTOM == p_cfg->niParamT408.gop_preset_index) + { + if (!p_cfg->niParamT408.custom_gop_params.custom_gop_size) + { + strncpy(p_param_err, + "Invalid custom GOP paramaters: custom gop size must > 0", + max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + { + if (GOP_PRESET_IDX_CUSTOM != p_cfg->niParamT408.gop_preset_index && + GOP_PRESET_IDX_DEFAULT != p_cfg->niParamT408.gop_preset_index) + { + strncpy(p_param_err, + "Invalid custom GOP paramaters: selected gopPresetIdx is " + "not compatible with custom gop", + max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; LRETURN; } if (p_cfg->niParamT408.custom_gop_params.custom_gop_size < 1) @@ -7400,44 +9659,157 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; LRETURN; } + + for (i = 0; i < p_cfg->niParamT408.custom_gop_params.custom_gop_size; i++) + { + if (p_cfg->niParamT408.custom_gop_params.pic_param[i].poc_offset > + p_cfg->niParamT408.custom_gop_params.custom_gop_size) + { + strncpy(p_param_err, "Invalid custom gop parameters: poc_offset larger" + " than GOP size", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } } - if(p_cfg->ui8enableSSIM != 0) + if(p_cfg->ui8useLowDelayPocType != 0) { - if (!is_fw_rev_higher(p_ctx, (uint8_t)'6', (uint8_t)'1')) + if (NI_CODEC_FORMAT_H264 != p_ctx->codec_format) { - p_cfg->ui8enableSSIM = 0; - strncpy(p_param_warn, "enableSSIM is not supported for FW lower than Rev 62. All ssim will be 0.", max_err_len); + p_cfg->ui8useLowDelayPocType = 0; + strncpy(p_param_warn, "useLowDelayPocType is only supported for H.264. Change useLowDelayPocType to 0", max_err_len); warning = NI_RETCODE_PARAM_WARN; } - if ((NI_CODEC_FORMAT_H264 != p_ctx->codec_format) && (NI_CODEC_FORMAT_H265 != p_ctx->codec_format)) + } + if(p_cfg->niParamT408.entropy_coding_mode != 1) + { + if (NI_CODEC_FORMAT_H264 != p_ctx->codec_format) + { + strncpy(p_param_err, + "entropyCodingMode is only supported for H.264.", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + } + if (p_cfg->ui8av1ErrResilientMode) + { + if (NI_CODEC_FORMAT_AV1 != p_ctx->codec_format) + { + strncpy(p_param_err, + "av1ErrorResilientMode is only supported for AV1.", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + } + if (-1 != p_cfg->ui32QLevel) + { + if (NI_CODEC_FORMAT_JPEG != p_ctx->codec_format) + { + strncpy(p_param_err, "qLevel is only supported for JPEG.", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + } + + if(p_cfg->ui8enableSSIM != 0) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "62") < 0) { p_cfg->ui8enableSSIM = 0; - strncpy(p_param_warn, "enableSSIM is only supported on H.264 or H.265", max_err_len); + strncpy(p_param_warn, "enableSSIM is not supported on device with FW api version < 6.2. Reported ssim will be 0.", max_err_len); warning = NI_RETCODE_PARAM_WARN; } } + + if (p_cfg->niParamT408.slice_mode || p_cfg->niParamT408.slice_arg) + { + if (NI_CODEC_FORMAT_JPEG == p_ctx->codec_format || NI_CODEC_FORMAT_AV1 == p_ctx->codec_format) + { + strncpy(p_param_err, "sliceMode/sliceArg is only supported for H.264 or H.265.", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + + if (p_cfg->niParamT408.slice_mode) + { + int ctu_mb_size = (NI_CODEC_FORMAT_H264 == p_ctx->codec_format) ? 16 : 64; + int max_num_ctu_mb_row = (p_src->source_height + ctu_mb_size - 1) / ctu_mb_size; + if (p_cfg->niParamT408.slice_arg < 1 || p_cfg->niParamT408.slice_arg > max_num_ctu_mb_row) + { + snprintf(p_param_err, max_err_len, "Invalid number of rows per slice: should be between 1 and %d", + max_num_ctu_mb_row); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } + } + if (p_src->use_low_delay_poc_type) + { + if (NI_CODEC_FORMAT_H264 != p_ctx->codec_format) + { + strncpy(p_param_err, "useLowDelayPocType is only supported for H.264.", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + } } if (QUADRA) { - if (p_cfg->ui8LookAheadDepth != 0) + if (p_cfg->ui8LookAheadDepth != 0 || p_cfg->i8crf >= 0) { - if (1 == p_cfg->niParamT408.gop_preset_index || + if ((1 == p_cfg->niParamT408.gop_preset_index && p_cfg->ui8LookAheadDepth != 0) || 3 == p_cfg->niParamT408.gop_preset_index || 7 == p_cfg->niParamT408.gop_preset_index || - 9 == p_cfg->niParamT408.gop_preset_index) + 10 == p_cfg->niParamT408.gop_preset_index) { strncpy(p_param_err, - "this gopPreset is not supported when lookaheadDepth > 0", + "this gopPreset is not supported for lookahead and/or CRF", max_err_len); param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; LRETURN; } - if (p_src->source_width < 288) + + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + { + bool bIsgopLowdelay = true; + // lookahead does not support gopLowDelay (all B-frames, encode in order) gop patterns + for (i = 0; i < p_cfg->niParamT408.custom_gop_params.custom_gop_size; + i++) + { + // check if all frames are B-frames + if (2 != p_cfg->niParamT408.custom_gop_params.pic_param[i].pic_type) + { + bIsgopLowdelay = false; + break; + } + // check if all frames are encoded in display order + if (p_cfg->niParamT408.custom_gop_params.pic_param[i].poc_offset != (i+1)) + { + bIsgopLowdelay = false; + break; + } + } + if (bIsgopLowdelay) + { + strncpy(p_param_err, "B-frames low delay custom gop is not supported for " + "lookahead and/or CRF", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + } + + if (p_enc->bitrateMode != -1) { strncpy(p_param_err, - "lookAheadDepth requires input width of at least 288", + "bitrateMode is invalid when lookahead is enabled (or in CRF mode)", max_err_len); param_ret = NI_RETCODE_PARAM_ERROR_PIC_WIDTH; LRETURN; @@ -7505,6 +9877,34 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, p_cfg->ui8gopSize = 1; p_cfg->ui8gopLowdelay = 0; } + if (10 == p_cfg->niParamT408.gop_preset_index) + { + p_cfg->ui8gopSize = 4; + p_cfg->ui8gopLowdelay = 0; + } + + if (p_cfg->ui8LookAheadDepth != 0 + || p_cfg->ui8bitrateMode == 1 + || p_cfg->ui32vbvMaxRate + || p_cfg->ui32vbvMinRate + || p_cfg->i8enableipRatio) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Force newRcEnable to 0 in 2-pass encode or in 1-pass average bitrate mode, with ipRatio, VbvMaxRate, or VbvMinRate\n"); + p_cfg->ui8NewRCEnable = 0; + } + else if (p_cfg->ui8NewRCEnable == 255) + { + if ((p_cfg->ui8gopSize > 1 || p_cfg->ui8gopSize == 0) && p_cfg->ui8gopLowdelay == 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Set newRcEnable to 0 in non low delay gop preset\n"); + p_cfg->ui8NewRCEnable = 0; + } + else if (p_cfg->niParamT408.intra_period == 1 || p_cfg->niParamT408.avcIdrPeriod == 1) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Set newRcEnable to 0 in intra only mode\n"); + p_cfg->ui8NewRCEnable = 0; + } + } } if (NI_CODEC_FORMAT_H264 == p_ctx->codec_format) @@ -7587,7 +9987,8 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, } } } else if (((p_cfg->ui8gopSize != 1 || p_cfg->ui8gopLowdelay)) && - (p_cfg->niParamT408.intra_period != 1)) + (p_cfg->niParamT408.intra_period != 1) && + (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_HIERARCHICAL_IPPPP)) { if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_DEFAULT || p_cfg->ui8gopSize != 0 || @@ -7595,7 +9996,7 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, ->ui8gopLowdelay) // if gopSize is 0 (default / adapative gop), autoset to 1 { strncpy(p_param_err, - "GOP size must be 1 and must not use low delay GOP (no " + "Must use gopPresetIdx 1,9,10 (no " "B frames) for profile 1", max_err_len); param_ret = NI_RETCODE_INVALID_PARAM; @@ -7604,6 +10005,12 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, p_cfg->ui8gopSize = 1; //autoset to 1 } } + if (p_cfg->niParamT408.tier) + { + strncpy(p_param_err, "Tier is not supported for H.264", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } } } else if (NI_CODEC_FORMAT_H265 == p_ctx->codec_format) @@ -7706,3255 +10113,5578 @@ ni_retcode_t ni_validate_custom_template(ni_session_context_t *p_ctx, max_err_len); warning = NI_RETCODE_PARAM_WARN; } - } - - if (p_src->force_frame_type != 0 && p_src->force_frame_type != 1) - { - strncpy(p_param_err, "Invalid forceFrameType: out of range", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - - if (p_cfg->niParamT408.forcedHeaderEnable > 2) - { - strncpy(p_param_err, "Invalid forcedHeaderEnable: out of range", - max_err_len); - param_ret = NI_RETCODE_PARAM_INVALID_VALUE; - LRETURN; - } - - if (p_cfg->niParamT408.decoding_refresh_type < 0 || - p_cfg->niParamT408.decoding_refresh_type > 2) - { - strncpy(p_param_err, "Invalid decoding_refresh_type: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE; - LRETURN; - } - - if (!QUADRA) - { - if (p_cfg->niParamT408.gop_preset_index < 0 || - p_cfg->niParamT408.gop_preset_index > 8) - { - strcpy(p_param_err, "Invalid gop_preset_index: out of range"); - param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; - LRETURN; - } - - if (p_src->low_delay_mode && 1 != p_cfg->niParamT408.gop_preset_index && - 2 != p_cfg->niParamT408.gop_preset_index && - 3 != p_cfg->niParamT408.gop_preset_index && - 6 != p_cfg->niParamT408.gop_preset_index && - 7 != p_cfg->niParamT408.gop_preset_index && - !(0 == p_cfg->niParamT408.gop_preset_index && - 1 == p_cfg->niParamT408.custom_gop_params.custom_gop_size)) - { - strcpy(p_param_err, "GOP size must be 1 when lowDelay is enabled"); - param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; - LRETURN; - } - } - else // QUADRA - { - if (p_cfg->ui8gopSize > 8) + if (p_cfg->ui8hdr10_enable) { - strncpy(p_param_err, "Invalid gopSize out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; - LRETURN; + strncpy(p_param_err, + "masterDisplay not supported for AV1", + max_err_len); + warning = NI_RETCODE_PARAM_WARN; } - - if (p_cfg->ui8gopLowdelay && - p_cfg->ui8gopSize > 4) - { - strncpy(p_param_err, "GOP size must be <= 4 for low delay GOP", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; - LRETURN; - } - - if (p_cfg->ui8LookAheadDepth) - { - if (p_cfg->ui8LookAheadDepth < 4 || p_cfg->ui8LookAheadDepth > 40) + if (p_cfg->ui8hrdEnable) { - strncpy(p_param_err, "Invalid LookAheadDepth: out of range. <[4-40]>", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH; - LRETURN; + strncpy(p_param_err, "hrdEnable is not supported on av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (p_cfg->ui8gopLowdelay) + if (p_cfg->ui8EnableAUD) { - strncpy(p_param_err, "2-pass encode does not support low delay GOP", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; - LRETURN; + strncpy(p_param_err, "enableAUD is not supported on av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - - } - - if (p_src->low_delay_mode || p_cfg->ui8picSkipEnable) - { - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + if (p_cfg->ui8HDR10CLLEnable) { - for (i = 0; i < p_cfg->niParamT408.custom_gop_params.custom_gop_size; i++) - { - if (p_cfg->niParamT408.custom_gop_params.pic_param[i].poc_offset != (i+1)) - { - if (p_src->low_delay_mode) - strncpy(p_param_err, "Custom GOP must not include backward prediction when lowDelay is enabled", max_err_len); - else - strncpy(p_param_err, "Custom GOP must not include backward prediction when picSkip is enabled", max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - } - } else if (1 != p_cfg->ui8gopSize && !p_cfg->ui8gopLowdelay && - p_cfg->niParamT408.intra_period != 1) + strncpy(p_param_err, "maxCLL is not supported on av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8repeatHeaders) { - if (p_src->low_delay_mode) - strncpy(p_param_err, "Must use low delay GOP (gopPresetIdx 1,3,7,9) when lowDelay is enabled", max_err_len); - else - strncpy(p_param_err, "Must use low delay GOP (gopPresetIdx 1,3,7,9) when picSkip is enabled", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; - LRETURN; + strncpy(p_param_err, "repeatHeaders is not supported on av1 encoder", + max_err_len); + warning = NI_RETCODE_PARAM_WARN; } - - if (p_cfg->ui8multicoreJointMode) + if (p_cfg->ui8enableSSIM) { - if (p_src->low_delay_mode) - strncpy(p_param_err, - "Cannot use multicoreJointMode when lowDelay is enabled", - max_err_len); - else - strncpy(p_param_err, - "Cannot use multicoreJointMode when picSkip is enabled", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; + strncpy(p_param_err, "enableSSIM is not supported on av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; } - } - - if (p_src->low_delay_mode) - { - if (p_cfg->ui16maxFrameSize == 0) + if (p_cfg->ui8EnableRdoQuant) { - p_cfg->ui16maxFrameSize = ((p_src->source_width * p_src->source_height * 3 / 4) * p_ctx->bit_depth_factor) / 2000; - ni_log(NI_LOG_ERROR, "%s: maxFrameSize is not set in low delay mode. Set it to half of frame size %d\n", - __func__, p_cfg->ui16maxFrameSize*2000); + strncpy(p_param_err, "EnableRdoQuant is not supported on av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - - // minimum acceptable value of maxFrameSize is bitrate / framerate in byte - uint32_t min_maxFrameSize = ((p_cfg->i32bitRate / p_cfg->i32frameRateInfo * p_cfg->i32frameRateDenominator) / 8) / 2000; - - if (p_cfg->ui16maxFrameSize < min_maxFrameSize) + if (p_cfg->ui8fillerEnable) { - ni_log(NI_LOG_ERROR, "%s: maxFrameSize %d is too small. Changed to minimum value (bitrate/framerate in byte): %d\n", - __func__, p_cfg->ui16maxFrameSize*2000, min_maxFrameSize*2000); - p_cfg->ui16maxFrameSize = min_maxFrameSize; + strncpy(p_param_err, "fillerEnable is not supported on av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - else - { - if (p_cfg->ui16maxFrameSize != 0) + if (p_cfg->i8ppsInitQp) { - strncpy(p_param_err, "maxFrameSize can only be used when lowDelay is enabled", max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; + strncpy(p_param_err, "ppsInitQp is not supported for av1 encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; } - } - } - - if (QUADRA) + } else if (NI_CODEC_FORMAT_JPEG == p_ctx->codec_format) { - if (p_cfg->ui16gdrDuration) - { - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + if (p_cfg->ui8hdr10_enable) { - for (i = 0; i < p_cfg->niParamT408.custom_gop_params.custom_gop_size; i++) - { - if (2 == p_cfg->niParamT408.custom_gop_params.pic_param[i].pic_type) - { - strncpy(p_param_err, "Custom GOP can not have B frames for intra refresh", max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - } + strncpy(p_param_err, + "masterDisplay not supported for jpeg", + max_err_len); + warning = NI_RETCODE_PARAM_WARN; } - else if (p_cfg->ui8gopSize != 1 || p_cfg->ui8gopLowdelay) + if (p_cfg->niParamT408.conf_win_top != 0) { - if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_DEFAULT) - { - strncpy(p_param_err, - "GOP must not contain B frames for gdrDuration", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - strncpy(p_param_warn, "GOP size forced to 1 and low delay GOP force disabled (no B frames) for intra refresh", max_err_len); - warning = NI_RETCODE_PARAM_WARN; - p_cfg->ui8gopSize = 1; - p_cfg->ui8gopLowdelay = 0; + strncpy(p_param_err, "confWinTop is not supported in jpeg", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (p_cfg->ui16gdrDuration == 1) + if (p_cfg->niParamT408.conf_win_bottom != 0) { - strncpy(p_param_err, - "intra refresh cycle (height / intraRefreshArg MB or CTU) must > 1", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; + strncpy(p_param_err, "confWinBottom is not supported in jpeg", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (p_cfg->ui8LookAheadDepth != 0) + if (p_cfg->niParamT408.conf_win_left != 0) { - strncpy(p_param_warn, "lookaheadDepth forced to 0 (disable 2-pass) for intra refresh", max_err_len); - p_cfg->ui8LookAheadDepth = 0; + strncpy(p_param_err, "confWinLeft is not supported in jpeg", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (STD_HEVC == p_cfg->ui8bitstreamFormat || - STD_AV1 == p_cfg->ui8bitstreamFormat) + if (p_cfg->niParamT408.conf_win_right != 0) { - if (p_cfg->niParamT408.intra_period < p_cfg->ui16gdrDuration) - { - strncpy(p_param_warn, "intraPeriod forced to match intra refersh cycle (intraPeriod must >= intra refersh cycle)", max_err_len); - p_cfg->niParamT408.intra_period = p_cfg->ui16gdrDuration; - } + strncpy(p_param_err, "confWinRight is not supported in jpeg", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - else if (STD_AVC == p_cfg->ui8bitstreamFormat) + if (p_cfg->ui8hrdEnable) { - if (p_cfg->niParamT408.avcIdrPeriod < p_cfg->ui16gdrDuration) - { - strncpy(p_param_warn, "intraPeriod forced to match intra refersh cycle (intraPeriod must >= intra refersh cycle)", max_err_len); - p_cfg->niParamT408.avcIdrPeriod = p_cfg->ui16gdrDuration; - } + strncpy(p_param_err, "hrdEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - - if ((p_cfg->ui8hrdEnable) || (p_cfg->ui8fillerEnable)) - { - // enable rate control - if (p_cfg->ui8rcEnable == 0) - { - p_cfg->ui8rcEnable = p_src->cfg_enc_params.rc.enable_rate_control = 1; - } - - // enable hrd if it is off - if (p_cfg->i32vbvBufferSize == 0) - { - p_cfg->i32vbvBufferSize = 3000; - } - } - - if (p_cfg->ui32ltrRefInterval || p_cfg->niParamT408.useLongTerm) - { - if (p_cfg->ui32ltrRefInterval && p_cfg->niParamT408.useLongTerm) - { - strncpy(p_param_err, - "Can't enable ltrRefInterval and longTermReferenceEnable " - "at same time", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + if (p_cfg->ui8EnableAUD) { - if (p_cfg->niParamT408.custom_gop_params.custom_gop_size > 1) - { - strncpy(p_param_err, "Custom GOP size can not be > 1 for long term reference", max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; + strncpy(p_param_err, "enableAUD is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } - } else if ((p_cfg->ui8gopSize != 1) && (p_cfg->ui8gopLowdelay == 0) && - (p_cfg->niParamT408.intra_period != 1)) + } + if (p_cfg->ui8repeatHeaders) { - if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_DEFAULT) - { - strncpy(p_param_err, - "GOP size can not be > 1 for long term reference", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - strncpy(p_param_warn, "GOP size forced to 1 for long term reference", max_err_len); - warning = NI_RETCODE_PARAM_WARN; - p_cfg->ui8gopSize = 1; + strncpy(p_param_err, "repeatHeaders is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - - if (p_cfg->ui8LookAheadDepth != 0) + if (p_src->cfg_enc_params.preferred_transfer_characteristics != -1) { - strncpy(p_param_warn, "lookaheadDepth forced to 0 (disable 2-pass) for long term reference", max_err_len); - p_cfg->ui8LookAheadDepth = 0; + strncpy(p_param_err, "prefTRC is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - - if (p_cfg->ui32setLongTermInterval && (p_cfg->niParamT408.useLongTerm == 0)) - { - strncpy( - p_param_err, - "Must set longTermReferenceEnable for longTermReferenceInterval", - max_err_len); - param_ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - } - - if (p_cfg->niParamT408.cu_size_mode < 0 || - p_cfg->niParamT408.cu_size_mode > 7) - { - strncpy(p_param_err, "Invalid cu_size_mode: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE; - LRETURN; - } - - - - if (p_cfg->niParamT408.use_recommend_enc_params < 0 || - p_cfg->niParamT408.use_recommend_enc_params > 3) - { - strncpy(p_param_err, "Invalid use_recommend_enc_params: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM; - LRETURN; - } - - switch (p_cfg->niParamT408.use_recommend_enc_params) - { - case 0: - case 2: - case 3: - { - if (p_cfg->niParamT408.use_recommend_enc_params != 3) + if (p_cfg->ui8HDR10CLLEnable) { - // in FAST mode (recommendEncParam==3), max_num_merge value will be - // decided in FW - if (p_cfg->niParamT408.max_num_merge < 0 || - p_cfg->niParamT408.max_num_merge > 3) - { - strncpy(p_param_err, "Invalid max_num_merge: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_MAXNUMMERGE; + strncpy(p_param_err, "maxCLL is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } } - break; - } - - default: break; - } - - if ( p_cfg->niParamT408.intra_qp < -1 || - p_cfg->niParamT408.intra_qp > 51 ) - { - strncpy(p_param_err, "Invalid intra_qp: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_INTRA_QP; - LRETURN; - } - - if (QUADRA) - { - if (p_cfg->i8crf >= 0 && p_cfg->i8crf <= 51) - { - if (p_cfg->ui8LookAheadDepth < 4 || p_cfg->ui8LookAheadDepth > 40) + if (p_cfg->ui8colorPrimaries != 2) { - strncpy(p_param_err, "CRF requres LookAheadDepth <[4-40]>", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH; - LRETURN; + strncpy(p_param_err, "colorPri is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (p_cfg->ui8rcEnable == 1) + if (p_cfg->ui8colorTrc != 2) { - strncpy(p_param_err, "CRF requires RcEnable 0", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_RCENABLE; - LRETURN; + strncpy(p_param_err, "colorTrc is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (p_cfg->ui8ctbRcMode > 0) + if (p_cfg->ui8colorSpace != 2) { - strncpy(p_param_warn, "Lookahead with CtbRcMode > 0 may degrade quality", max_err_len); - warning = NI_RETCODE_PARAM_WARN; - //LRETURN; + strncpy(p_param_err, "colorSpc is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - } - - if ( p_cfg->niParamT408.enable_mb_level_rc != 1 && - p_cfg->niParamT408.enable_mb_level_rc != 0 ) - { - strncpy(p_param_err, "Invalid enable_mb_level_rc: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_RCENABLE; - LRETURN; - } - - { - if ( p_cfg->niParamT408.minQpI < 0 || - p_cfg->niParamT408.minQpI > 51 ) - { - strncpy(p_param_err, "Invalid min_qp: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_MN_QP; - LRETURN; - } - - if ( p_cfg->niParamT408.maxQpI < 0 || - p_cfg->niParamT408.maxQpI > 51 ) - { - strncpy(p_param_err, "Invalid max_qp: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_MX_QP; - LRETURN; - } - // TBD minQpP minQpB maxQpP maxQpB - - if ( p_cfg->niParamT408.enable_cu_level_rate_control != 1 && - p_cfg->niParamT408.enable_cu_level_rate_control != 0 ) - { - strncpy(p_param_err, "Invalid enable_cu_level_rate_control: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN; - LRETURN; - } - - //if (p_cfg->niParamT408.enable_cu_level_rate_control == 1) - { - if ( p_cfg->niParamT408.enable_hvs_qp != 1 && - p_cfg->niParamT408.enable_hvs_qp != 0 ) + if (p_src->sar_num) { - strncpy(p_param_err, "Invalid enable_hvs_qp: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_HVS_QP_EN; - LRETURN; + strncpy(p_param_err, "sarNum is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - - if (p_cfg->niParamT408.enable_hvs_qp) + if (p_src->sar_denom != 1) { - if ( p_cfg->niParamT408.max_delta_qp < 0 || - p_cfg->niParamT408.max_delta_qp > 51 ) - { - strncpy(p_param_err, "Invalid max_delta_qp: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_MX_DELTA_QP; - LRETURN; - } -#if 0 // TBD missing enable_hvs_qp_scale? - if ( p_cfg->niParamT408.enable_hvs_qp_scale != 1 && - p_cfg->niParamT408.enable_hvs_qp_scale != 0 ) - { - strcpy(p_param_err, "Invalid enable_hvs_qp_scale: out of range"); - param_ret = NI_RETCODE_PARAM_ERROR_HVS_QP_SCL; + strncpy(p_param_err, "sarDenom is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } - - if (p_cfg->niParamT408.enable_hvs_qp_scale == 1) { - if ( p_cfg->niParamT408.hvs_qp_scale < 0 || - p_cfg->niParamT408.hvs_qp_scale > 4 ) - { - strcpy(p_param_err, "Invalid hvs_qp_scale: out of range"); - param_ret = NI_RETCODE_PARAM_ERROR_HVS_QP_SCL; - LRETURN; - } - } -#endif } - } - // hrd is off when i32vbvBufferSize is 0 - if ((p_cfg->i32vbvBufferSize < 10 && p_cfg->i32vbvBufferSize != 0) || p_cfg->i32vbvBufferSize > 3000) - { - strncpy(p_param_err, "Invalid i32vbvBufferSize: out of range", max_err_len); - param_ret = NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE; - LRETURN; - } - } - - // check valid for common param - param_ret = ni_check_common_params(&p_cfg->niParamT408, p_src, p_param_err, max_err_len); - if (param_ret != NI_RETCODE_SUCCESS) - { - LRETURN; - } - - // check valid for RC param - param_ret = ni_check_ratecontrol_params(p_cfg, p_param_err, max_err_len); - if (param_ret != NI_RETCODE_SUCCESS) - { - LRETURN; - } - - if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_CUSTOM) - { - p_ctx->keyframe_factor = - presetGopKeyFrameFactor[p_cfg->niParamT408.gop_preset_index]; - } - if (warning == NI_RETCODE_PARAM_WARN && param_ret == NI_RETCODE_SUCCESS) - { - param_ret = NI_RETCODE_PARAM_WARN; - strncpy(p_param_err, p_param_warn, max_err_len); - } - -END: - ni_aligned_free(p_param_warn); - return param_ret; -} - -ni_retcode_t ni_check_common_params(ni_t408_config_t *p_param, - ni_xcoder_params_t *p_src, - char *p_param_err, uint32_t max_err_len) -{ - ni_retcode_t ret = NI_RETCODE_SUCCESS; - int32_t low_delay = 0; - int32_t intra_period_gop_step_size; - int32_t i, j; - - if (!p_param || !p_src || !p_param_err) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", - __func__); - ret = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - - //Zero out the error buffer - memset(p_param_err, 0, max_err_len); - - // check low-delay gop structure - if (!QUADRA) - { - if (0 == p_param->gop_preset_index) // common gop - { - if (p_param->custom_gop_params.custom_gop_size > 1) + if (p_src->video_full_range_flag != -1) { - int minVal = p_param->custom_gop_params.pic_param[0].poc_offset; - low_delay = 1; - for (i = 1; i < p_param->custom_gop_params.custom_gop_size; i++) - { - if (minVal > p_param->custom_gop_params.pic_param[i].poc_offset) - { - low_delay = 0; - break; - } else - { - minVal = p_param->custom_gop_params.pic_param[i].poc_offset; - } - } + strncpy(p_param_err, + "videoFullRangeFlag is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - else if (p_param->gop_preset_index == 2 || - p_param->gop_preset_index == 3 || - p_param->gop_preset_index == 6 || - p_param->gop_preset_index == 7) // low-delay case (IPPP, IBBB) - { - low_delay = 1; - } - - if (low_delay) - { - intra_period_gop_step_size = 1; - } - else - { - if (p_param->gop_preset_index == GOP_PRESET_IDX_CUSTOM) + if (p_cfg->ui8temporalLayersEnable) { - intra_period_gop_step_size = p_param->custom_gop_params.custom_gop_size; + strncpy(p_param_err, + "temporalLayersEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - else + if (p_cfg->ui8LowDelay) { - intra_period_gop_step_size = presetGopSize[p_param->gop_preset_index]; + strncpy(p_param_err, "LowDelay is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - - if (((p_param->intra_period != 0) && ((p_param->intra_period < intra_period_gop_step_size+1) == 1)) || - ((p_param->avcIdrPeriod != 0) && ((p_param->avcIdrPeriod < intra_period_gop_step_size+1) == 1))) - { - strncpy(p_param_err, "Invalid intra_period and gop_preset_index: gop structure is larger than intra period", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_INTRA_PERIOD; - LRETURN; - } - - if (((!low_delay) && (p_param->intra_period != 0) && ((p_param->intra_period % intra_period_gop_step_size) != 0)) || - ((!low_delay) && (p_param->avcIdrPeriod != 0) && ((p_param->avcIdrPeriod % intra_period_gop_step_size) != 0))) - { - strncpy(p_param_err, "Invalid intra_period and gop_preset_index: intra period is not a multiple of gop structure size", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_INTRA_PERIOD; - LRETURN; - } - - if (p_param->gop_preset_index == GOP_PRESET_IDX_CUSTOM) - { - int temp_poc[NI_MAX_GOP_NUM]; - int min_poc = p_param->custom_gop_params.pic_param[0].poc_offset; - for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + if (p_cfg->ui8rdoLevel) { - if (p_param->custom_gop_params.pic_param[i].temporal_id >= XCODER_MAX_NUM_TEMPORAL_LAYER) - { - strncpy(p_param_err, "Invalid custom gop parameters: temporal_id larger than 7", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + strncpy(p_param_err, "rdoLevel is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } - - if (p_param->custom_gop_params.pic_param[i].temporal_id < 0) - { - strncpy(p_param_err, "Invalid custom gop parameters: temporal_id is zero or negative", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + } + if (p_cfg->ui8EnableRdoQuant) + { + strncpy(p_param_err, "EnableRdoQuant is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } - temp_poc[i] = p_param->custom_gop_params.pic_param[i].poc_offset; - if (min_poc > temp_poc[i]) - { - min_poc = temp_poc[i]; - } } - int count_pos = 0; - for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + if (p_cfg->ui8enable2PassGopPatern) { - for (j = 0; j < p_param->custom_gop_params.custom_gop_size; j++) - { - if (temp_poc[j] == min_poc) - { - count_pos++; - min_poc++; - } - } + strncpy(p_param_err, + "enable2PassGop is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (count_pos != p_param->custom_gop_params.custom_gop_size) + if (p_cfg->ui8LookAheadDepth) { - strncpy(p_param_err, "Invalid custom gop parameters: poc_offset is invalid", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; - LRETURN; + strncpy(p_param_err, + "lookAheadDepth is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - } - else // QUADRA - { - if (p_param->custom_gop_params.custom_gop_size) - { - int temp_poc[NI_MAX_GOP_NUM]; - int min_poc = p_param->custom_gop_params.pic_param[0].poc_offset; - for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + if (GOP_PRESET_IDX_DEFAULT != p_cfg->niParamT408.gop_preset_index) { - if (p_param->custom_gop_params.pic_param[i].temporal_id >= XCODER_MAX_NUM_TEMPORAL_LAYER) - { - strncpy(p_param_err, "Invalid custom gop parameters: temporal_id larger than 7", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + strncpy(p_param_err, + "gopPresetIdx is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } - - if (p_param->custom_gop_params.pic_param[i].temporal_id < 0) - { - strncpy(p_param_err, "Invalid custom gop parameters: temporal_id is negative", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + } + if (p_cfg->niParamT408.roiEnable) + { + strncpy(p_param_err, "roiEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; LRETURN; - } - - for (j = 0; j < p_param->custom_gop_params.pic_param[i].num_ref_pics; j++) - { - if (p_param->custom_gop_params.pic_param[i].rps[j].ref_pic == 0) - { - strncpy(p_param_err, "Invalid custom gop parameters: ref pic delta cannot be 0", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; - LRETURN; - } - } - - temp_poc[i] = p_param->custom_gop_params.pic_param[i].poc_offset; - if (min_poc > temp_poc[i]) - { - min_poc = temp_poc[i]; - } } - int count_pos = 0; - for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + if(p_src->roi_demo_mode) { - for (j = 0; j < p_param->custom_gop_params.custom_gop_size; j++) - { - if (temp_poc[j] == min_poc) - { - count_pos++; - min_poc++; - } - } + strncpy(p_param_err, + "RoiDemoMode is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - if (count_pos != p_param->custom_gop_params.custom_gop_size) + if (p_src->cacheRoi) { - strncpy(p_param_err, "Invalid custom gop parameters: poc_offset is invalid", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; - LRETURN; + strncpy(p_param_err, "cacheRoi is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } - } - - if (0 == p_param->use_recommend_enc_params) - { - // RDO - { - int align_32_width_flag = p_src->source_width % 32; - int align_16_width_flag = p_src->source_width % 16; - int align_8_width_flag = p_src->source_width % 8; - int align_32_height_flag = p_src->source_height % 32; - int align_16_height_flag = p_src->source_height % 16; - int align_8_height_flag = p_src->source_height % 8; - - if (((p_param->cu_size_mode & 0x1) == 0) && ((align_8_width_flag != 0) || (align_8_height_flag != 0))) + if (p_src->reconf_demo_mode != XCODER_TEST_RECONF_OFF) { - strncpy(p_param_err, "Invalid use_recommend_enc_params and cu_size_mode: picture width and height must be aligned with 8 pixels when enable CU8x8 of cu_size_mode. Recommend to set cu_size_mode |= 0x1 (CU8x8)", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN; - LRETURN; + strncpy(p_param_err, + "ReconfDemoMode is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - else if (((p_param->cu_size_mode & 0x1) == 0) && ((p_param->cu_size_mode & 0x2) == 0) && ((align_16_width_flag != 0) || (align_16_height_flag != 0))) + if (p_cfg->niParamT408.intraRefreshMode) { - strncpy(p_param_err, "Invalid use_recommend_enc_params and cu_size_mode: picture width and height must be aligned with 16 pixels when enable CU16x16 of cu_size_mode. Recommend to set cu_size_mode |= 0x2 (CU16x16)", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN; - LRETURN; + strncpy(p_param_err, + "intraRefreshMode is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - else if (((p_param->cu_size_mode & 0x1) == 0) && ((p_param->cu_size_mode & 0x2) == 0) && ((p_param->cu_size_mode & 0x4) == 0) && ((align_32_width_flag != 0) || (align_32_height_flag != 0))) + if (p_cfg->niParamT408.intraRefreshArg) { - strncpy(p_param_err, "Invalid use_recommend_enc_params and cu_size_mode: picture width and height must be aligned with 32 pixels when enable CU32x32 of cu_size_mode. Recommend to set cu_size_mode |= 0x4 (CU32x32)", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN; - LRETURN; + strncpy(p_param_err, + "intraRefreshArg is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; } - } + if (p_cfg->niParamT408.intra_period != 120) + { + strncpy(p_param_err, + "intraPeriod is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8intraResetRefresh) + { + strncpy( + p_param_err, + "IntraRefreshResetOnForceIDR is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->niParamT408.useLongTerm) + { + strncpy(p_param_err, + "longTermReferenceEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui32setLongTermInterval) + { + strncpy(p_param_err, + "longTermReferenceInterval is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8setLongTermCount != 2) + { + strncpy(p_param_err, + "longTermReferenceCount is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8multicoreJointMode) + { + strncpy(p_param_err, + "multicoreJointMode is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8enableSSIM) + { + strncpy(p_param_err, "enableSSIM is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_enc->rc.vbv_buffer_size != -1) + { + strncpy(p_param_err, + "vbvBufferSize is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8fillerEnable) + { + strncpy(p_param_err, + "fillerEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8picSkipEnable) + { + strncpy(p_param_err, "picSkip is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui16maxFrameSize) + { + strncpy(p_param_err, "maxFrameSize is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->niParamT408.enable_cu_level_rate_control) + { + strncpy(p_param_err, + "cuLevelRCEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->niParamT408.enable_hvs_qp) + { + strncpy(p_param_err, "hvsQPEnable is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->niParamT408.profile) + { + strncpy(p_param_err, "profile is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->niParamT408.intra_mb_refresh_mode || p_cfg->niParamT408.intra_mb_refresh_arg) + { + strncpy(p_param_err, "intraRefreshMode or intraRefreshArg is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i8crf != -1) + { + strncpy(p_param_err, "crf is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i32tolCtbRcInter != (int32_t)(0.1 * 1000)) + { + strncpy(p_param_err, "tolCtbRcInter is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i32tolCtbRcIntra != (int32_t)(0.1 * 1000)) + { + strncpy(p_param_err, "tolCtbRcIntra is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8rcQpDeltaRange != 10) + { + strncpy(p_param_err, + "rcQpDeltaRange is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i16bitrateWindow != -255) + { + strncpy(p_param_err, "bitrateWindow is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i16ctbRowQpStep) + { + strncpy(p_param_err, "ctbRowQpStep is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->ui8AiEnhanceMode) + { + strncpy(p_param_err, + "enableAIEnhance is not supported on jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i8ppsInitQp) + { + strncpy(p_param_err, "ppsInitQp is not supported for jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_cfg->i8pass1Qp) + { + strncpy(p_param_err, "pass1Qp is not supported for jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } + if (p_enc->bitrateMode != -1) + { + strncpy(p_param_err, "bitrateMode is not supported for jpeg encoder", + max_err_len); + param_ret = NI_RETCODE_ERROR_UNSUPPORTED_FEATURE; + LRETURN; + } } - if ((p_param->conf_win_top < 0) || (p_param->conf_win_top > 8192)) - { - strncpy(p_param_err, "Invalid conf_win_top: out of range", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP; - LRETURN; - } - if (p_param->conf_win_top % 2) + if (p_src->force_frame_type != 0 && p_src->force_frame_type != 1) { - strncpy(p_param_err, "Invalid conf_win_top: not multiple of 2", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP; - LRETURN; + strncpy(p_param_err, "Invalid forceFrameType: out of range", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; } - if ((p_param->conf_win_bottom < 0) || (p_param->conf_win_bottom > 8192)) - { - strncpy(p_param_err, "Invalid conf_win_bottom: out of range", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT; - LRETURN; - } - if (p_param->conf_win_bottom % 2) - { - strncpy(p_param_err, "Invalid conf_win_bottom: not multiple of 2", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT; - LRETURN; - } - - if ((p_param->conf_win_left < 0) || (p_param->conf_win_left > 8192)) - { - strncpy(p_param_err, "Invalid conf_win_left: out of range", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_L; - LRETURN; - } - if (p_param->conf_win_left % 2) - { - strncpy(p_param_err, "Invalid conf_win_left: not multiple of 2", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_L; - LRETURN; - } - - if (p_param->conf_win_right < 0 || p_param->conf_win_right > 8192) - { - strncpy(p_param_err, "Invalid conf_win_right: out of range", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_R; - LRETURN; - } - if (p_param->conf_win_right % 2) - { - strncpy(p_param_err, "Invalid conf_win_right: not multiple of 2", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_R; - } - -END: - - return ret; -} - -ni_retcode_t ni_check_ratecontrol_params(ni_encoder_config_t* p_cfg, char* p_param_err, uint32_t max_err_len) -{ - ni_retcode_t ret = NI_RETCODE_SUCCESS; - ni_t408_config_t* p_param = &p_cfg->niParamT408; - - if( (!p_cfg) || (!p_param_err) ) + if (p_cfg->niParamT408.forcedHeaderEnable > 2) { - ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", - __func__); - ret = NI_RETCODE_INVALID_PARAM; + strncpy(p_param_err, "Invalid forcedHeaderEnable: out of range", + max_err_len); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; LRETURN; } - //Zero out the error buffer - memset(p_param_err, 0, max_err_len); - - if (p_param->roiEnable != 0 && p_param->roiEnable != 1) + if (p_cfg->niParamT408.decoding_refresh_type < 0 || + p_cfg->niParamT408.decoding_refresh_type > 2) { - strncpy(p_param_err, "Invalid roiEnable: out of range", max_err_len); - ret = NI_RETCODE_PARAM_INVALID_VALUE; + strncpy(p_param_err, "Invalid decoding_refresh_type: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE; LRETURN; } - if (p_param->roiEnable && p_param->enable_hvs_qp) + if (!QUADRA) { - strncpy(p_param_err, "hvsQPEnable and roiEnable: not mutually exclusive", max_err_len); - ret = NI_RETCODE_PARAM_INVALID_VALUE; - LRETURN; - } + if (p_cfg->niParamT408.gop_preset_index < 0 || + p_cfg->niParamT408.gop_preset_index > 8) + { + strcpy(p_param_err, "Invalid gop_preset_index: out of range"); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; + LRETURN; + } - // TBD RevB - if (p_cfg->ui8rcEnable == 1) - { - if (p_param->minQpP > p_param->maxQpP || p_param->minQpB > p_param->maxQpB) + if (p_src->low_delay_mode && 1 != p_cfg->niParamT408.gop_preset_index && + 2 != p_cfg->niParamT408.gop_preset_index && + 3 != p_cfg->niParamT408.gop_preset_index && + 6 != p_cfg->niParamT408.gop_preset_index && + 7 != p_cfg->niParamT408.gop_preset_index && + !(0 == p_cfg->niParamT408.gop_preset_index && + 1 == p_cfg->niParamT408.custom_gop_params.custom_gop_size)) { - strncpy(p_param_err, "Invalid min_qp(P/B) and max_qp(P/B): min_qp cannot be larger than max_qp", max_err_len); - ret = NI_RETCODE_PARAM_ERROR_MX_QP; + strcpy(p_param_err, "GOP size must be 1 when lowDelay is enabled"); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; LRETURN; } } - -END: - - return ret; -} - - -/*!****************************************************************************** - * \brief Print xcoder user configurations - * - * \param - * - * \return - *******************************************************************************/ -void ni_params_print(ni_xcoder_params_t *const p_encoder_params) -{ - if (!p_encoder_params) + else // QUADRA { - return; - } - - ni_encoder_cfg_params_t *p_enc = &p_encoder_params->cfg_enc_params; - - ni_log(NI_LOG_DEBUG, "XCoder Params:\n"); - - ni_log(NI_LOG_DEBUG, "preset=%d\n", p_encoder_params->preset); - ni_log(NI_LOG_DEBUG, "fps_number / fps_denominator=%u / %u\n", - p_encoder_params->fps_number, - p_encoder_params->fps_denominator); - - ni_log(NI_LOG_DEBUG, "source_width x source_height=%dx%d\n", p_encoder_params->source_width, p_encoder_params->source_height); - ni_log(NI_LOG_DEBUG, "bitrate=%d\n", p_encoder_params->bitrate); - - ni_log(NI_LOG_DEBUG, "profile=%d\n", p_enc->profile); - ni_log(NI_LOG_DEBUG, "level_idc=%d\n", p_enc->level_idc); - ni_log(NI_LOG_DEBUG, "high_tier=%d\n", p_enc->high_tier); - - ni_log(NI_LOG_DEBUG, "frame_rate=%d\n", p_enc->frame_rate); - - ni_log(NI_LOG_DEBUG, "use_recommend_enc_params=%d\n", p_enc->use_recommend_enc_params); - ni_log(NI_LOG_DEBUG, "cu_size_mode=%d\n", p_enc->cu_size_mode); - ni_log(NI_LOG_DEBUG, "max_num_merge=%d\n", p_enc->max_num_merge); - ni_log(NI_LOG_DEBUG, "enable_dynamic_8x8_merge=%d\n", p_enc->enable_dynamic_8x8_merge); - ni_log(NI_LOG_DEBUG, "enable_dynamic_16x16_merge=%d\n", p_enc->enable_dynamic_16x16_merge); - ni_log(NI_LOG_DEBUG, "enable_dynamic_32x32_merge=%d\n", p_enc->enable_dynamic_32x32_merge); - // trans_rate not available in Rev B - ni_log(NI_LOG_DEBUG, "enable_rate_control=%d\n", p_enc->rc.enable_rate_control); - ni_log(NI_LOG_DEBUG, "enable_cu_level_rate_control=%d\n", p_enc->rc.enable_cu_level_rate_control); - ni_log(NI_LOG_DEBUG, "enable_hvs_qp=%d\n", p_enc->rc.enable_hvs_qp); - ni_log(NI_LOG_DEBUG, "enable_hvs_qp_scale=%d\n", p_enc->rc.enable_hvs_qp_scale); - ni_log(NI_LOG_DEBUG, "hvs_qp_scale=%d\n", p_enc->rc.hvs_qp_scale); - ni_log(NI_LOG_DEBUG, "min_qp=%d\n", p_enc->rc.min_qp); - ni_log(NI_LOG_DEBUG, "max_qp=%d\n", p_enc->rc.max_qp); - ni_log(NI_LOG_DEBUG, "max_delta_qp=%d\n", p_enc->rc.max_delta_qp); - ni_log(NI_LOG_DEBUG, "vbv_buffer_size=%d\n", p_enc->rc.vbv_buffer_size); - ni_log(NI_LOG_DEBUG, "enable_filler=%d\n", p_enc->rc.enable_filler); - ni_log(NI_LOG_DEBUG, "enable_pic_skip=%d\n", p_enc->rc.enable_pic_skip); - - ni_log(NI_LOG_DEBUG, "forcedHeaderEnable=%d\n", p_enc->forced_header_enable); - ni_log(NI_LOG_DEBUG, "roi_enable=%d\n", p_enc->roi_enable); - ni_log(NI_LOG_DEBUG, "long_term_ref_enable=%d\n", p_enc->long_term_ref_enable); - ni_log(NI_LOG_DEBUG, "long_term_ref_interval=%d\n", p_enc->long_term_ref_interval); - ni_log(NI_LOG_DEBUG, "long_term_ref_count=%d\n", p_enc->long_term_ref_count); - ni_log(NI_LOG_DEBUG, "conf_win_top=%d\n", p_enc->conf_win_top); - ni_log(NI_LOG_DEBUG, "conf_win_bottom=%d\n", p_enc->conf_win_bottom); - ni_log(NI_LOG_DEBUG, "conf_win_left=%d\n", p_enc->conf_win_left); - ni_log(NI_LOG_DEBUG, "conf_win_right=%d\n", p_enc->conf_win_right); - - ni_log(NI_LOG_DEBUG, "intra_qp=%d\n", p_enc->rc.intra_qp); - ni_log(NI_LOG_DEBUG, "enable_mb_level_rc=%d\n", p_enc->rc.enable_mb_level_rc); - - ni_log(NI_LOG_DEBUG, "intra_period=%d\n", p_enc->intra_period); - ni_log(NI_LOG_DEBUG, "decoding_refresh_type=%d\n", p_enc->decoding_refresh_type); + if (p_cfg->ui8gopSize > 8) + { + strncpy(p_param_err, "Invalid gopSize out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; + LRETURN; + } - // Rev. B: H.264 only or HEVC-shared parameters, in ni_t408_config_t - ni_log(NI_LOG_DEBUG, "enable_transform_8x8=%d\n", p_enc->enable_transform_8x8); - ni_log(NI_LOG_DEBUG, "avc_slice_mode=%d\n", p_enc->avc_slice_mode); - ni_log(NI_LOG_DEBUG, "avc_slice_arg=%d\n", p_enc->avc_slice_arg); - ni_log(NI_LOG_DEBUG, "entropy_coding_mode=%d\n", p_enc->entropy_coding_mode); - ni_log(NI_LOG_DEBUG, "intra_mb_refresh_mode=%d\n", p_enc->intra_mb_refresh_mode); - ni_log(NI_LOG_DEBUG, "intra_mb_refresh_arg=%d\n", p_enc->intra_mb_refresh_arg); + if (p_cfg->ui8gopLowdelay && + p_cfg->ui8gopSize > 4) + { + strncpy(p_param_err, "GOP size must be <= 4 for low delay GOP", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; + LRETURN; + } - ni_log(NI_LOG_DEBUG, "gop_preset_index=%d\n", p_enc->gop_preset_index); -#ifndef QUADRA - if (!QUADRA) - { - if (p_enc->gop_preset_index == GOP_PRESET_IDX_CUSTOM) + if (p_cfg->ui8LookAheadDepth) { - int i; - ni_log(NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_enc->custom_gop_params.custom_gop_size); - for (i = 0; i < p_enc->custom_gop_params.custom_gop_size; i++) + if (p_cfg->ui8LookAheadDepth < 4 || p_cfg->ui8LookAheadDepth > 40) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_enc->custom_gop_params.pic_param[i].pic_type); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_enc->custom_gop_params.pic_param[i].poc_offset); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_qp=%d\n", i, p_enc->custom_gop_params.pic_param[i].pic_qp); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pic_L0=%d\n", i, p_enc->custom_gop_params.pic_param[i].num_ref_pic_L0); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L0=%d\n", i, p_enc->custom_gop_params.pic_param[i].ref_poc_L0); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L1=%d\n", i, p_enc->custom_gop_params.pic_param[i].ref_poc_L1); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_enc->custom_gop_params.pic_param[i].temporal_id); + strncpy(p_param_err, "Invalid LookAheadDepth: out of range. <[4-40]>", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH; + LRETURN; + } + if (p_cfg->ui8gopLowdelay) + { + strncpy(p_param_err, "2-pass encode does not support low delay GOP", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; + LRETURN; } + if (p_cfg->ui8planarFormat == NI_PIXEL_PLANAR_FORMAT_TILED4X4) + { + strncpy(p_param_err, "2-pass encode does not support tile4x4 format", + max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH; + LRETURN; + } + } - } - else // QUADRA -#endif - { - if (p_enc->custom_gop_params.custom_gop_size) + + if (p_src->low_delay_mode || p_cfg->ui8picSkipEnable) { - int i, j; - ni_log(NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_enc->custom_gop_params.custom_gop_size); - for (i = 0; i < NI_MAX_GOP_NUM; i++) + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_enc->custom_gop_params.pic_param[i].poc_offset); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_offset=%d\n", i, p_enc->custom_gop_params.pic_param[i].qp_offset); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_factor=%lf\n", i, p_enc->custom_gop_params.pic_param[i].qp_factor); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_enc->custom_gop_params.pic_param[i].temporal_id); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_enc->custom_gop_params.pic_param[i].pic_type); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pics=%d\n", i, p_enc->custom_gop_params.pic_param[i].num_ref_pics); - for (j = 0; j < NI_MAX_REF_PIC; j++) + for (i = 0; i < p_cfg->niParamT408.custom_gop_params.custom_gop_size; i++) { - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic=%d\n", i, j, p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic); - ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic_used=%d\n", i, j, p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic_used); + if (p_cfg->niParamT408.custom_gop_params.pic_param[i].poc_offset != (i+1)) + { + if (p_src->low_delay_mode) + strncpy(p_param_err, "Custom GOP must not include backward prediction when lowDelay is enabled", max_err_len); + else + strncpy(p_param_err, "Custom GOP must not include backward prediction when picSkip is enabled", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } } + } else if (1 != p_cfg->ui8gopSize && !p_cfg->ui8gopLowdelay && + p_cfg->niParamT408.intra_period != 1 && + p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_HIERARCHICAL_IPPPP) + { + if (p_src->low_delay_mode) + strncpy(p_param_err, "Must use low delay GOP (gopPresetIdx 1,3,7,9,10) when lowDelay is enabled", max_err_len); + else + strncpy(p_param_err, "Must use low delay GOP (gopPresetIdx 1,3,7,9,10) when picSkip is enabled", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; + LRETURN; + } else if ((p_cfg->ui8LookAheadDepth != 0) && (!p_cfg->ui8useLowDelayPocType)) + { + if (p_src->low_delay_mode) + strncpy(p_param_err, "lookAheadDepth must be 0 when lowDelay is enabled", max_err_len); + else + strncpy(p_param_err, "lookAheadDepth must be 0 when picSkip is enabled", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; } - } - } - return; -} + if (p_cfg->ui8multicoreJointMode) + { + if (p_src->low_delay_mode) + strncpy(p_param_err, + "Cannot use multicoreJointMode when lowDelay is enabled", + max_err_len); + else + strncpy(p_param_err, + "Cannot use multicoreJointMode when picSkip is enabled", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } -/*!****************************************************************************** - * \brief decoder keep alive thread function triggers every 1 second - * - * \param void thread args - * - * \return void - *******************************************************************************/ -void *ni_session_keep_alive_thread(void *arguments) -{ - ni_retcode_t retval = NI_RETCODE_SUCCESS; - ni_thread_arg_struct_t *args = (ni_thread_arg_struct_t *)arguments; - ni_session_stats_t inst_info = {0}; - ni_session_context_t ctx = {0}; - uint32_t loop = 0; - uint64_t endtime = ni_gettime_ns(); - //interval(nanoseconds) is equals to ctx.keep_alive_timeout/3(330,000,000ns approximately equal to 1/3 second). - uint64_t interval = args->keep_alive_timeout * 330000000LL; -#ifndef _ANDROID -#ifdef __linux__ - struct sched_param sched_param; + if (p_src->minFramesDelay) + { + if (p_src->low_delay_mode) + strncpy(p_param_err, + "Cannot enable minFramesDelay when lowDelay is enabled", + max_err_len); + else + strncpy(p_param_err, + "Cannot enable minFramesDelay when picSkip is enabled", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + } - // Linux has a wide variety of signals, Windows has a few. - // A large number of signals will interrupt the thread, which will cause heartbeat command interval more than 1 second. - // So just mask the unuseful signals in Linux - sigset_t signal; - sigfillset(&signal); - ni_pthread_sigmask(SIG_BLOCK, &signal, NULL); + if (p_cfg->ui8useLowDelayPocType) + { + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size > 1) + { + strncpy(p_param_err, "Custom GOP size must be 1 when useLowDelayPocType is enabled", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } else if (1 != p_cfg->ui8gopSize && !p_cfg->ui8gopLowdelay && + p_cfg->niParamT408.intra_period != 1) + { + strncpy(p_param_err, "Must use GOP with all frames as reference frames (gopPresetIdx 1,3,7,9) when useLowDelayPocType is enabled", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_GOP_PRESET; + LRETURN; + } + } - /* set up schedule priority - * first try to run with RR mode. - * if fails, try to set nice value. - * if fails either, ignore it and run with default priority. - * Note: Scheduling requires root permission. App is probably exectued - * without root so the priority for this thread might just end up - * being default. - */ - if (((sched_param.sched_priority = sched_get_priority_max(SCHED_RR)) == - -1) || - sched_setscheduler(syscall(SYS_gettid), SCHED_RR, &sched_param) < 0) + if (p_src->low_delay_mode) { - ni_log(NI_LOG_DEBUG, "%s cannot set scheduler: %s\n", __func__, - strerror(NI_ERRNO)); - if (setpriority(PRIO_PROCESS, 0, -20) != 0) + // minimum acceptable value of maxFrameSize is bitrate / framerate in bytes + uint32_t min_maxFrameSize = p_cfg->i32bitRate / p_cfg->i32frameRateInfo * p_cfg->i32frameRateDenominator / 8; + + if (p_cfg->ui16maxFrameSize == 0) + { + if (p_enc->maxFrameSizeRatio > 0) + { + if (min_maxFrameSize * p_enc->maxFrameSizeRatio > NI_MAX_FRAME_SIZE) + { + p_cfg->ui16maxFrameSize = NI_MAX_FRAME_SIZE / 2000; + } else + { + p_cfg->ui16maxFrameSize = min_maxFrameSize * p_enc->maxFrameSizeRatio / 2000; + } + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: Set maxFrameSize to %d times the " + "minimum frame size %d bytes in low delay mode\n", __func__, + p_enc->maxFrameSizeRatio, p_cfg->ui16maxFrameSize * 2000); + } else + { + p_cfg->ui16maxFrameSize = ((p_src->source_width * p_src->source_height * 3 / 4) * p_ctx->bit_depth_factor) / 2000; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: maxFrameSize is not set in low delay " + "mode. Set it to half of the maximum frame size %d bytes\n", + __func__, p_cfg->ui16maxFrameSize*2000); + } + } + + if (p_cfg->ui16maxFrameSize < min_maxFrameSize / 2000) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: maxFrameSize %u is too small. Changed to minimum value (bitrate/framerate in byte): %u\n", + __func__, p_cfg->ui16maxFrameSize*2000, min_maxFrameSize); + p_cfg->ui16maxFrameSize = min_maxFrameSize / 2000; + } + } + else + { + if (p_cfg->ui16maxFrameSize != 0 || p_enc->maxFrameSizeRatio > 0) + { + strncpy(p_param_err, "maxFrameSize can only be used when lowDelay is enabled", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + } + } + + if (QUADRA) + { + if (p_cfg->ui16gdrDuration) + { + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + { + for (i = 0; i < p_cfg->niParamT408.custom_gop_params.custom_gop_size; i++) { - ni_log(NI_LOG_DEBUG, "%s cannot set nice value: %s\n", __func__, - strerror(NI_ERRNO)); + if (2 == p_cfg->niParamT408.custom_gop_params.pic_param[i].pic_type) + { + strncpy(p_param_err, "Custom GOP can not have B frames for intra refresh", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + } + } + else if (p_cfg->ui8gopSize != 1 || p_cfg->ui8gopLowdelay) + { + if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_DEFAULT) + { + strncpy(p_param_err, + "Must use gopPresetIdx 9 (consecutive P frame) for intra refresh", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + strncpy(p_param_warn, "GOP size forced to 1 and low delay GOP force disabled (no B frames) for intra refresh", max_err_len); + warning = NI_RETCODE_PARAM_WARN; + p_cfg->ui8gopSize = 1; + p_cfg->ui8gopLowdelay = 0; + } + if (p_cfg->ui16gdrDuration == 1) + { + strncpy(p_param_err, + "intra refresh cycle (height / intraRefreshArg MB or CTU) must > 1", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + if (p_cfg->ui8LookAheadDepth != 0) + { + strncpy(p_param_err, "lookaheadDepth must be 0 for intra refresh", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + if (STD_HEVC == p_cfg->ui8bitstreamFormat || + STD_AV1 == p_cfg->ui8bitstreamFormat) + { + if (p_cfg->niParamT408.intra_period < p_cfg->ui16gdrDuration) + { + strncpy(p_param_warn, "intraPeriod forced to match intra refersh cycle (intraPeriod must >= intra refersh cycle)", max_err_len); + p_cfg->niParamT408.intra_period = p_cfg->ui16gdrDuration; + } + } + else if (STD_AVC == p_cfg->ui8bitstreamFormat) + { + if (p_cfg->niParamT408.avcIdrPeriod < p_cfg->ui16gdrDuration) + { + strncpy(p_param_warn, "intraPeriod forced to match intra refersh cycle (intraPeriod must >= intra refersh cycle)", max_err_len); + p_cfg->niParamT408.avcIdrPeriod = p_cfg->ui16gdrDuration; } + } } -#elif defined(_WIN32) - /* set up schedule priority. - * try to set the current thread to time critical level which is the highest prioriy - * level. - */ - if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == - 0) + if ((p_cfg->ui8hrdEnable) || (p_cfg->ui8fillerEnable)) { - ni_log(NI_LOG_DEBUG, "%s cannot set priority: %d.\n", __func__, - GetLastError()); + // enable rate control + if (p_cfg->ui8rcEnable == 0) + { + p_cfg->ui8rcEnable = p_src->cfg_enc_params.rc.enable_rate_control = 1; + } + + // enable hrd if it is off + if (p_cfg->i32vbvBufferSize == 0) + { + p_cfg->i32vbvBufferSize = 3000; + } } -#endif -#endif - // Initializes the session context variables that keep alive command and query status command need. - ctx.hw_id = args->hw_id; - ctx.session_id = args->session_id; - ctx.session_timestamp = args->session_timestamp; - ctx.device_type = args->device_type; - ctx.blk_io_handle = args->device_handle; - ctx.event_handle = args->thread_event_handle; - ctx.p_all_zero_buf = args->p_buffer; - ctx.keep_alive_timeout = args->keep_alive_timeout; - ni_log(NI_LOG_DEBUG, "%s ctx.keep_alive_timeout: %us.\n", __func__, - ctx.keep_alive_timeout); + // maxrate must >= bitrate + if (p_cfg->ui32vbvMaxRate != 0) + { + if (p_cfg->ui32vbvMaxRate < p_cfg->i32bitRate) + { + snprintf(p_param_err, max_err_len, "vbvMaxRate %u cannot be smaller than bitrate %d", + p_cfg->ui32vbvMaxRate, p_cfg->i32bitRate); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } - for (;;) // condition TBD + // minrate must <= bitrate + if (p_cfg->ui32vbvMinRate != 0) { - retval = - ni_send_session_keep_alive(ctx.session_id, ctx.blk_io_handle, - ctx.event_handle, ctx.p_all_zero_buf); - retval = ni_query_session_stats(&ctx, ctx.device_type, &inst_info, - retval, nvme_admin_cmd_xcoder_config); - (void)retval; - CHECK_ERR_RC2((&ctx), retval, inst_info, nvme_admin_cmd_xcoder_config, - ctx.device_type, ctx.hw_id, &(ctx.session_id)); + if (p_cfg->ui32vbvMinRate > p_cfg->i32bitRate) + { + snprintf(p_param_err, max_err_len, "vbvMinRate %u cannot be larger than bitrate %d", + p_cfg->ui32vbvMinRate, p_cfg->i32bitRate); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } - // 1. If received failure, set the close_thread flag to TRUE, and exit, - // then main thread will check this flag and return failure directly; - // 2. skip checking VPU recovery. - // If keep_alive thread detect the VPU RECOVERY before main thread, - // the close_thread flag may damage the vpu recovery handling process. - if ((NI_RETCODE_SUCCESS != retval) && - (NI_RETCODE_NVME_SC_VPU_RECOVERY != retval)) + // The supported range of vbvBufferSize are 0, or 1/framerate to 3000. If the vbvBufferSize is not 0. + // The minimum vbvBufferSize in msec is 1/framerate. The actual minimum in bits is bitrate/framerate. + if (p_cfg->i32vbvBufferSize != 0) + { + // check buffer size compatible to bitrate + uint32_t minVbvBufferSize = p_cfg->i32frameRateDenominator * 1000 / p_cfg->i32frameRateInfo; + if (p_cfg->i32vbvBufferSize < minVbvBufferSize) { + snprintf(p_param_err, max_err_len, "vbvBufferSize must be greater than the average frame size. Minimum is %u msec for framerate %d fps", + minVbvBufferSize, (p_cfg->i32frameRateInfo / p_cfg->i32frameRateDenominator)); + param_ret = NI_RETCODE_PARAM_INVALID_VALUE; LRETURN; } - endtime += interval; - while (ni_gettime_ns() < endtime) + // check buffer size compatible to maxrate + if (p_cfg->ui32vbvMaxRate != 0) { - if (args->close_thread) + uint32_t maxRateMinVbvBufferSize = ((int64_t)p_cfg->i32frameRateDenominator * 1000 / p_cfg->i32frameRateInfo) * p_cfg->ui32vbvMaxRate / p_cfg->i32bitRate; + if (p_cfg->i32vbvBufferSize < maxRateMinVbvBufferSize) { - LRETURN; + snprintf(p_param_warn, max_err_len, "vbvBufferSize cannot be smaller than one frame size based on vbvMaxRate, force vbvBufferSize to %u msec for bitrate %d vbvMaxRate %u and framerate %d fps", + maxRateMinVbvBufferSize, p_cfg->i32bitRate, p_cfg->ui32vbvMaxRate, (p_cfg->i32frameRateInfo / p_cfg->i32frameRateDenominator)); + warning = NI_RETCODE_PARAM_WARN; + p_cfg->i32vbvBufferSize = maxRateMinVbvBufferSize; } - ni_usleep(10000); // 10ms per loop } + // check buffer size compatible to minrate (capped CRF may set minrate without maxrate) + else if (p_cfg->ui32vbvMinRate != 0) + { + uint32_t minRateMinVbvBufferSize = ((int64_t)p_cfg->i32frameRateDenominator * 1000 / p_cfg->i32frameRateInfo) * p_cfg->ui32vbvMinRate / p_cfg->i32bitRate; + if (p_cfg->i32vbvBufferSize < minRateMinVbvBufferSize) + { + snprintf(p_param_warn, max_err_len, "vbvBufferSize cannot be smaller than one frame size based on vbvMinRate, force vbvBufferSize to %u msec for bitrate %d vbvMinRate %u and framerate %d fps", + minRateMinVbvBufferSize, p_cfg->i32bitRate, p_cfg->ui32vbvMinRate, (p_cfg->i32frameRateInfo / p_cfg->i32frameRateDenominator)); + warning = NI_RETCODE_PARAM_WARN; + p_cfg->i32vbvBufferSize = minRateMinVbvBufferSize; + } + } } - -END: - - if (NI_RETCODE_SUCCESS != retval) + else { - ni_log(NI_LOG_ERROR, "%s abormal closed:%d\n", __func__, retval); - // changing the value to be True here means the thread has been closed. - args->close_thread = true; + // check buffer size compatible to maxrate and/or minrate + if ( p_cfg->ui32vbvMaxRate != 0 || p_cfg->ui32vbvMinRate != 0 ) + { + snprintf(p_param_warn, max_err_len, "vbvMaxRate %u vbvMinRate %u does not take effect when vbvBufferSize is 0, force vbvMaxRate vbvMinRate to 0", + p_cfg->ui32vbvMaxRate, p_cfg->ui32vbvMinRate); + warning = NI_RETCODE_PARAM_WARN; + p_cfg->ui32vbvMaxRate = 0; + p_cfg->ui32vbvMinRate = 0; + } } - ni_log(NI_LOG_DEBUG, "%s(): exit\n", __func__); - - return NULL; -} + if (p_cfg->ui32ltrRefInterval || p_cfg->niParamT408.useLongTerm) + { + if (p_cfg->ui32ltrRefInterval && p_cfg->niParamT408.useLongTerm) + { + strncpy(p_param_err, + "Can't enable ltrRefInterval and longTermReferenceEnable " + "at same time", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } -/*!****************************************************************************** -* \brief Open a xcoder upload instance -* -* \param p_ctx - pointer to caller allocated uploader session context -* -* \return -* On success -* NI_RETCODE_SUCCESS -* -* On failure -* NI_RETCODE_INVALID_PARAM -* NI_RETCODE_ERROR_MEM_ALOC -* NI_RETCODE_ERROR_INVALID_SESSION -* NI_RETCODE_FAILURE -*******************************************************************************/ -ni_retcode_t ni_uploader_session_open(ni_session_context_t* p_ctx) -{ - ni_retcode_t retval = NI_RETCODE_SUCCESS; - void * p_buffer = NULL; - uint32_t ui32LBA = 0; - - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); - - if (!p_ctx) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): passed parameters are null!, return\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - - //Create the session if the create session flag is set - if (NI_INVALID_SESSION_ID == p_ctx->session_id) - { - p_ctx->device_type = NI_DEVICE_TYPE_UPLOAD; - p_ctx->pts_table = NULL; - p_ctx->dts_queue = NULL; - p_ctx->p_leftover = NULL; - p_ctx->buffer_pool = NULL; - p_ctx->prev_size = 0; - p_ctx->sent_size = 0; - p_ctx->status = 0; - p_ctx->key_frame_type = 0; - p_ctx->ready_to_close = 0; - p_ctx->rc_error_count = 0; - p_ctx->frame_num = 0; - p_ctx->pkt_num = 0; - p_ctx->pkt_index = 0; - - //malloc zero data buffer - if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), - NI_DATA_BUFFER_LEN)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; - } - memset(p_ctx->p_all_zero_buf, 0, NI_DATA_BUFFER_LEN); + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size) + { + if (p_cfg->niParamT408.custom_gop_params.custom_gop_size > 1) + { + strncpy(p_param_err, "Custom GOP size can not be > 1 for long term reference", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + } else if ((p_cfg->ui8gopSize != 1) && (p_cfg->ui8gopLowdelay == 0) && + (p_cfg->niParamT408.intra_period != 1)) + { + if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_DEFAULT) + { + strncpy(p_param_err, + "Must use low delay GOP (gopPresetIdx 1,3,7,9) for long term reference", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + strncpy(p_param_warn, "GOP size forced to 1 for long term reference", max_err_len); + warning = NI_RETCODE_PARAM_WARN; + p_cfg->ui8gopSize = 1; + } - //malloc data buffer - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; + if (p_cfg->ui8LookAheadDepth != 0) + { + strncpy(p_param_err, "lookaheadDepth must be 0 for long term reference", max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; LRETURN; + } } - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - - //Set session ID to be invalid. In case we cannot open session, the session id wold remain invalid. - //In case we can open sesison, the session id would become valid. - ((ni_session_stats_t *)p_buffer)->ui16SessionId = - (uint16_t)NI_INVALID_SESSION_ID; - // First uint32_t is either an invaild session ID or a valid session ID, depending on if session could be opened - ui32LBA = OPEN_SESSION_CODEC(NI_DEVICE_TYPE_ENCODER, ni_htonl(p_ctx->codec_format), 1/*1 for uploadMode*/); - retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - if (retval != NI_RETCODE_SUCCESS) - { - ni_log(NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); - LRETURN; - } - //Open will return a session status structure with a valid session id if it worked. - //Otherwise the invalid session id set before the open command will stay - p_ctx->session_id = ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); - p_ctx->session_timestamp = - ni_htonll(((ni_session_stats_t *)p_buffer)->ui64Session_timestamp); - if (NI_INVALID_SESSION_ID == p_ctx->session_id) + if (p_cfg->ui32setLongTermInterval && (p_cfg->niParamT408.useLongTerm == 0)) { - ni_log(NI_LOG_ERROR, - "ERROR %s(): p_ctx->device_handle=%" PRIx64 - ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); - ni_encoder_session_close(p_ctx, 0); - retval = NI_RETCODE_ERROR_INVALID_SESSION; + strncpy( + p_param_err, + "Must set longTermReferenceEnable for longTermReferenceInterval", + max_err_len); + param_ret = NI_RETCODE_INVALID_PARAM; LRETURN; } - ni_log(NI_LOG_DEBUG, - "Uploader open session ID:0x%x,timestamp:%" PRIu64 "\n", - p_ctx->session_id, p_ctx->session_timestamp); - - //Send keep alive timeout Info - uint64_t keep_alive_timeout = - p_ctx->keep_alive_timeout * 1000000; //send us to FW - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); - ni_log(NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, - keep_alive_timeout); - ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - - if (NI_RETCODE_SUCCESS != retval) + + if (p_cfg->ui8av1ErrResilientMode) { - ni_log(NI_LOG_ERROR, - "ERROR %s(): nvme write keep_alive_timeout command " - "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", - __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + if (STD_AV1 != p_cfg->ui8bitstreamFormat) + { + strncpy(p_param_warn, "AV1 err resilient mode forced to 0 when using other codecs", max_err_len); + warning = NI_RETCODE_PARAM_WARN; + p_cfg->ui8av1ErrResilientMode = 0; + } } - - ni_log(NI_LOG_DEBUG, "Open session completed\n"); } - // init for frame pts calculation - p_ctx->is_first_frame = 1; - p_ctx->last_pts = 0; - p_ctx->last_dts = 0; - - ni_timestamp_init(p_ctx, &p_ctx->pts_table, "dec_pts"); - ni_timestamp_init(p_ctx, &p_ctx->dts_queue, "dec_dts"); - - //p_ctx->active_video_width = 0; - //p_ctx->active_video_height = 0; - - ni_log(NI_LOG_DEBUG, - "%s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, " - "p_ctx->session_id=%d\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); - - p_ctx->hw_action = NI_CODEC_HW_NONE; - -#ifndef _WIN32 - // If this is a P2P upload session, open the Netint kernel driver - if (p_ctx->isP2P) + if (p_cfg->niParamT408.cu_size_mode < 0 || + p_cfg->niParamT408.cu_size_mode > 7) { - int ret; - char line[256]; - char syspath[256]; - struct stat bstat; - char *block_dev; - char *dom, *bus, *dev, *fnc; - FILE *fp; - - p_ctx->netint_fd = open("/dev/netint", O_RDWR); - if (p_ctx->netint_fd < 0) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() Can't open device: %s\n", __func__, - strerror(NI_ERRNO)); - retval = NI_RETCODE_FAILURE; - LRETURN; - } - - // find the PCI domain:bus:device:function - block_dev = &p_ctx->blk_xcoder_name[0]; - if (stat(block_dev, &bstat) < 0) - { - ni_log(NI_LOG_ERROR, "failed to get stat of file %s\n", block_dev); - retval = NI_RETCODE_FAILURE; - LRETURN; - } - - if ((bstat.st_mode & S_IFMT) != S_IFBLK) - { - ni_log(NI_LOG_ERROR, "%s is not a block device\n", block_dev); - retval = NI_RETCODE_FAILURE; - LRETURN; - } + strncpy(p_param_err, "Invalid cu_size_mode: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE; + LRETURN; + } - ret = snprintf(syspath, sizeof(syspath) - 1, - "/sys/block/%s/device/address", block_dev + 5); - syspath[ret] = '\0'; - fp = fopen(syspath, "r"); - if (fp == NULL) - { - ni_log(NI_LOG_ERROR, "Failed to read address\n"); - retval = NI_RETCODE_FAILURE; - LRETURN; - } + if (p_cfg->niParamT408.use_recommend_enc_params < 0 || + p_cfg->niParamT408.use_recommend_enc_params > 3) + { + strncpy(p_param_err, "Invalid use_recommend_enc_params: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM; + LRETURN; + } - if (fgets(line, 256, fp) == NULL) + switch (p_cfg->niParamT408.use_recommend_enc_params) + { + case 0: + case 2: + case 3: + { + if (p_cfg->niParamT408.use_recommend_enc_params != 3) { - ni_log(NI_LOG_ERROR, "Failed to read line from address\n"); - fclose(fp); - retval = NI_RETCODE_FAILURE; + // in FAST mode (recommendEncParam==3), max_num_merge value will be + // decided in FW + if (p_cfg->niParamT408.max_num_merge < 0 || + p_cfg->niParamT408.max_num_merge > 3) + { + strncpy(p_param_err, "Invalid max_num_merge: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_MAXNUMMERGE; LRETURN; + } } + break; + } - fclose(fp); - - errno = 0; - p_ctx->domain = strtoul(line, &dom, 16); - - if (errno < 0) - { - ni_log(NI_LOG_ERROR, "Failed to read PCI domain\n"); - retval = NI_RETCODE_FAILURE; - LRETURN; - } + default: break; + } - errno = 0; - p_ctx->bus = strtoul(dom + 1, &bus, 16); + if ( p_cfg->niParamT408.intra_qp < -1 || + p_cfg->niParamT408.intra_qp > 51 ) + { + strncpy(p_param_err, "Invalid intra_qp: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_INTRA_QP; + LRETURN; + } - if (errno < 0) + if (QUADRA) + { + if (p_cfg->i8crf >= 0 && p_cfg->i8crf <= 51) + { + if (p_cfg->ui8LookAheadDepth < 4 || p_cfg->ui8LookAheadDepth > 40) { - ni_log(NI_LOG_ERROR, "Failed to read PCI bus\n"); - retval = NI_RETCODE_FAILURE; + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6X") < 0) + { + strncpy(p_param_err, "CRF requres LookAheadDepth <[4-40]>", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH; LRETURN; + } + else + { + p_cfg->ui8LookAheadDepth = 1; + p_cfg->ui8noMbtree = 1; + strncpy(p_param_warn, "enable lookahead of current frame", max_err_len); + warning = NI_RETCODE_PARAM_WARN; + } } - - errno = 0; - p_ctx->dev = strtoul(bus + 1, &dev, 16); - - if (errno < 0) + + if (p_cfg->ui8rcEnable == 1) { - ni_log(NI_LOG_ERROR, "Failed to read PCI device\n"); - retval = NI_RETCODE_FAILURE; - LRETURN; + strncpy(p_param_err, "CRF requires RcEnable 0", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_RCENABLE; + LRETURN; } - - errno = 0; - p_ctx->fn = strtoul(dev + 1, &fnc, 16); - - if (errno < 0) + #if 0 + if (p_cfg->ui8ctbRcMode > 0) { - ni_log(NI_LOG_ERROR, "Failed to read PCI function\n"); - retval = NI_RETCODE_FAILURE; - LRETURN; + strncpy(p_param_warn, "Lookahead with cuLevelRCEnable or hvsQPEnable may degrade quality", max_err_len); + warning = NI_RETCODE_PARAM_WARN; + //LRETURN; } + #endif + } - ni_log(NI_LOG_DEBUG, "PCI slot = %d:%d:%d:%d\n", p_ctx->domain, p_ctx->bus, - p_ctx->dev, p_ctx->fn); + if (p_cfg->ui8tuneBframeVisual == TUNE_BFRAME_VISUAL_MEDIUM) + { + if (p_cfg->ui8LookAheadDepth == 0) + { + strncpy(p_param_err, "tuneBframeVisual level 1 (medium) requires lookahead or crf encode", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_RCENABLE; + LRETURN; + } + } } -#endif - -#ifdef XCODER_DUMP_ENABLED - char dump_file[256] = { 0 }; - snprintf(dump_file, sizeof dump_file, "%s%u%s", "decoder_in_id", - p_ctx->session_id, ".264"); - p_ctx->p_dump[0] = fopen(dump_file, "wb"); - ni_log(NI_LOG_DEBUG, "dump_file = %s\n", dump_file); - - snprintf(dump_file, sizeof dump_file, "%s%u%s", "decoder_out_id", - p_ctx->session_id, ".yuv"); - p_ctx->p_dump[1] = fopen(dump_file, "wb"); - ni_log(NI_LOG_DEBUG, "dump_file = %s\n", dump_file); - - if (!p_ctx->p_dump[0] || !p_ctx->p_dump[1]) + if ( p_cfg->niParamT408.enable_mb_level_rc != 1 && + p_cfg->niParamT408.enable_mb_level_rc != 0 ) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): Cannot open dump file\n", __func__); + strncpy(p_param_err, "Invalid enable_mb_level_rc: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_RCENABLE; + LRETURN; } -#endif - -END: - - ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); - return retval; -} -/*!****************************************************************************** -* \brief Copy a xcoder decoder worker thread info -* -* \param -* -* \return -*******************************************************************************/ -ni_retcode_t ni_decoder_session_copy_internal(ni_session_context_t *src_p_ctx, ni_session_context_t *dst_p_ctx) -{ - if (!src_p_ctx || !dst_p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: passed parameters are null!, return\n"); - return NI_RETCODE_INVALID_PARAM; - } - //dst_p_ctx->dts_queue_mutex = src_p_ctx->dts_queue_mutex; - //dst_p_ctx->decoder_read_mutex = src_p_ctx->decoder_read_mutex; - //dst_p_ctx->decoder_read_mutex_len = src_p_ctx->decoder_read_mutex_len; - //dst_p_ctx->decoder_read_cond = src_p_ctx->decoder_read_cond; - //dst_p_ctx->decoder_read_semaphore = src_p_ctx->decoder_read_semaphore; - //dst_p_ctx->decoder_read_workerqueue = src_p_ctx->decoder_read_workerqueue; - dst_p_ctx->max_nvme_io_size = src_p_ctx->max_nvme_io_size; - dst_p_ctx->device_handle = src_p_ctx->device_handle; - dst_p_ctx->blk_io_handle = src_p_ctx->blk_io_handle; - dst_p_ctx->hw_id = src_p_ctx->hw_id; - // - ////dst_p_ctx->worker_queue_decoder_read = src_p_ctx->worker_queue_decoder_read; - //// Here we copy a worker thread pool - //int counter; - //for (counter = 0; counter < MAX_NUM_OF_THREADS_PER_FRAME; counter++) - //{ - // dst_p_ctx->ThreadID_decoder_read[counter] = src_p_ctx->ThreadID_decoder_read[counter]; - //} + if ( p_cfg->niParamT408.minQpI < 0 || + p_cfg->niParamT408.minQpI > 51 ) + { + strncpy(p_param_err, "Invalid min_qp: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_MN_QP; + LRETURN; + } - //pthread_mutex_alloc_and_init(&dst_p_ctx->dts_queue_mutex); + if ( p_cfg->niParamT408.maxQpI < 0 || + p_cfg->niParamT408.maxQpI > 51 ) + { + strncpy(p_param_err, "Invalid max_qp: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_MX_QP; + LRETURN; + } - return NI_RETCODE_SUCCESS; -} + if ( p_cfg->niParamT408.enable_cu_level_rate_control != 1 && + p_cfg->niParamT408.enable_cu_level_rate_control != 0 ) + { + strncpy(p_param_err, "Invalid enable_cu_level_rate_control: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN; + LRETURN; + } -/*!****************************************************************************** -* \brief Send a YUV p_frame to upload session -* -* \param -* -* \return -*******************************************************************************/ -int ni_hwupload_session_write(ni_session_context_t *p_ctx, ni_frame_t *p_frame, - niFrameSurface1_t *hwdesc) -{ - int retval = 0; - uint32_t size = 0; - //uint32_t metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE; - uint32_t i = 0; - uint32_t tx_size = 0, aligned_tx_size = 0; - uint32_t sent_size = 0; - uint32_t frame_size_bytes = 0; - uint32_t retry_count = 0; - ni_instance_buf_info_t buf_info = { 0 }; -#ifdef MEASURE_LATENCY - uint64_t abs_time_ns; -#endif + //if (p_cfg->niParamT408.enable_cu_level_rate_control == 1) + { + if ( p_cfg->niParamT408.enable_hvs_qp != 1 && + p_cfg->niParamT408.enable_hvs_qp != 0 ) + { + strncpy(p_param_err, "Invalid enable_hvs_qp: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_HVS_QP_EN; + LRETURN; + } - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); - //niFrameSurface1_t* p_data3 = (niFrameSurface1_t*)((uint8_t*)p_frame->p_data[3]); - ////p_data3->rsvd = p_meta->hwdesc->rsvd; - //ni_log(NI_LOG_DEBUG, "%s:mar16 HW=%d ui16FrameIdx=%d i8InstID=%d device_handle=%d\n", - // ishwframe, p_data3->ui16FrameIdx, p_data3->i8InstID, p_data3->device_handle); + if (p_cfg->niParamT408.enable_hvs_qp) + { + if ( p_cfg->niParamT408.max_delta_qp < 0 || + p_cfg->niParamT408.max_delta_qp > 51 ) + { + strncpy(p_param_err, "Invalid max_delta_qp: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_MX_DELTA_QP; + LRETURN; + } + } + } + // hrd is off when i32vbvBufferSize is 0 + if ((p_cfg->i32vbvBufferSize < 10 && p_cfg->i32vbvBufferSize != 0) || p_cfg->i32vbvBufferSize > 3000) + { + strncpy(p_param_err, "Invalid i32vbvBufferSize: out of range", max_err_len); + param_ret = NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE; + LRETURN; + } + } - if (!p_ctx || !p_frame) + // check valid for common param + param_ret = ni_check_common_params(&p_cfg->niParamT408, p_src, p_param_err, max_err_len); + if (param_ret != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; LRETURN; } - if (NI_INVALID_SESSION_ID == p_ctx->session_id) + // check valid for RC param + param_ret = ni_check_ratecontrol_params(p_cfg, p_param_err, max_err_len); + if (param_ret != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } -#ifdef MEASURE_LATENCY - if ((p_frame->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) + if (p_cfg->niParamT408.gop_preset_index != GOP_PRESET_IDX_CUSTOM) { - abs_time_ns = ni_gettime_ns(); - ni_lat_meas_q_add_entry((ni_lat_meas_q_t *)p_ctx->frame_time_q, - abs_time_ns, p_frame->dts); + p_ctx->keyframe_factor = + presetGopKeyFrameFactor[p_cfg->niParamT408.gop_preset_index]; } -#endif - - frame_size_bytes = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2];// +p_frame->data_len[3] + p_frame->extra_data_len; - ni_log(NI_LOG_DEBUG, "frame size bytes =%u %d is metadata!\n", frame_size_bytes, - 0); - p_ctx->status = 0; - for (;;) + if (warning == NI_RETCODE_PARAM_WARN && param_ret == NI_RETCODE_SUCCESS) { - //retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, - // NI_DEVICE_TYPE_ENCODER, &buf_info); + param_ret = NI_RETCODE_PARAM_WARN; + strncpy(p_param_err, p_param_warn, max_err_len); + } - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_UPLOAD, - NI_DEVICE_TYPE_ENCODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - //CHECK_VPU_RECOVERY(retval); No need for this because - //no VPU is involved for upload - if (NI_RETCODE_SUCCESS != retval || - (buf_info.hw_inst_ind.buffer_avail == 0 && retry_count >= 500)) - { - ni_log(NI_LOG_TRACE, "Upload write query retry %d\n", retry_count); - retval = NI_RETCODE_ERROR_MEM_ALOC; - p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; - LRETURN; - } - if (buf_info.hw_inst_ind.buffer_avail == 0 && retry_count < 500) - { - retry_count++; - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); - ni_usleep(100); - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); - } else //available - { - ni_log(NI_LOG_DEBUG, "%s: avail %d, FID %d\n", __func__, - buf_info.hw_inst_ind.buffer_avail, - buf_info.hw_inst_ind.frame_index); - break; - } +END: + free(p_param_warn); + return param_ret; +} + +ni_retcode_t ni_check_common_params(ni_t408_config_t *p_param, + ni_xcoder_params_t *p_src, + char *p_param_err, uint32_t max_err_len) +{ + ni_retcode_t ret = NI_RETCODE_SUCCESS; + int32_t low_delay = 0; + int32_t intra_period_gop_step_size; + int32_t i, j; + + if (!p_param || !p_src || !p_param_err) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", + __func__); + ret = NI_RETCODE_INVALID_PARAM; + LRETURN; } - ni_log(NI_LOG_DEBUG, "Info hwupload write query success, available buf " - "size %u >= frame size %u , retry %u\n", - buf_info.buf_avail_size, frame_size_bytes, retry_count); + //Zero out the error buffer + memset(p_param_err, 0, max_err_len); + + // check low-delay gop structure + if (!QUADRA) { -#ifdef XCODER_TIMESTAMP_DTS_ENABLED - retval = ni_timestamp_register(p_ctx->buffer_pool, p_ctx->dts_queue, - p_frame->dts, 0); - if (NI_RETCODE_SUCCESS != retval) + if (0 == p_param->gop_preset_index) // common gop + { + if (p_param->custom_gop_params.custom_gop_size > 1) { - ni_log(NI_LOG_ERROR, - "ERROR %s(): ni_timestamp_register() for dts " - "returned: %d\n", - __func__, retval); + int minVal = p_param->custom_gop_params.pic_param[0].poc_offset; + low_delay = 1; + for (i = 1; i < p_param->custom_gop_params.custom_gop_size; i++) + { + if (minVal > p_param->custom_gop_params.pic_param[i].poc_offset) + { + low_delay = 0; + break; + } else + { + minVal = p_param->custom_gop_params.pic_param[i].poc_offset; + } + } } -#endif - - //Apply write configuration here - retval = ni_config_session_rw(p_ctx, SESSION_WRITE_CONFIG, 1, - NI_CODEC_HW_UPLOAD, 0); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + } + else if (p_param->gop_preset_index == 2 || + p_param->gop_preset_index == 3 || + p_param->gop_preset_index == 6 || + p_param->gop_preset_index == 7) // low-delay case (IPPP, IBBB) + { + low_delay = 1; + } - uint32_t ui32LBA = - WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); - ni_log(NI_LOG_DEBUG, - "%s: p_data = %p, p_frame->buffer_size = %u, " - "p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", - __func__, p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, - ui32LBA); - sent_size = frame_size_bytes; - if (sent_size % NI_MEM_PAGE_ALIGNMENT) + if (low_delay) + { + intra_period_gop_step_size = 1; + } + else + { + if (p_param->gop_preset_index == GOP_PRESET_IDX_CUSTOM) { - sent_size = - ((sent_size / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT) + - NI_MEM_PAGE_ALIGNMENT; + intra_period_gop_step_size = p_param->custom_gop_params.custom_gop_size; } - - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_frame->p_buffer, sent_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_write, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - if (retval < 0) + else { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + intra_period_gop_step_size = presetGopSize[p_param->gop_preset_index]; } + } - hwdesc->ui16FrameIdx = buf_info.hw_inst_ind.frame_index; - hwdesc->ui16session_ID = p_ctx->session_id; - hwdesc->device_handle = - (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); - hwdesc->bit_depth = p_ctx->bit_depth_factor; - hwdesc->src_cpu = (uint8_t)NI_DEVICE_TYPE_ENCODER; - hwdesc->output_idx = 0; + if (((p_param->intra_period != 0) && ((p_param->intra_period < intra_period_gop_step_size+1) == 1)) || + ((p_param->avcIdrPeriod != 0) && ((p_param->avcIdrPeriod < intra_period_gop_step_size+1) == 1))) + { + strncpy(p_param_err, "Invalid intra_period and gop_preset_index: gop structure is larger than intra period", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_INTRA_PERIOD; + LRETURN; + } - p_ctx->frame_num++; - size = frame_size_bytes; + if (((!low_delay) && (p_param->intra_period != 0) && ((p_param->intra_period % intra_period_gop_step_size) != 0)) || + ((!low_delay) && (p_param->avcIdrPeriod != 0) && ((p_param->avcIdrPeriod % intra_period_gop_step_size) != 0))) + { + strncpy(p_param_err, "Invalid intra_period and gop_preset_index: intra period is not a multiple of gop structure size", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_INTRA_PERIOD; + LRETURN; + } -#ifdef XCODER_DUMP_DATA - char dump_file[256]; - snprintf(dump_file, sizeof(dump_file), "%ld-%u-hwup-fme/fme-%04ld.yuv", - (long)getpid(), p_ctx->session_id, (long)p_ctx->frame_num); + if (p_param->gop_preset_index == GOP_PRESET_IDX_CUSTOM) + { + int temp_poc[NI_MAX_GOP_NUM]; + int min_poc = p_param->custom_gop_params.pic_param[0].poc_offset; + for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + { + if (p_param->custom_gop_params.pic_param[i].temporal_id >= XCODER_MAX_NUM_TEMPORAL_LAYER) + { + strncpy(p_param_err, "Invalid custom gop parameters: temporal_id larger than 7", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } - FILE *f = fopen(dump_file, "wb"); - fwrite(p_frame->p_buffer, - p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2], - 1, f); - fflush(f); - fclose(f); -#endif + if (p_param->custom_gop_params.pic_param[i].temporal_id < 0) + { + strncpy(p_param_err, "Invalid custom gop parameters: temporal_id is zero or negative", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + temp_poc[i] = p_param->custom_gop_params.pic_param[i].poc_offset; + if (min_poc > temp_poc[i]) + { + min_poc = temp_poc[i]; + } + } + int count_pos = 0; + for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + { + for (j = 0; j < p_param->custom_gop_params.custom_gop_size; j++) + { + if (temp_poc[j] == min_poc) + { + count_pos++; + min_poc++; + } + } + } + if (count_pos != p_param->custom_gop_params.custom_gop_size) + { + strncpy(p_param_err, "Invalid custom gop parameters: poc_offset is invalid", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } } - -#ifdef MEASURE_LATENCY - if ((p_frame->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) + else // QUADRA { - abs_time_ns = ni_gettime_ns(); - ni_log(NI_LOG_INFO, "DTS:%" PRId64 ",DELTA:%lu,uLAT:%lu;\n", p_frame->dts, - abs_time_ns - p_ctx->prev_read_frame_time, - ni_lat_meas_q_check_latency((ni_lat_meas_q_t *)p_ctx->frame_time_q, - abs_time_ns, p_frame->dts)); - p_ctx->prev_read_frame_time = abs_time_ns; - } -#endif - - retval = size; - -END: - - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); - return retval; -} + if (p_param->custom_gop_params.custom_gop_size) + { + int temp_poc[NI_MAX_GOP_NUM]; + int min_poc = p_param->custom_gop_params.pic_param[0].poc_offset; + for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + { + if (p_param->custom_gop_params.pic_param[i].temporal_id >= XCODER_MAX_NUM_TEMPORAL_LAYER) + { + strncpy(p_param_err, "Invalid custom gop parameters: temporal_id larger than 7", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } -/*!****************************************************************************** -* \brief Retrieve a HW descriptor of uploaded frame -* -* \param p_ctx pointer to uploader session context -* hwdesc pointer to hw descriptor -* -* \return -* On success -* NI_RETCODE_SUCCESS -* On failure -* NI_RETCODE_INVALID_PARAM -* NI_RETCODE_ERROR_INVALID_SESSION -* NI_RETCODE_FAILURE -*******************************************************************************/ -int ni_hwupload_session_read_hwdesc(ni_session_context_t *p_ctx, - niFrameSurface1_t *hwdesc) -{ - int retval = 0; - ni_instance_buf_info_t hwdesc_info = { 0 }; - int query_retry = 0; + if (p_param->custom_gop_params.pic_param[i].temporal_id < 0) + { + strncpy(p_param_err, "Invalid custom gop parameters: temporal_id is negative", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + for (j = 0; j < p_param->custom_gop_params.pic_param[i].num_ref_pics; j++) + { + if (p_param->custom_gop_params.pic_param[i].rps[j].ref_pic == 0) + { + strncpy(p_param_err, "Invalid custom gop parameters: ref pic delta cannot be 0", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } - if (!p_ctx || !hwdesc) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } + for (j = 0; j < NI_MAX_REF_PIC; j++) + { + if (p_param->custom_gop_params.pic_param[i].rps[j].ref_pic != 0 && + p_param->custom_gop_params.pic_param[i].rps[j].ref_pic_used == -1) + { + ni_log(NI_LOG_ERROR,"g%drefPic%d specified without g%drefPic%dUsed specified!\n", i, j, i, j); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } - if (NI_INVALID_SESSION_ID == p_ctx->session_id) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; + temp_poc[i] = p_param->custom_gop_params.pic_param[i].poc_offset; + if (min_poc > temp_poc[i]) + { + min_poc = temp_poc[i]; + } + } + int count_pos = 0; + for (i = 0; i < p_param->custom_gop_params.custom_gop_size; i++) + { + for (j = 0; j < p_param->custom_gop_params.custom_gop_size; j++) + { + if (temp_poc[j] == min_poc) + { + count_pos++; + min_poc++; + } + } + } + if (count_pos != p_param->custom_gop_params.custom_gop_size) + { + strncpy(p_param_err, "Invalid custom gop parameters: poc_offset is invalid", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSTOM_GOP; + LRETURN; + } + } } - for (;;) + if (0 == p_param->use_recommend_enc_params) { - query_retry++; -#ifndef _WIN32 - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_R_ACQUIRE, - NI_DEVICE_TYPE_ENCODER, &hwdesc_info); -#else - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_UPLOAD, - NI_DEVICE_TYPE_ENCODER, &hwdesc_info); -#endif - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - - if (NI_RETCODE_SUCCESS != retval) + // RDO { - ni_log(NI_LOG_DEBUG, "Warning upload read hwdesc fail rc %d or ind " - "!\n", retval); + int align_32_width_flag = p_src->source_width % 32; + int align_16_width_flag = p_src->source_width % 16; + int align_8_width_flag = p_src->source_width % 8; + int align_32_height_flag = p_src->source_height % 32; + int align_16_height_flag = p_src->source_height % 16; + int align_8_height_flag = p_src->source_height % 8; - if (query_retry >= 1000) + if (((p_param->cu_size_mode & 0x1) == 0) && ((align_8_width_flag != 0) || (align_8_height_flag != 0))) { - retval = NI_RETCODE_FAILURE; + strncpy(p_param_err, "Invalid use_recommend_enc_params and cu_size_mode: picture width and height must be aligned with 8 pixels when enable CU8x8 of cu_size_mode. Recommend to set cu_size_mode |= 0x1 (CU8x8)", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN; + LRETURN; + } + else if (((p_param->cu_size_mode & 0x1) == 0) && ((p_param->cu_size_mode & 0x2) == 0) && ((align_16_width_flag != 0) || (align_16_height_flag != 0))) + { + strncpy(p_param_err, "Invalid use_recommend_enc_params and cu_size_mode: picture width and height must be aligned with 16 pixels when enable CU16x16 of cu_size_mode. Recommend to set cu_size_mode |= 0x2 (CU16x16)", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN; + LRETURN; + } + else if (((p_param->cu_size_mode & 0x1) == 0) && ((p_param->cu_size_mode & 0x2) == 0) && ((p_param->cu_size_mode & 0x4) == 0) && ((align_32_width_flag != 0) || (align_32_height_flag != 0))) + { + strncpy(p_param_err, "Invalid use_recommend_enc_params and cu_size_mode: picture width and height must be aligned with 32 pixels when enable CU32x32 of cu_size_mode. Recommend to set cu_size_mode |= 0x4 (CU32x32)", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN; LRETURN; } - } - else - { - ni_log(NI_LOG_DEBUG, "Info hwupload read hwdesc success, " - "frame_ind=%d !\n", hwdesc_info.hw_inst_ind.frame_index); - - hwdesc->ui16FrameIdx = hwdesc_info.hw_inst_ind.frame_index; - hwdesc->ui16session_ID = p_ctx->session_id; - hwdesc->device_handle = - (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); - hwdesc->bit_depth = p_ctx->bit_depth_factor; - hwdesc->src_cpu = (uint8_t)NI_DEVICE_TYPE_ENCODER; - hwdesc->output_idx = 0; - LRETURN; } } -END: - return retval; -} - -/*!***************************************************************************** -* \brief clear a particular xcoder instance buffer/data -* -* \param ni_session_context_t p_ctx - xcoder Context -* \param ni_instance_buf_info_rw_type_t rw_type -* \param ni_device_type_t device_type - xcoder type Encoder or Decoder -* \param ni_instance_buf_info_t *out - Struct preallocated from the caller -* where the resulting data will be placed -* -* \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, -* NI_RETCODE_ERROR_MEM_ALOC or NI_RETCODE_ERROR_NVME_CMD_FAILED on -* failure -******************************************************************************/ -ni_retcode_t ni_clear_instance_buf(niFrameSurface1_t *surface, - int32_t device_handle) -{ - ni_nvme_command_t cmd = { 0 }; - void* p_buffer = NULL; - ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t dataLen = 0; - uint32_t ui32LBA = 0; - - ni_log(NI_LOG_TRACE, "%s(): enter - device_handle %d\n", __func__, - device_handle); - - if ((uint16_t)NI_INVALID_SESSION_ID == surface->ui16session_ID) + if ((p_param->conf_win_top < 0) || (p_param->conf_win_top > 8192)) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; + strncpy(p_param_err, "Invalid conf_win_top: out of range", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP; LRETURN; } - - //malloc data buffer - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) + if (p_param->conf_win_top % 2) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; + strncpy(p_param_err, "Invalid conf_win_top: not multiple of 2", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP; + LRETURN; } - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - //maybe just set 13 aqs inst id again? - ni_log(NI_LOG_DEBUG, "%s():cdw10=0x%x FID = %d\n", __func__, cmd.cdw10, - surface->ui16FrameIdx); - ui32LBA = CLEAR_INSTANCE_BUF_W(((uint16_t)surface->ui16FrameIdx)); - retval = ni_nvme_send_write_cmd((ni_device_handle_t)(int64_t)device_handle, - NI_INVALID_DEVICE_HANDLE, p_buffer, - NI_DATA_BUFFER_LEN, ui32LBA); - //Cannot check sessio stats here since this isn't a session command. - if (retval < 0) + + if ((p_param->conf_win_bottom < 0) || (p_param->conf_win_bottom > 8192)) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + strncpy(p_param_err, "Invalid conf_win_bottom: out of range", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT; + LRETURN; + } + if (p_param->conf_win_bottom % 2) + { + strncpy(p_param_err, "Invalid conf_win_bottom: not multiple of 2", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT; + LRETURN; + } + + if ((p_param->conf_win_left < 0) || (p_param->conf_win_left > 8192)) + { + strncpy(p_param_err, "Invalid conf_win_left: out of range", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_L; + LRETURN; + } + if (p_param->conf_win_left % 2) + { + strncpy(p_param_err, "Invalid conf_win_left: not multiple of 2", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_L; + LRETURN; + } + + if (p_param->conf_win_right < 0 || p_param->conf_win_right > 8192) + { + strncpy(p_param_err, "Invalid conf_win_right: out of range", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_R; + LRETURN; + } + if (p_param->conf_win_right % 2) + { + strncpy(p_param_err, "Invalid conf_win_right: not multiple of 2", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_CONF_WIN_R; } END: - ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); - return retval; + return ret; } -/*!****************************************************************************** -* \brief Retrieve a hw desc p_frame from decoder -* \param -* -* \return -*******************************************************************************/ -ni_retcode_t ni_decoder_session_read_desc(ni_session_context_t* p_ctx, ni_frame_t* p_frame) +ni_retcode_t ni_check_ratecontrol_params(ni_encoder_config_t* p_cfg, char* p_param_err, uint32_t max_err_len) { - //Needs serious editing to support hwdesc read again, this is currently vanilla read - //queue_info decoder_read_workerqueue; - ni_instance_mgr_stream_info_t data = {0}; - int rx_size = 0; - uint64_t frame_offset = 0; - uint16_t yuvW = 0; - uint16_t yuvH = 0; - uint8_t *p_data_buffer; - int i = 0; - int retval = NI_RETCODE_SUCCESS; - int metadata_hdr_size = NI_FW_META_DATA_SZ - - NI_MAX_NUM_OF_DECODER_OUTPUTS * sizeof(niFrameSurface1_t); - int sei_size = 0; - uint32_t total_bytes_to_read = 0; - uint32_t total_yuv_met_size = 0; - uint32_t read_size_bytes = 0; - uint32_t actual_read_size = 0; - int keep_processing = 1; - ni_instance_buf_info_t buf_info = {0}; - int query_retry = 0; - uint32_t ui32LBA = 0; - unsigned int bytes_read_so_far = 0; - int query_type = INST_BUF_INFO_RW_READ; -#ifdef MEASURE_LATENCY - uint64_t abs_time_ns; -#endif - - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); - - if (!p_ctx || !p_frame) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - return NI_RETCODE_INVALID_PARAM; - } + ni_retcode_t ret = NI_RETCODE_SUCCESS; + ni_t408_config_t* p_param = NULL; - if (NI_INVALID_SESSION_ID == p_ctx->session_id) + if( (!p_cfg) || (!p_param_err) ) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; + ni_log(NI_LOG_ERROR, "ERROR: %s() Null pointer parameters passed\n", + __func__); + ret = NI_RETCODE_INVALID_PARAM; + LRETURN; } + p_param = &p_cfg->niParamT408; - p_data_buffer = (uint8_t *)p_frame->p_buffer; - - // p_frame->p_data[] can be NULL before actual resolution is returned by - // decoder and buffer pool is allocated, so no checking here. + //Zero out the error buffer + memset(p_param_err, 0, max_err_len); - total_bytes_to_read = p_frame->data_len[3] + metadata_hdr_size; - total_yuv_met_size = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + metadata_hdr_size; - ni_log(NI_LOG_DEBUG, - "Total bytes to read %u total_yuv_met_size %u, low_delay %u\n", - total_bytes_to_read, total_yuv_met_size, p_ctx->decoder_low_delay); - if (p_ctx->decoder_low_delay > 0 && !p_ctx->ready_to_close) + if (p_param->roiEnable != 0 && p_param->roiEnable != 1) { - ni_log(NI_LOG_DEBUG, "frame_num = %" PRIu64 ", pkt_num = %" PRIu64 "\n", - p_ctx->frame_num, p_ctx->pkt_num); - if (p_ctx->frame_num >= p_ctx->pkt_num) - { - //nothing to query, leave - retval = NI_RETCODE_SUCCESS; - LRETURN; - } - query_type = INST_BUF_INFO_RW_READ_BUSY; + strncpy(p_param_err, "Invalid roiEnable: out of range", max_err_len); + ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; } - for (;;) - { - query_retry++; - retval = ni_query_instance_buf_info(p_ctx, query_type, - NI_DEVICE_TYPE_DECODER, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - - ni_log(NI_LOG_DEBUG, "Info query buf_info.size = %u\n", - buf_info.buf_avail_size); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_TRACE, "Dec read desc failed. Retry %d\n", query_retry); + if (p_param->roiEnable && p_param->enable_hvs_qp) + { + strncpy(p_param_err, "hvsQPEnable and roiEnable: not mutually exclusive", max_err_len); + ret = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } - if (query_retry >= 1000) - { - ni_log(NI_LOG_DEBUG, "Warning: dec read desc failed %d retries. rc=%d" - "\n", query_retry, retval); - retval = NI_RETCODE_SUCCESS; - LRETURN; - } - ni_pthread_mutex_unlock(p_ctx->xcoder_mutex); - ni_usleep(100); - ni_pthread_mutex_lock(p_ctx->xcoder_mutex); - } else if (buf_info.buf_avail_size == metadata_hdr_size) - { - ni_log(NI_LOG_DEBUG, - "(HwFrame) Info only metadata hdr is available, seq change?\n"); - total_bytes_to_read = metadata_hdr_size; - break; - } else if (buf_info.buf_avail_size < total_yuv_met_size) + if (p_cfg->ui8rcEnable == 1) + { + if (p_param->minQpP > p_param->maxQpP || p_param->minQpB > p_param->maxQpB) { - ni_log(NI_LOG_TRACE, "Dec read desc buf_size < frame_size. Retry %d\n", query_retry); - - // query to see if it is eos now, if we have sent it - if (p_ctx->ready_to_close) - { - ni_log(NI_LOG_DEBUG, "Info dec query, ready_to_close %u, query eos\n", - p_ctx->ready_to_close); - retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - - if (data.is_flushed) - { - ni_log(NI_LOG_DEBUG, "Info eos reached.\n"); - p_frame->end_of_stream = 1; - retval = NI_RETCODE_SUCCESS; - LRETURN; - } - } - - if (NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == p_ctx->status && - query_retry < 1000 / 2) - { - ni_usleep(100); - continue; - } else - { - if (p_ctx->decoder_low_delay>0) - { - ni_log(NI_LOG_ERROR, "Warning: low_delay mode non sequential input? Disabling LD\n"); - p_ctx->decoder_low_delay = -1; - } - ni_log(NI_LOG_DEBUG, "Warning: dec read desc failed %d retries. rc=%d" - "\n", query_retry, retval); - } - retval = NI_RETCODE_SUCCESS; + strncpy(p_param_err, "Invalid min_qp(P/B) and max_qp(P/B): min_qp cannot be larger than max_qp", max_err_len); + ret = NI_RETCODE_PARAM_ERROR_MX_QP; LRETURN; } - else - { - // We have to ensure there are adequate number of DTS for picture - // reorder delay otherwise wait for more packets to be sent to decoder. - ni_timestamp_table_t *p_dts_queue = p_ctx->dts_queue; - if ((int)p_dts_queue->list.count < p_ctx->pic_reorder_delay + 1 && - !p_ctx->ready_to_close) - { - retval = NI_RETCODE_SUCCESS; - ni_log(NI_LOG_DEBUG, - "At least %d packets should be sent before reading the " - "first frame!\n", - p_ctx->pic_reorder_delay + 1); - LRETURN; - } - // get actual YUV transfer size if this is the stream's very first read - if (0 == p_ctx->active_video_width || 0 == p_ctx->active_video_height) - { - retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - - ni_log(NI_LOG_DEBUG, "Info dec YUV query, pic size %ux%u xfer frame size " - "%ux%u frame-rate %u is_flushed %u\n", - data.picture_width, data.picture_height, - data.transfer_frame_stride, data.transfer_frame_height, - data.frame_rate, data.is_flushed); - p_ctx->active_video_width = data.transfer_frame_stride; - p_ctx->active_video_height = data.transfer_frame_height; - p_ctx->actual_video_width = data.picture_width; - p_ctx->pixel_format = data.pix_format; - p_ctx->bit_depth_factor = ni_get_bitdepth_factor_from_pixfmt(p_ctx->pixel_format); - //p_ctx->bit_depth_factor = data.transfer_frame_stride / data.picture_width; - p_ctx->is_first_frame = 1; - - ni_log(NI_LOG_DEBUG, "Info dec YUV, adjust frame size from %ux%u to " - "%ux%u\n", p_frame->video_width, p_frame->video_height, - p_ctx->active_video_width, p_ctx->active_video_height); + } - retval = ni_frame_buffer_alloc( - p_frame, p_ctx->actual_video_width, p_ctx->active_video_height, - p_ctx->codec_format == NI_CODEC_FORMAT_H264, 1, - p_ctx->bit_depth_factor, - 3, // Alloc space for write to data[3] and metadata - 1); +END: - if (NI_RETCODE_SUCCESS != retval) - { - LRETURN; - } - total_bytes_to_read = p_frame->data_len[3] + metadata_hdr_size; - p_data_buffer = (uint8_t*)p_frame->p_buffer; - // make sure we don't read more than available - ni_log(NI_LOG_DEBUG, "Info dec buf size: %u YUV frame + meta-hdr size: %u " - "available: %u\n", p_frame->buffer_size, - total_bytes_to_read, buf_info.buf_avail_size); - } - break; - } - }// end while1 query retry + return ret; +} - ni_log(NI_LOG_DEBUG, "total_bytes_to_read %u max_nvme_io_size %u ylen %u cr len " - "%u cb len %u hdr %d\n", - total_bytes_to_read, p_ctx->max_nvme_io_size, - p_frame->data_len[0], p_frame->data_len[1], - p_frame->data_len[2], metadata_hdr_size); - ni_log(NI_LOG_DEBUG, "p_frame->data_len[3] = %u\n", p_frame->data_len[3]); - if (buf_info.buf_avail_size < total_bytes_to_read) +/*!****************************************************************************** + * \brief Print xcoder user configurations + * + * \param + * + * \return + *******************************************************************************/ +void ni_params_print(ni_xcoder_params_t *const p_encoder_params) +{ + if (!p_encoder_params) { - ni_log(NI_LOG_ERROR, - "ERROR %s() avaliable size(%u) less than " - "needed (%u)\n", - __func__, buf_info.buf_avail_size, total_bytes_to_read); - abort(); + return; } - //Apply read configuration here - retval = ni_config_session_rw(p_ctx, SESSION_READ_CONFIG, 1, - NI_CODEC_HW_ENABLE, 0); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + ni_encoder_cfg_params_t *p_enc = &p_encoder_params->cfg_enc_params; - read_size_bytes = total_bytes_to_read; - ui32LBA = READ_INSTANCE_R(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); - if (read_size_bytes % NI_MEM_PAGE_ALIGNMENT) - { - read_size_bytes = ( (read_size_bytes / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT) + NI_MEM_PAGE_ALIGNMENT; - } + ni_log(NI_LOG_DEBUG, "XCoder Params:\n"); - retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_data_buffer, read_size_bytes, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_read, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - if (retval < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; - } else - { - // command issued successfully, now exit - ni_metadata_dec_frame_t *p_meta = - (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer + - p_frame->data_len[0] + - p_frame->data_len[1] + - p_frame->data_len[2] + - p_frame->data_len[3]); + ni_log(NI_LOG_DEBUG, "preset=%d\n", p_encoder_params->preset); + ni_log(NI_LOG_DEBUG, "fps_number / fps_denominator=%u / %u\n", + p_encoder_params->fps_number, + p_encoder_params->fps_denominator); - if (buf_info.buf_avail_size != metadata_hdr_size) - { - // shift metadata to end of triple output -#ifdef _WIN32 - p_data_buffer = (uint8_t *)p_frame->p_buffer + - sizeof(niFrameSurface1_t) * NI_MAX_NUM_OF_DECODER_OUTPUTS; - memcpy(p_meta, p_data_buffer, metadata_hdr_size); -#else - memcpy(p_meta, - p_frame->p_buffer + - sizeof(niFrameSurface1_t) * NI_MAX_NUM_OF_DECODER_OUTPUTS, - metadata_hdr_size); -#endif - sei_size = p_meta->sei_size; - niFrameSurface1_t *p_data3 = - (niFrameSurface1_t *)((uint8_t *)p_frame->p_buffer + - p_frame->data_len[0] + - p_frame->data_len[1] + - p_frame->data_len[2]); + ni_log(NI_LOG_DEBUG, "source_width x source_height=%dx%d\n", p_encoder_params->source_width, p_encoder_params->source_height); + ni_log(NI_LOG_DEBUG, "bitrate=%d\n", p_encoder_params->bitrate); - niFrameSurface1_t *p_data3_1 = - (niFrameSurface1_t *)((uint8_t *)p_frame->p_buffer + - sizeof(niFrameSurface1_t)); - niFrameSurface1_t *p_data3_2 = - (niFrameSurface1_t *)((uint8_t *)p_frame->p_buffer + - 2 * sizeof(niFrameSurface1_t)); - // Libxcoder knows the handle so overwrite here - p_data3->device_handle = - (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); - p_data3_1->device_handle = - (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); - p_data3_2->device_handle = - (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); - p_data3->ui16session_ID = p_data3_1->ui16session_ID = - p_data3_2->ui16session_ID = (uint16_t)p_ctx->session_id; - p_data3->src_cpu = p_data3_1->src_cpu = p_data3_2->src_cpu = - (uint8_t)NI_DEVICE_TYPE_DECODER; + ni_log(NI_LOG_DEBUG, "profile=%d\n", p_enc->profile); + ni_log(NI_LOG_DEBUG, "level_idc=%d\n", p_enc->level_idc); + ni_log(NI_LOG_DEBUG, "high_tier=%d\n", p_enc->high_tier); - p_data3->output_idx = 0; - p_data3_1->output_idx = 1; - p_data3_2->output_idx = 2; + ni_log(NI_LOG_DEBUG, "frame_rate=%d\n", p_enc->frame_rate); - ni_log(NI_LOG_DEBUG, - "p_data3_1:sei_size=%d device_handle=%d == hw_id=%d ses_id=%d\n", - sei_size, p_data3_1->device_handle, p_ctx->hw_id, - p_data3_1->ui16session_ID); - ni_log(NI_LOG_DEBUG, - "p_data3_1: ui16FrameIdx=%d NodeAddre=0x%x planar=%d\n", - p_data3_1->ui16FrameIdx, p_data3_1->ui32nodeAddress, - p_data3_1->encoding_type); - ni_log( - NI_LOG_DEBUG, - "p_data3_2:sei_size=%d device_handle=%d == hw_id=%d ses_id=%d\n", - sei_size, p_data3_2->device_handle, p_ctx->hw_id, - p_data3_2->ui16session_ID); - ni_log(NI_LOG_DEBUG, - "p_data3_2: ui16FrameIdx=%d NodeAddre=0x%x planar=%d\n", - p_data3_2->ui16FrameIdx, p_data3_2->ui32nodeAddress, - p_data3_2->encoding_type); + ni_log(NI_LOG_DEBUG, "use_recommend_enc_params=%d\n", p_enc->use_recommend_enc_params); + ni_log(NI_LOG_DEBUG, "cu_size_mode=%d\n", p_enc->cu_size_mode); + ni_log(NI_LOG_DEBUG, "max_num_merge=%d\n", p_enc->max_num_merge); + ni_log(NI_LOG_DEBUG, "enable_dynamic_8x8_merge=%d\n", p_enc->enable_dynamic_8x8_merge); + ni_log(NI_LOG_DEBUG, "enable_dynamic_16x16_merge=%d\n", p_enc->enable_dynamic_16x16_merge); + ni_log(NI_LOG_DEBUG, "enable_dynamic_32x32_merge=%d\n", p_enc->enable_dynamic_32x32_merge); + // trans_rate not available in Rev B + ni_log(NI_LOG_DEBUG, "enable_rate_control=%d\n", p_enc->rc.enable_rate_control); + ni_log(NI_LOG_DEBUG, "enable_cu_level_rate_control=%d\n", p_enc->rc.enable_cu_level_rate_control); + ni_log(NI_LOG_DEBUG, "enable_hvs_qp=%d\n", p_enc->rc.enable_hvs_qp); + ni_log(NI_LOG_DEBUG, "enable_hvs_qp_scale=%d\n", p_enc->rc.enable_hvs_qp_scale); + ni_log(NI_LOG_DEBUG, "hvs_qp_scale=%d\n", p_enc->rc.hvs_qp_scale); + ni_log(NI_LOG_DEBUG, "min_qp=%d\n", p_enc->rc.min_qp); + ni_log(NI_LOG_DEBUG, "max_qp=%d\n", p_enc->rc.max_qp); + ni_log(NI_LOG_DEBUG, "max_delta_qp=%d\n", p_enc->rc.max_delta_qp); + ni_log(NI_LOG_DEBUG, "vbv_buffer_size=%d\n", p_enc->rc.vbv_buffer_size); + ni_log(NI_LOG_DEBUG, "enable_filler=%d\n", p_enc->rc.enable_filler); + ni_log(NI_LOG_DEBUG, "enable_pic_skip=%d\n", p_enc->rc.enable_pic_skip); - ni_log(NI_LOG_DEBUG, - "%s:sei_size=%d device_handle=%d == hw_id=%d " - "ses_id=%d\n", - __func__, sei_size, p_data3->device_handle, p_ctx->hw_id, - p_data3->ui16session_ID); - ni_log(NI_LOG_DEBUG, - "%s: ui16FrameIdx=%d NodeAddre=0x%x, " - "planar=%d\n", - __func__, p_data3->ui16FrameIdx, p_data3->ui32nodeAddress, - p_data3->encoding_type); - } + ni_log(NI_LOG_DEBUG, "forcedHeaderEnable=%d\n", p_enc->forced_header_enable); + ni_log(NI_LOG_DEBUG, "roi_enable=%d\n", p_enc->roi_enable); + ni_log(NI_LOG_DEBUG, "long_term_ref_enable=%d\n", p_enc->long_term_ref_enable); + ni_log(NI_LOG_DEBUG, "long_term_ref_interval=%d\n", p_enc->long_term_ref_interval); + ni_log(NI_LOG_DEBUG, "long_term_ref_count=%d\n", p_enc->long_term_ref_count); + ni_log(NI_LOG_DEBUG, "conf_win_top=%d\n", p_enc->conf_win_top); + ni_log(NI_LOG_DEBUG, "conf_win_bottom=%d\n", p_enc->conf_win_bottom); + ni_log(NI_LOG_DEBUG, "conf_win_left=%d\n", p_enc->conf_win_left); + ni_log(NI_LOG_DEBUG, "conf_win_right=%d\n", p_enc->conf_win_right); - total_bytes_to_read = total_bytes_to_read + sei_size; - ni_log(NI_LOG_DEBUG, - "decoder read desc success, retval %d " - "total_bytes_to_read include sei %u sei_size %d\n", - __func__, retval, total_bytes_to_read, sei_size); + ni_log(NI_LOG_DEBUG, "intra_qp=%d\n", p_enc->rc.intra_qp); + ni_log(NI_LOG_DEBUG, "enable_mb_level_rc=%d\n", p_enc->rc.enable_mb_level_rc); - if (total_bytes_to_read > NI_MEM_PAGE_ALIGNMENT) + ni_log(NI_LOG_DEBUG, "intra_period=%d\n", p_enc->intra_period); + ni_log(NI_LOG_DEBUG, "decoding_refresh_type=%d\n", p_enc->decoding_refresh_type); + + // Rev. B: H.264 only or HEVC-shared parameters, in ni_t408_config_t + ni_log(NI_LOG_DEBUG, "enable_transform_8x8=%d\n", p_enc->enable_transform_8x8); + ni_log(NI_LOG_DEBUG, "slice_mode=%d\n", p_enc->slice_mode); + ni_log(NI_LOG_DEBUG, "slice_arg=%d\n", p_enc->slice_arg); + ni_log(NI_LOG_DEBUG, "entropy_coding_mode=%d\n", p_enc->entropy_coding_mode); + ni_log(NI_LOG_DEBUG, "intra_mb_refresh_mode=%d\n", p_enc->intra_mb_refresh_mode); + ni_log(NI_LOG_DEBUG, "intra_mb_refresh_arg=%d\n", p_enc->intra_mb_refresh_arg); + ni_log(NI_LOG_DEBUG, "intra_reset_refresh=%d\n", p_enc->intra_reset_refresh); + + ni_log(NI_LOG_DEBUG, "gop_preset_index=%d\n", p_enc->gop_preset_index); +#ifndef QUADRA + if (!QUADRA) + { + if (p_enc->gop_preset_index == GOP_PRESET_IDX_CUSTOM) + { + int i; + ni_log(NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_enc->custom_gop_params.custom_gop_size); + for (i = 0; i < p_enc->custom_gop_params.custom_gop_size; i++) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Oversized metadata!\n", __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_enc->custom_gop_params.pic_param[i].pic_type); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_enc->custom_gop_params.pic_param[i].poc_offset); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_qp=%d\n", i, p_enc->custom_gop_params.pic_param[i].pic_qp); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pic_L0=%d\n", i, p_enc->custom_gop_params.pic_param[i].num_ref_pic_L0); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L0=%d\n", i, p_enc->custom_gop_params.pic_param[i].ref_poc_L0); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].ref_poc_L1=%d\n", i, p_enc->custom_gop_params.pic_param[i].ref_poc_L1); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_enc->custom_gop_params.pic_param[i].temporal_id); } + } } - - //bytes_read_so_far = total_bytes_to_read; - // Note: session status is NOT reset but tracked between send - // and recv to catch and recover from a loop condition - //total_bytes_to_read = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + p_frame->data_len[3] + metadata_hdr_size + sei_size; //since only HW desc - bytes_read_so_far = total_bytes_to_read; - //bytes_read_so_far = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + p_frame->data_len[3] + metadata_hdr_size + sei_size; //since only HW desc - rx_size = ni_create_frame(p_frame, bytes_read_so_far, &frame_offset, true); - p_ctx->frame_pkt_offset = frame_offset; - - if (rx_size > 0) + else // QUADRA +#endif { - ni_log(NI_LOG_DEBUG, "%s(): s-state %d first_frame %d\n", __func__, - p_ctx->session_run_state, p_ctx->is_first_frame); - if (ni_timestamp_get_with_threshold( - p_ctx->dts_queue, 0, (int64_t *)&p_frame->dts, - XCODER_FRAME_OFFSET_DIFF_THRES, 0, - p_ctx->buffer_pool) != NI_RETCODE_SUCCESS) + if (p_enc->custom_gop_params.custom_gop_size) + { + int i, j; + ni_log(NI_LOG_DEBUG, "custom_gop_params.custom_gop_size=%d\n", p_enc->custom_gop_params.custom_gop_size); + for (i = 0; i < NI_MAX_GOP_NUM; i++) { - if (p_ctx->last_dts != NI_NOPTS_VALUE && !p_ctx->ready_to_close) - { - p_ctx->pic_reorder_delay++; - p_frame->dts = p_ctx->last_dts + p_ctx->last_dts_interval; - ni_log(NI_LOG_DEBUG, "Padding DTS: %" PRId64 "\n", p_frame->dts); - } else - { - p_frame->dts = NI_NOPTS_VALUE; - } + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].poc_offset=%d\n", i, p_enc->custom_gop_params.pic_param[i].poc_offset); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_offset=%d\n", i, p_enc->custom_gop_params.pic_param[i].qp_offset); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].qp_factor=%lf\n", i, p_enc->custom_gop_params.pic_param[i].qp_factor); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].temporal_id=%d\n", i, p_enc->custom_gop_params.pic_param[i].temporal_id); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].pic_type=%d\n", i, p_enc->custom_gop_params.pic_param[i].pic_type); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].num_ref_pics=%d\n", i, p_enc->custom_gop_params.pic_param[i].num_ref_pics); + for (j = 0; j < NI_MAX_REF_PIC; j++) + { + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic=%d\n", i, j, p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic); + ni_log(NI_LOG_DEBUG, "custom_gop_params.pic_param[%d].rps[%d].ref_pic_used=%d\n", i, j, p_enc->custom_gop_params.pic_param[i].rps[j].ref_pic_used); + } } + } + } - if (p_ctx->is_first_frame) - { - for (i = 0; i < p_ctx->pic_reorder_delay; i++) - { - if (p_ctx->last_pts == NI_NOPTS_VALUE && - p_ctx->last_dts == NI_NOPTS_VALUE) - { - // If the p_frame->pts is unknown in the very beginning we assume - // p_frame->pts == 0 as well as DTS less than PTS by 1000 * 1/timebase - if (p_frame->pts >= p_frame->dts && - p_frame->pts - p_frame->dts < 1000) - { - break; - } - } + return; +} - if (ni_timestamp_get_with_threshold( - p_ctx->dts_queue, 0, (int64_t *)&p_frame->dts, - XCODER_FRAME_OFFSET_DIFF_THRES, - p_ctx->frame_num % 500 == 0, - p_ctx->buffer_pool) != NI_RETCODE_SUCCESS) - { - p_frame->dts = NI_NOPTS_VALUE; - } - } - // Reset for DTS padding counting - p_ctx->pic_reorder_delay = 0; - } +/*!****************************************************************************** + * \brief decoder keep alive thread function triggers every 1 second + * + * \param void thread args + * + * \return void + *******************************************************************************/ +void *ni_session_keep_alive_thread(void *arguments) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + ni_thread_arg_struct_t *args = (ni_thread_arg_struct_t *)arguments; + ni_session_stats_t inst_info = {0}; + ni_session_context_t ctx = {0}; + uint64_t endtime = ni_gettime_ns(); + uint64_t current_time; + ni_pthread_mutex_t *p_mutex; + //interval(nanoseconds) is equals to ctx.keep_alive_timeout/3(330,000,000ns approximately equal to 1/3 second). + uint64_t interval = args->keep_alive_timeout * 330000000LL; +#ifndef _ANDROID +#ifdef __linux__ + struct sched_param sched_param; + + // Linux has a wide variety of signals, Windows has a few. + // A large number of signals will interrupt the thread, which will cause heartbeat command interval more than 1 second. + // So just mask the unuseful signals in Linux + sigset_t signal; + sigfillset(&signal); + ni_pthread_sigmask(SIG_BLOCK, &signal, NULL); + + /* set up schedule priority + * first try to run with RR mode. + * if fails, try to set nice value. + * if fails either, ignore it and run with default priority. + * Note: Scheduling requires root permission. App is probably exectued + * without root so the priority for this thread might just end up + * being default. + */ + if (((sched_param.sched_priority = sched_get_priority_max(SCHED_RR)) == + -1) || + sched_setscheduler(syscall(SYS_gettid), SCHED_RR, &sched_param) < 0) + { + ni_log(NI_LOG_DEBUG, "%s cannot set scheduler: %s\n", __func__, + strerror(NI_ERRNO)); + if (setpriority(PRIO_PROCESS, 0, -20) != 0) + { + ni_log(NI_LOG_DEBUG, "%s cannot set nice value: %s\n", __func__, + strerror(NI_ERRNO)); + } + } + +#elif defined(_WIN32) + /* set up schedule priority. + * try to set the current thread to time critical level which is the highest prioriy + * level. + */ + if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == + 0) + { + ni_log(NI_LOG_DEBUG, "%s cannot set priority: %d.\n", __func__, + GetLastError()); + } +#endif +#endif +#ifndef _WIN32 + // Set thread name, name is KAT + hw_id + session_id + // hw_id need at most 2 bytes, session_id at most 4 bytes. + char name[16] = {0}; + snprintf(name, sizeof(name), "%s%.2x%.4x", "KAT", args->hw_id, args->session_id); +#if __linux__ + prctl(PR_SET_NAME, name); +#elif __APPLE__ + pthread_setname_np(name); +#endif +#endif + // Initializes the session context variables that keep alive command and query status command need. + ni_device_session_context_init(&ctx); + ctx.last_access_time = endtime; + ctx.hw_id = args->hw_id; + ctx.session_id = args->session_id; + ctx.session_timestamp = args->session_timestamp; + ctx.device_type = args->device_type; + ctx.blk_io_handle = args->device_handle; + ctx.event_handle = args->thread_event_handle; + ctx.p_all_zero_buf = args->p_buffer; + ctx.keep_alive_timeout = args->keep_alive_timeout; + volatile uint64_t * plast_access_time = args->plast_access_time; + if((ctx.last_access_time - *plast_access_time) >= + ctx.keep_alive_timeout * 1000000000LL) + { + ni_log(NI_LOG_ERROR, + "%s creation timeout. session_id=0x%X requested timeout: %" PRIu64 + "ns, ping time delta: %" PRIu64 "ns\n ", + __func__, ctx.session_id, + (uint64_t)ctx.keep_alive_timeout * 1000000000LL, + ctx.last_access_time - *plast_access_time); + } + ni_log(NI_LOG_DEBUG, "%s ctx.keep_alive_timeout: %us.\n", __func__, + ctx.keep_alive_timeout); + p_mutex = args->p_mutex; + + for (;;) + { + ni_pthread_mutex_lock(p_mutex); + + retval = + ni_send_session_keep_alive(ctx.session_id, ctx.blk_io_handle, + ctx.event_handle, ctx.p_all_zero_buf); + + retval = ni_query_session_stats(&ctx, + ctx.device_type, + &inst_info, + retval, + nvme_admin_cmd_xcoder_config); + + if (NI_RETCODE_SUCCESS == retval) + { + retval = ni_nvme_check_error_code(inst_info.ui32LastTransactionCompletionStatus, + nvme_admin_cmd_xcoder_config, + ctx.device_type, + ctx.hw_id, + &(ctx.session_id)); + } + + ni_pthread_mutex_unlock(p_mutex); + + if(retval) + { + uint32_t error_status = inst_info.ui32LastTransactionCompletionStatus; + if(error_status == NI_RETCODE_SUCCESS) + { + /* QDFWSH-971: Error is sometimes captured by keep_alive_thread + but LastTransactionCompletionStatus may be overwrited and cause + incorrect log. In this case, check LastErrorStatus.*/ + ni_log(NI_LOG_ERROR, "session_no 0x%x inst_err_no may be overwrited!\n", + ctx.session_id); + ni_nvme_check_error_code(inst_info.ui32LastErrorStatus, + nvme_admin_cmd_xcoder_config, + ctx.device_type, + ctx.hw_id, + &(ctx.session_id)); + error_status = inst_info.ui32LastErrorStatus; + } + ni_log(NI_LOG_ERROR, + "Persistent failures detected, %s() line-%d: session_no 0x%x sess_err_no %u " + "inst_err_no %u\n", + __func__, __LINE__, ctx.session_id, inst_info.ui16ErrorCount, error_status); + LRETURN; + } + current_time = ni_gettime_ns(); + /*If the interval between two heartbeats is greater then expected(interval) or + acceptable(timeout) then the thread might have been blocked.*/ + if ((current_time - ctx.last_access_time) >= (2 * interval) || //*2 is for safety + (current_time - ctx.last_access_time) >= + args->keep_alive_timeout * 1000000000LL) + { + ni_log( + NI_LOG_ERROR, + "%s was possibly blocked. session_id=0x%X requested timeout: %" PRIu64 + "ns, ping time delta: %" PRIu64 "ns\n ", + __func__, ctx.session_id, + (uint64_t)ctx.keep_alive_timeout * 1000000000LL, + current_time - ctx.last_access_time); + } + *plast_access_time = ctx.last_access_time = current_time; + if (ctx.session_id == NI_INVALID_SESSION_ID) + { + retval = NI_RETCODE_ERROR_INVALID_SESSION; + } + + // 1. If received failure, set the close_thread flag to TRUE, and exit, + // then main thread will check this flag and return failure directly; + // 2. skip checking VPU recovery. + // If keep_alive thread detect the VPU RECOVERY before main thread, + // the close_thread flag may damage the vpu recovery handling process. + if ((NI_RETCODE_SUCCESS != retval) && + (NI_RETCODE_NVME_SC_VPU_RECOVERY != retval)) + { + LRETURN; + } + endtime += interval; + while (ni_gettime_ns() < endtime) + { + if (args->close_thread) + { + LRETURN; + } + ni_usleep(10000); // 10ms per loop + } + } + +END: + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log(NI_LOG_ERROR, "%s abnormal closed:%d\n", __func__, retval); + // changing the value to be True here means the thread has been closed. + args->close_thread = true; + } + + ni_device_session_context_clear(&ctx); + + ni_log(NI_LOG_DEBUG, "%s(): exit\n", __func__); + + return NULL; +} + +/*!****************************************************************************** +* \brief Open a xcoder upload instance +* +* \param p_ctx - pointer to caller allocated uploader session context +* +* \return +* On success +* NI_RETCODE_SUCCESS +* +* On failure +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_ERROR_MEM_ALOC +* NI_RETCODE_ERROR_INVALID_SESSION +* NI_RETCODE_FAILURE +*******************************************************************************/ +ni_retcode_t ni_uploader_session_open(ni_session_context_t* p_ctx) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + void * p_buffer = NULL; + uint32_t ui32LBA = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + //Create the session if the create session flag is set + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + p_ctx->device_type = NI_DEVICE_TYPE_UPLOAD; + p_ctx->pts_table = NULL; + p_ctx->dts_queue = NULL; + p_ctx->p_leftover = NULL; + p_ctx->buffer_pool = NULL; + p_ctx->prev_size = 0; + p_ctx->sent_size = 0; + p_ctx->status = 0; + p_ctx->key_frame_type = 0; + p_ctx->ready_to_close = 0; + p_ctx->rc_error_count = 0; + p_ctx->frame_num = 0; + p_ctx->pkt_num = 0; + p_ctx->pkt_index = 0; + + //malloc zero data buffer + if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), + NI_DATA_BUFFER_LEN)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_ctx->p_all_zero_buf, 0, NI_DATA_BUFFER_LEN); + + //malloc data buffer + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + + //Set session ID to be invalid. In case we cannot open session, the session id wold remain invalid. + //In case we can open sesison, the session id would become valid. + ((ni_session_stats_t *)p_buffer)->ui16SessionId = + (uint16_t)NI_INVALID_SESSION_ID; + + // First uint32_t is either an invaild session ID or a valid session ID, depending on if session could be opened + ui32LBA = OPEN_SESSION_CODEC(NI_DEVICE_TYPE_ENCODER, ni_htonl(p_ctx->codec_format), 1/*1 for uploadMode*/); + retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); + LRETURN; + } + //Open will return a session status structure with a valid session id if it worked. + //Otherwise the invalid session id set before the open command will stay + p_ctx->session_id = ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); + p_ctx->session_timestamp = ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_high); + p_ctx->session_timestamp = (p_ctx->session_timestamp << 32) | + ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_low); + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): p_ctx->device_handle=%" PRIx64 + ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", + __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, + p_ctx->session_id); + ni_encoder_session_close(p_ctx, 0); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + ni_log2(p_ctx, NI_LOG_DEBUG, + "Uploader open session ID:0x%x,timestamp:%" PRIu64 "\n", + p_ctx->session_id, p_ctx->session_timestamp); + + //Send keep alive timeout Info + uint64_t keep_alive_timeout = + p_ctx->keep_alive_timeout * 1000000; //send us to FW + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, + keep_alive_timeout); + ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): nvme write keep_alive_timeout command " + "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", + __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "Open session completed\n"); + } + + // init for frame pts calculation + p_ctx->is_first_frame = 1; + p_ctx->last_pts = 0; + p_ctx->last_dts = 0; + + ni_timestamp_init(p_ctx, &p_ctx->pts_table, "dec_pts"); + ni_timestamp_init(p_ctx, &p_ctx->dts_queue, "dec_dts"); + + //p_ctx->active_video_width = 0; + //p_ctx->active_video_height = 0; + + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_ctx->device_handle=%" PRIx64 ", p_ctx->hw_id=%d, " + "p_ctx->session_id=%d\n", + __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, + p_ctx->session_id); + + p_ctx->hw_action = NI_CODEC_HW_NONE; +#ifndef _WIN32 + // If this is a P2P upload session, open the Netint kernel driver + if (p_ctx->isP2P) + { + retval = p2p_fill_pcie_address(p_ctx); + if(retval != NI_RETCODE_SUCCESS) + { + LRETURN; + } + } +#endif + +END: + + ni_aligned_free(p_buffer); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + return retval; +} + +/*!****************************************************************************** +* \brief Copy a xcoder decoder worker thread info +* +* \param +* +* \return +*******************************************************************************/ +ni_retcode_t ni_decoder_session_copy_internal(ni_session_context_t *src_p_ctx, ni_session_context_t *dst_p_ctx) +{ + if (!src_p_ctx || !dst_p_ctx) + { + ni_log(NI_LOG_ERROR, "ERROR %s(): passed parameters are null!, return\n", __func__); + return NI_RETCODE_INVALID_PARAM; + } + + dst_p_ctx->pext_mutex = src_p_ctx->pext_mutex; //for hwdl + dst_p_ctx->max_nvme_io_size = src_p_ctx->max_nvme_io_size; + dst_p_ctx->device_handle = src_p_ctx->device_handle; + dst_p_ctx->blk_io_handle = src_p_ctx->blk_io_handle; + dst_p_ctx->hw_id = src_p_ctx->hw_id; + dst_p_ctx->session_timestamp = src_p_ctx->session_timestamp; + if (src_p_ctx->isP2P) + { + dst_p_ctx->isP2P = src_p_ctx->isP2P; + dst_p_ctx->ddr_config = src_p_ctx->ddr_config; + dst_p_ctx->domain = src_p_ctx->domain; + dst_p_ctx->bus = src_p_ctx->bus; + dst_p_ctx->dev = src_p_ctx->dev; + dst_p_ctx->fn = src_p_ctx->fn; + dst_p_ctx->netint_fd = src_p_ctx->netint_fd; + } + + return NI_RETCODE_SUCCESS; +} + +/*!****************************************************************************** +* \brief Send a YUV p_frame to upload session +* +* \param +* +* \return +*******************************************************************************/ +int ni_hwupload_session_write(ni_session_context_t *p_ctx, ni_frame_t *p_frame, + niFrameSurface1_t *hwdesc) +{ + int retval = 0; + uint32_t size = 0; + //uint32_t metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE; + uint32_t i = 0; + uint32_t sent_size = 0; + uint32_t frame_size_bytes = 0; + uint32_t retry_count = 0; + ni_instance_buf_info_t buf_info = { 0 }; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + //niFrameSurface1_t* p_data3 = (niFrameSurface1_t*)((uint8_t*)p_frame->p_data[3]); + ////p_data3->rsvd = p_meta->hwdesc->rsvd; + //ni_log2(p_ctx, NI_LOG_DEBUG, "%s:mar16 HW=%d ui16FrameIdx=%d i8InstID=%d device_handle=%d\n", + // ishwframe, p_data3->ui16FrameIdx, p_data3->i8InstID, p_data3->device_handle); + + if (!p_ctx || !p_frame) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + uint8_t separate_metadata = p_frame->separate_metadata; + uint8_t separate_start = (p_frame->separate_start && p_frame->total_start_len) ? 1 : 0; + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + +#ifdef MEASURE_LATENCY + if ((p_frame->pts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) + { + uint64_t abs_time_ns = ni_gettime_ns(); + ni_lat_meas_q_add_entry((ni_lat_meas_q_t *)p_ctx->frame_time_q, + abs_time_ns, p_frame->pts); + } +#endif + + frame_size_bytes = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2];// +p_frame->data_len[3] + p_frame->extra_data_len; + ni_log2(p_ctx, NI_LOG_DEBUG, "frame size bytes =%u %d is metadata!\n", frame_size_bytes, + 0); + p_ctx->status = 0; + + if (p_frame->end_of_stream) + { + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + + for (;;) + { + query_sleep(p_ctx); + + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_UPLOAD, + NI_DEVICE_TYPE_ENCODER, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval || + (buf_info.hw_inst_ind.buffer_avail == 0 && retry_count >= 500)) + { + if (retry_count >= 500) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "hwupload write exceeded max query retries. rc=%d try=%d" + "\n", + retval, retry_count); + } + retval = NI_RETCODE_ERROR_MEM_ALOC; + p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; + LRETURN; + } + if (buf_info.hw_inst_ind.buffer_avail == 0 && retry_count < 500) + { + retry_count++; + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(100); + ni_pthread_mutex_lock(&p_ctx->mutex); + } else //available + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: avail %d, FID %d\n", __func__, + buf_info.hw_inst_ind.buffer_avail, + buf_info.hw_inst_ind.frame_index); + break; + } + } + ni_log2(p_ctx, NI_LOG_DEBUG, "Info hwupload write query success, available buf " + "size %u >= frame size %u , retry %u\n", + buf_info.buf_avail_size, frame_size_bytes, retry_count); + + { +#ifdef XCODER_TIMESTAMP_DTS_ENABLED + retval = ni_timestamp_register(p_ctx->buffer_pool, p_ctx->dts_queue, + p_frame->dts, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): ni_timestamp_register() for dts " + "returned: %d\n", + __func__, retval); + } +#endif + + //Apply write configuration here + retval = ni_config_session_rw(p_ctx, SESSION_WRITE_CONFIG, 1, + NI_CODEC_HW_UPLOAD, 0); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + if (separate_metadata) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6S") < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): uploader separated metadata not supported on device with FW api version < 6.S\n", + __func__); + retval = NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + LRETURN; + } + + if (!p_frame->p_metadata_buffer) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): p_metadata_buffer is NULL, allocation failed?\n", + __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + + // fill in metadata + ni_metadata_enc_frame_t *p_meta; + p_meta = (ni_metadata_enc_frame_t *)p_frame->p_metadata_buffer; + + if (separate_start) + { + for (i = 0; i < NI_MAX_NUM_SW_FRAME_DATA_POINTERS; i++) + p_meta->start_len[i] = p_frame->start_len[i]; + } + else + { + memset(p_meta->start_len, 0, sizeof(p_meta->start_len)); + } + p_meta->inconsecutive_transfer = p_frame->inconsecutive_transfer; + + ni_log( + NI_LOG_DEBUG, + "%s(): %d.%u p_ctx->frame_num=%" PRIu64 ", " + "p_frame->video_width=%u, p_frame->video_height=%u, " + "start_len [%u,%u,%u] inconsecutive_transfer %u\n", + __func__, p_ctx->hw_id, p_ctx->session_id, p_ctx->frame_num, + p_frame->video_width, p_frame->video_height, + p_meta->start_len[0], p_meta->start_len[1], p_meta->start_len[2], + p_meta->inconsecutive_transfer); + + uint32_t ui32LBA_metadata = + WRITE_METADATA_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_metadata_buffer = %p, metadata_buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_metadata_buffer, + p_frame->metadata_buffer_size, p_ctx->frame_num, + ui32LBA_metadata); + + sent_size = + ((p_frame->metadata_buffer_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd( + p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_metadata_buffer, sent_size, + ui32LBA_metadata); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", + __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } + + if (separate_start) + { + if (!p_frame->p_start_buffer) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): p_start_buffer is NULL, allocation failed?\n", + __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + + uint32_t ui32LBA = + WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_start_buffer = %p, p_frame->start_buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_start_buffer, p_frame->start_buffer_size, p_ctx->frame_num, + ui32LBA); + + sent_size = + ((p_frame->start_buffer_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_start_buffer, sent_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } + + if (p_frame->inconsecutive_transfer) + { + uint32_t ui32LBA = + WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + + for (i = 0; i < NI_MAX_NUM_SW_FRAME_DATA_POINTERS; i++) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_data = %p, p_frame->buffer_size " + "= %u, p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, + ui32LBA); + + if (p_frame->data_len[i]) + { + sent_size = p_frame->data_len[i]; + if (separate_start) + sent_size -= p_frame->start_len[i]; + + sent_size = + ((sent_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_data[i]+p_frame->start_len[i], sent_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } + } + } + else + { + uint32_t ui32LBA = + WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: p_data = %p, p_frame->buffer_size = %u, " + "p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + __func__, p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, + ui32LBA); + + sent_size = frame_size_bytes; + if (separate_start) + sent_size -= p_frame->total_start_len; + + sent_size = + ((sent_size + (NI_MEM_PAGE_ALIGNMENT-1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_buffer+p_frame->total_start_len, sent_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } + + hwdesc->ui16FrameIdx = buf_info.hw_inst_ind.frame_index; + hwdesc->ui16session_ID = p_ctx->session_id; + hwdesc->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + hwdesc->bit_depth = p_ctx->bit_depth_factor; + hwdesc->src_cpu = (uint8_t)NI_DEVICE_TYPE_ENCODER; + hwdesc->output_idx = hwdesc->ui32nodeAddress = 0; + + p_ctx->frame_num++; + size = frame_size_bytes; + +#ifdef XCODER_DUMP_DATA + char dump_file[256]; + snprintf(dump_file, sizeof(dump_file), "%ld-%u-hwup-fme/fme-%04ld.yuv", + (long)getpid(), p_ctx->session_id, (long)p_ctx->frame_num); + + FILE *f = fopen(dump_file, "wb"); + fwrite(p_frame->p_buffer, + p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2], + 1, f); + fflush(f); + fclose(f); +#endif + } + +#ifdef MEASURE_LATENCY + if ((p_frame->pts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) + { + uint64_t abs_time_ns = ni_gettime_ns(); + ni_lat_meas_q_t *q = (ni_lat_meas_q_t *)p_ctx->frame_time_q; + ni_log(NI_LOG_INFO, "PTS:%" PRId64 ",DELTA:%" PRId64 ",uLAT:%" PRIu64 ";\n", + p_frame->pts, abs_time_ns - q->last_benchmark_time, + ni_lat_meas_q_check_latency(q, abs_time_ns, p_frame->pts)); + q->last_benchmark_time = abs_time_ns; + } +#endif + + retval = size; + +END: + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + return retval; +} + +/*!****************************************************************************** +* \brief Retrieve a HW descriptor of uploaded frame +* +* \param p_ctx pointer to uploader session context +* hwdesc pointer to hw descriptor +* +* \return +* On success +* NI_RETCODE_SUCCESS +* On failure +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_ERROR_INVALID_SESSION +* NI_RETCODE_FAILURE +*******************************************************************************/ +int ni_hwupload_session_read_hwdesc(ni_session_context_t *p_ctx, + niFrameSurface1_t *hwdesc) +{ + int retval = 0; + ni_instance_buf_info_t hwdesc_info = { 0 }; + int query_retry = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx || !hwdesc) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + for (;;) + { + query_sleep(p_ctx); + + query_retry++; +#ifndef _WIN32 + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_R_ACQUIRE, + NI_DEVICE_TYPE_ENCODER, &hwdesc_info); +#else + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_UPLOAD, + NI_DEVICE_TYPE_ENCODER, &hwdesc_info); +#endif + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning upload read hwdesc fail rc %d or ind " + "!\n", retval); + + if (query_retry >= 1000) + { + retval = NI_RETCODE_FAILURE; + LRETURN; + } + ni_usleep(100); + } + else + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Info hwupload read hwdesc success, " + "frame_ind=%d !\n", hwdesc_info.hw_inst_ind.frame_index); + + hwdesc->ui16FrameIdx = hwdesc_info.hw_inst_ind.frame_index; + hwdesc->ui16session_ID = p_ctx->session_id; + hwdesc->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + hwdesc->bit_depth = p_ctx->bit_depth_factor; + hwdesc->src_cpu = (uint8_t)NI_DEVICE_TYPE_ENCODER; + hwdesc->output_idx = 0; + LRETURN; + } + } + +END: + return retval; +} + +/*!***************************************************************************** +* \brief clear a particular xcoder instance buffer/data +* +* \param ni_session_context_t p_ctx - xcoder Context +* \param ni_instance_buf_info_rw_type_t rw_type +* \param ni_device_type_t device_type - xcoder type Encoder or Decoder +* \param ni_instance_buf_info_t *out - Struct preallocated from the caller +* where the resulting data will be placed +* +* \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, +* NI_RETCODE_ERROR_MEM_ALOC or NI_RETCODE_ERROR_NVME_CMD_FAILED on +* failure +******************************************************************************/ +ni_retcode_t ni_clear_instance_buf(niFrameSurface1_t *surface) +{ + void* p_buffer = NULL; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + + ni_log(NI_LOG_TRACE, "%s(): enter - device_handle %d\n", __func__, + surface->device_handle); + + if ((uint16_t)NI_INVALID_SESSION_ID == surface->ui16session_ID) + { + ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + //malloc data buffer + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + ni_log(NI_LOG_DEBUG, "%s(): FID = %d\n", __func__, surface->ui16FrameIdx); + ui32LBA = CLEAR_INSTANCE_BUF_W(((uint16_t)surface->ui16FrameIdx)); + retval = ni_nvme_send_write_cmd((ni_device_handle_t)(int64_t)surface->device_handle, + NI_INVALID_DEVICE_HANDLE, p_buffer, + NI_DATA_BUFFER_LEN, ui32LBA); + //Cannot check sessio stats here since this isn't a session command. + if (retval < 0) + { + ni_log(NI_LOG_ERROR, "[session_id=0x%x,time_stamp=%" PRIu64 "] " "%s(): NVME command Failed\n", surface->ui16session_ID, ni_log_get_utime(), __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + +END: + + ni_aligned_free(p_buffer); + ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + return retval; +} + +/*!****************************************************************************** +* \brief Retrieve a hw desc p_frame from decoder +* \param +* +* \return +*******************************************************************************/ +ni_retcode_t ni_decoder_session_read_desc(ni_session_context_t* p_ctx, ni_frame_t* p_frame) +{ + //Needs serious editing to support hwdesc read again, this is currently vanilla read + //queue_info decoder_read_workerqueue; + ni_instance_mgr_stream_info_t data = {0}; + int rx_size = 0; + uint64_t frame_offset = 0; + uint8_t *p_data_buffer = NULL; + int i = 0; + int retval = NI_RETCODE_SUCCESS; + int metadata_hdr_size = NI_FW_META_DATA_SZ - + NI_MAX_NUM_OF_DECODER_OUTPUTS * sizeof(niFrameSurface1_t); + int sei_size = 0; + uint32_t total_bytes_to_read = 0; + uint32_t total_yuv_met_size = 0; + uint32_t read_size_bytes = 0; + ni_instance_buf_info_t buf_info = {0}; + int query_retry = 0; + uint32_t ui32LBA = 0; + unsigned int bytes_read_so_far = 0; + int query_type = INST_BUF_INFO_RW_READ; + int low_delay_notify = 0; + ni_session_statistic_t sessionStatistic = {0}; + uint32_t frames_dropped = 0; + ni_xcoder_params_t *p_param; + uint8_t get_first_metadata = 0; + uint8_t sequence_change = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx || !p_frame) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + +start: + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + p_param = (ni_xcoder_params_t *)p_ctx->p_session_config; + p_data_buffer = (uint8_t *)p_frame->p_buffer; + + // p_frame->p_data[] can be NULL before actual resolution is returned by + // decoder and buffer pool is allocated, so no checking here. + + total_bytes_to_read = p_frame->data_len[3] + metadata_hdr_size; + total_yuv_met_size = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + metadata_hdr_size; + ni_log2(p_ctx, NI_LOG_DEBUG, + "Total bytes to read %u total_yuv_met_size %u, low_delay %u\n", + total_bytes_to_read, total_yuv_met_size, p_ctx->decoder_low_delay); + if (p_ctx->decoder_low_delay > 0 && !p_ctx->ready_to_close) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "frame_num = %" PRIu64 ", pkt_num = %" PRIu64 "\n", + p_ctx->frame_num, p_ctx->pkt_num); + frames_dropped = p_ctx->session_statistic.ui32FramesDropped; + if (p_ctx->force_low_delay && (p_ctx->force_low_delay_cnt < frames_dropped)) { + p_ctx->force_low_delay_cnt = frames_dropped; + } + if (p_ctx->frame_num + p_ctx->force_low_delay_cnt + >= p_ctx->pkt_num) + { + //nothing to query, leave + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + query_type = INST_BUF_INFO_RW_READ_BUSY; + } + for (;;) + { + query_sleep(p_ctx); + + query_retry++; + + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6r3") >= 0) + { + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_DECODER, + &sessionStatistic); + CHECK_ERR_RC(p_ctx, retval, &sessionStatistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + CHECK_VPU_RECOVERY(retval); + + buf_info.buf_avail_size = sessionStatistic.ui32RdBufAvailSize; + } else + { + retval = ni_query_instance_buf_info(p_ctx, query_type, + NI_DEVICE_TYPE_DECODER, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + } + + ni_log2(p_ctx, NI_LOG_TRACE, "Dec read desc query buf_info.size = %u\n", + buf_info.buf_avail_size); + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_TRACE, "Dec read desc failed. Retry %d\n", query_retry); + + if (query_retry >= 1000) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning: dec read desc failed %d retries. rc=%d" + "\n", query_retry, retval); + p_ctx->max_retry_fail_count[1]++; + low_delay_notify = 1; + retval = (p_ctx->max_retry_fail_count[1] >= NI_XCODER_FAILURES_MAX) ? NI_RETCODE_FAILURE : NI_RETCODE_SUCCESS; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); + } else if (buf_info.buf_avail_size == DP_IPC_PASSTHRU) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): Bad available buffer size %u\n", __FUNCTION__, buf_info.buf_avail_size); + retval = NI_RETCODE_FAILURE; + LRETURN; + } else if (buf_info.buf_avail_size == metadata_hdr_size) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Dec read desc only hdr metadata is available. Seq change may " + "have occured.\n"); + total_bytes_to_read = metadata_hdr_size; + sequence_change = 1; + break; + } else if (buf_info.buf_avail_size < total_yuv_met_size) + { + ni_log2(p_ctx, NI_LOG_TRACE, "Dec read desc buf_size < frame_size. Retry %d\n", query_retry); + + // query to see if it is eos now, if we have sent it + if (p_ctx->ready_to_close) + { + ni_log2(p_ctx, NI_LOG_TRACE, + "Dec read desc query, ready_to_close %u, query eos\n", + p_ctx->ready_to_close); + retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + if (data.is_flushed || + query_retry >= + NI_MAX_DEC_SESSION_READ_QUERY_EOS_RETRIES) // 15000 retries + { + if (query_retry >= + NI_MAX_DEC_SESSION_READ_QUERY_EOS_RETRIES) //15000 retries + { + ni_log2(p_ctx, NI_LOG_ERROR, + "WARNING: Dec read desc query eos reached but exceeded max " + "retries. is_flushed=%u try=%d.\n", + data.is_flushed, query_retry); + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Dec read desc query eos reached. is_flushed=%u try=%d" + "\n", + data.is_flushed, query_retry); + } + p_frame->end_of_stream = 1; + low_delay_notify = 1; + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + else + { + ni_log2(p_ctx, NI_LOG_TRACE, + "Dec read desc available buf size == %d, query try %d, " + "retrying...\n", + buf_info.buf_avail_size, query_retry); + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_200US); // 200 us + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; + } + } + + if ((NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == p_ctx->status || + (p_ctx->decoder_low_delay > 0 && + ((p_ctx->frame_num + p_ctx->force_low_delay_cnt) + < p_ctx->pkt_num))) && + query_retry < 1000 / 2) + { + if (p_ctx->decoder_low_delay && p_ctx->force_low_delay) { + if (p_ctx->session_statistic.ui32FramesDropped > frames_dropped) { + // last pkt sent to decoder marked as dropped, no output, + // so just stop query and return + p_ctx->force_low_delay_cnt++; + low_delay_signal(p_ctx); + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); + + continue; + } else + { + if (p_ctx->decoder_low_delay > 0) + { + if (p_ctx->force_low_delay) { + p_ctx->force_low_delay_cnt++; + low_delay_signal(p_ctx); + } else { + ni_log2(p_ctx, NI_LOG_ERROR,"Warning: low delay mode with non sequential " + "input (B frames)? Just cancel the low delay mode then\n"); + // Here it should be the last signal to release the send thread + // holding the low delay mutex. + low_delay_signal(p_ctx); + p_ctx->decoder_low_delay = 0; + } + } + + if ((p_param->dec_input_params.min_packets_delay && p_ctx->pkt_delay_cnt)) + { + if(p_ctx->pkt_num >= (p_ctx->frame_num + p_ctx->pkt_delay_cnt + + p_ctx->session_statistic.ui32FramesDropped)) + { + if(query_retry <= 2000) + { + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(25); + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; + } else { + p_ctx->pkt_delay_cnt++; + ni_log2(p_ctx, NI_LOG_ERROR, + "Warning: decoder pkt_num %u frame_num %u " + "timeout, increaing pkt_delay_cnt to %u\n", + p_ctx->pkt_num, p_ctx->frame_num, + p_ctx->pkt_delay_cnt); + } + } + } + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning: dec read desc failed %d retries. rc=%d" + "\n", query_retry, retval); + } + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + else + { + // We have to ensure there are adequate number of DTS for picture + // reorder delay otherwise wait for more packets to be sent to decoder. + ni_timestamp_table_t *p_dts_queue = p_ctx->dts_queue; + if ((int)p_dts_queue->list.count < p_ctx->pic_reorder_delay + 1 && + !p_ctx->ready_to_close && + NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL != p_ctx->status) + { + retval = NI_RETCODE_SUCCESS; + ni_log2(p_ctx, NI_LOG_DEBUG, + "At least %d packets should be sent before reading the " + "first frame!\n", + p_ctx->pic_reorder_delay + 1); + LRETURN; + } + p_ctx->max_retry_fail_count[1] = 0; + + // get actual YUV transfer size if this is the stream's very first read + if (0 == p_ctx->active_video_width || 0 == p_ctx->active_video_height) + { + retval = ni_query_stream_info(p_ctx, NI_DEVICE_TYPE_DECODER, &data); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec YUV query, pic size %ux%u xfer frame size " + "%ux%u frame-rate %u is_flushed %u\n", + data.picture_width, data.picture_height, + data.transfer_frame_stride, data.transfer_frame_height, + data.frame_rate, data.is_flushed); + p_ctx->active_video_width = data.transfer_frame_stride; + p_ctx->active_video_height = data.transfer_frame_height; + p_ctx->actual_video_width = data.picture_width; + p_ctx->pixel_format = data.pix_format; + p_ctx->bit_depth_factor = ni_get_bitdepth_factor_from_pixfmt(p_ctx->pixel_format); + //p_ctx->bit_depth_factor = data.transfer_frame_stride / data.picture_width; + p_ctx->is_first_frame = 1; + p_ctx->pixel_format_changed = 0; + + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec YUV, adjust frame size from %ux%u to " + "%ux%u\n", p_frame->video_width, p_frame->video_height, + p_ctx->active_video_width, p_ctx->active_video_height); + + retval = ni_frame_buffer_alloc( + p_frame, p_ctx->actual_video_width, p_ctx->active_video_height, + p_ctx->codec_format == NI_CODEC_FORMAT_H264, 1, + p_ctx->bit_depth_factor, + 3, // Alloc space for write to data[3] and metadata + 1); + + if (NI_RETCODE_SUCCESS != retval) + { + LRETURN; + } + total_bytes_to_read = p_frame->data_len[3] + metadata_hdr_size; + p_data_buffer = (uint8_t*)p_frame->p_buffer; + // make sure we don't read more than available + ni_log2(p_ctx, NI_LOG_DEBUG, "Info dec buf size: %u YUV frame + meta-hdr size: %u " + "available: %u\n", p_frame->buffer_size, + total_bytes_to_read, buf_info.buf_avail_size); + } + break; + } + }// end while1 query retry + + ni_log2(p_ctx, NI_LOG_DEBUG, "total_bytes_to_read %u max_nvme_io_size %u ylen %u cr len " + "%u cb len %u hdr %d\n", + total_bytes_to_read, p_ctx->max_nvme_io_size, + p_frame->data_len[0], p_frame->data_len[1], + p_frame->data_len[2], metadata_hdr_size); + + ni_log2(p_ctx, NI_LOG_DEBUG, "p_frame->data_len[3] = %u\n", p_frame->data_len[3]); + if (buf_info.buf_avail_size < total_bytes_to_read) + { + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s() avaliable size(%u) less than " + "needed (%u)\n", + __func__, buf_info.buf_avail_size, total_bytes_to_read); + abort(); + } else if (total_bytes_to_read == metadata_hdr_size && !p_ctx->frame_num) + { + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rE") >= 0) + { + // allocate p_data_buffer to read the first metadata + void *p_metadata_buffer = NULL; + int buffer_size = ((metadata_hdr_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / + NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + if (ni_posix_memalign(&p_metadata_buffer, sysconf(_SC_PAGESIZE), buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate metadata buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + p_data_buffer = (uint8_t *)p_metadata_buffer; + get_first_metadata = 1; + sequence_change = 0; + } + } + + //Apply read configuration here + retval = ni_config_session_rw(p_ctx, SESSION_READ_CONFIG, 1, + NI_CODEC_HW_ENABLE, 0); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + read_size_bytes = total_bytes_to_read; + ui32LBA = READ_INSTANCE_R(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); + if (read_size_bytes % NI_MEM_PAGE_ALIGNMENT) + { + read_size_bytes = ( (read_size_bytes / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT) + NI_MEM_PAGE_ALIGNMENT; + } + + retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_data_buffer, read_size_bytes, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } else if (get_first_metadata) { + // got first metadata alone + ni_metadata_dec_frame_t *p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_data_buffer); + ni_log2(p_ctx, NI_LOG_DEBUG, "Got first pkt_delay_cnt %u\n", + p_meta->metadata_common.pkt_delay_cnt); + if (p_ctx->pkt_delay_cnt < p_meta->metadata_common.pkt_delay_cnt) + p_ctx->pkt_delay_cnt = p_meta->metadata_common.pkt_delay_cnt; + get_first_metadata = 0; + ni_aligned_free(p_data_buffer); + goto start; + } else + { + // command issued successfully, now exit + ni_metadata_dec_frame_t *p_meta; + p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer + + p_frame->data_len[0] + + p_frame->data_len[1] + + p_frame->data_len[2] + + p_frame->data_len[3]); + + if (buf_info.buf_avail_size != metadata_hdr_size) + { + low_delay_notify = 1; + // shift metadata to end of triple output +#ifdef _WIN32 + p_data_buffer = (uint8_t *)p_frame->p_buffer + + sizeof(niFrameSurface1_t) * NI_MAX_NUM_OF_DECODER_OUTPUTS; + memcpy(p_meta, p_data_buffer, metadata_hdr_size); +#else + memcpy(p_meta, + p_frame->p_buffer + + sizeof(niFrameSurface1_t) * NI_MAX_NUM_OF_DECODER_OUTPUTS, + metadata_hdr_size); +#endif + sei_size = p_meta->sei_size; + niFrameSurface1_t *p_data3 = + (niFrameSurface1_t *)((uint8_t *)p_frame->p_buffer + + p_frame->data_len[0] + + p_frame->data_len[1] + + p_frame->data_len[2]); + + niFrameSurface1_t *p_data3_1 = + (niFrameSurface1_t *)((uint8_t *)p_frame->p_buffer + + sizeof(niFrameSurface1_t)); + niFrameSurface1_t *p_data3_2 = + (niFrameSurface1_t *)((uint8_t *)p_frame->p_buffer + + 2 * sizeof(niFrameSurface1_t)); + // Libxcoder knows the handle so overwrite here + p_data3->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + p_data3_1->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + p_data3_2->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + p_data3->ui16session_ID = p_data3_1->ui16session_ID = + p_data3_2->ui16session_ID = (uint16_t)p_ctx->session_id; + p_data3->src_cpu = p_data3_1->src_cpu = p_data3_2->src_cpu = + (uint8_t)NI_DEVICE_TYPE_DECODER; + + p_data3->output_idx = 0; + p_data3_1->output_idx = 1; + p_data3_2->output_idx = 2; + + ni_log2(p_ctx, NI_LOG_DEBUG, + "p_data3_1:sei_size=%d device_handle=%d == hw_id=%d ses_id=%d\n", + sei_size, p_data3_1->device_handle, p_ctx->hw_id, + p_data3_1->ui16session_ID); + ni_log2(p_ctx, NI_LOG_DEBUG, + "p_data3_1: ui16FrameIdx=%d NodeAddre=0x%x planar=%d bd=%d\n", + p_data3_1->ui16FrameIdx, p_data3_1->ui32nodeAddress, + p_data3_1->encoding_type, p_data3_1->bit_depth); + ni_log2(p_ctx, + NI_LOG_DEBUG, + "p_data3_2:sei_size=%d device_handle=%d == hw_id=%d ses_id=%d\n", + sei_size, p_data3_2->device_handle, p_ctx->hw_id, + p_data3_2->ui16session_ID); + ni_log2(p_ctx, NI_LOG_DEBUG, + "p_data3_2: ui16FrameIdx=%d NodeAddre=0x%x planar=%d bd=%d\n", + p_data3_2->ui16FrameIdx, p_data3_2->ui32nodeAddress, + p_data3_2->encoding_type, p_data3_2->bit_depth); + + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s:sei_size=%d device_handle=%d == hw_id=%d " + "ses_id=%d\n", + __func__, sei_size, p_data3->device_handle, p_ctx->hw_id, + p_data3->ui16session_ID); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: session=0x%x ui16FrameIdx=%u NodeAddress=0x%x, " + "planar=%d bd=%d\n", + __func__, p_ctx->session_id, p_data3->ui16FrameIdx, p_data3->ui32nodeAddress, + p_data3->encoding_type, p_data3->bit_depth); + } else if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rE") >= 0) + { + p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer); + ni_log2(p_ctx, NI_LOG_DEBUG, "Got pkt_delay_cnt %u\n", + p_meta->metadata_common.pkt_delay_cnt); + if (p_ctx->pkt_delay_cnt < p_meta->metadata_common.pkt_delay_cnt) + p_ctx->pkt_delay_cnt = p_meta->metadata_common.pkt_delay_cnt; + } + + total_bytes_to_read = total_bytes_to_read + sei_size; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s decoder read desc success, retval %d " + "total_bytes_to_read include sei %u sei_size %d\n", + __func__, retval, total_bytes_to_read, sei_size); + + if (total_bytes_to_read > NI_MEM_PAGE_ALIGNMENT) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Oversized metadata!\n", __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + } + + //bytes_read_so_far = total_bytes_to_read; + // Note: session status is NOT reset but tracked between send + // and recv to catch and recover from a loop condition + //total_bytes_to_read = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + p_frame->data_len[3] + metadata_hdr_size + sei_size; //since only HW desc + bytes_read_so_far = total_bytes_to_read; + //bytes_read_so_far = p_frame->data_len[0] + p_frame->data_len[1] + p_frame->data_len[2] + p_frame->data_len[3] + metadata_hdr_size + sei_size; //since only HW desc + rx_size = ni_create_frame(p_frame, bytes_read_so_far, &frame_offset, true); + p_ctx->frame_pkt_offset = frame_offset; + if (p_ctx->decoder_low_delay > 0 && buf_info.buf_avail_size == metadata_hdr_size && + p_ctx->enable_low_delay_check) + { + ni_log2(p_ctx, NI_LOG_TRACE, "Low delay mode amd check header if has b frame\n"); + + ni_metadata_dec_frame_t *p_meta = + (ni_metadata_dec_frame_t *)((uint8_t *)p_frame->p_buffer + + p_frame->data_len[0] + + p_frame->data_len[1] + + p_frame->data_len[2]); + if (p_meta->metadata_common.has_b_frame == 1) + { + ni_log2(p_ctx, NI_LOG_ERROR,"Warning: session 0x%x decoder lowDelay mode " + "is cancelled due to has_b_frames, frame_num %u\n", + p_ctx->session_id, p_ctx->frame_num); + p_ctx->decoder_low_delay = 0; + } + } + + if (rx_size > 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): s-state %d first_frame %d\n", __func__, + p_ctx->session_run_state, p_ctx->is_first_frame); + if (ni_timestamp_get_with_threshold( + p_ctx->dts_queue, 0, (int64_t *)&p_frame->dts, + XCODER_FRAME_OFFSET_DIFF_THRES, 0, + p_ctx->buffer_pool) != NI_RETCODE_SUCCESS) + { + if (p_ctx->last_dts != NI_NOPTS_VALUE && !p_ctx->ready_to_close) + { + p_ctx->pic_reorder_delay++; + p_frame->dts = p_ctx->last_dts + p_ctx->last_dts_interval; + ni_log2(p_ctx, NI_LOG_DEBUG, "Padding DTS: %" PRId64 "\n", p_frame->dts); + } else + { + p_frame->dts = NI_NOPTS_VALUE; + } + } + + if (p_ctx->is_first_frame) + { + for (i = 0; i < p_ctx->pic_reorder_delay; i++) + { + if (p_ctx->last_pts == NI_NOPTS_VALUE && + p_ctx->last_dts == NI_NOPTS_VALUE) + { + // If the p_frame->pts is unknown in the very beginning we assume + // p_frame->pts == 0 as well as DTS less than PTS by 1000 * 1/timebase + if (p_frame->pts >= p_frame->dts && + p_frame->pts - p_frame->dts < 1000) + { + break; + } + } + + if (ni_timestamp_get_with_threshold( + p_ctx->dts_queue, 0, (int64_t *)&p_frame->dts, + XCODER_FRAME_OFFSET_DIFF_THRES, + p_ctx->frame_num % 500 == 0, + p_ctx->buffer_pool) != NI_RETCODE_SUCCESS) + { + p_frame->dts = NI_NOPTS_VALUE; + } + } + // Reset for DTS padding counting + p_ctx->pic_reorder_delay = 0; + } + if (p_ctx->codec_format == NI_CODEC_FORMAT_JPEG)//fw won't save frameoffset when decoding jpeg. + { + if (p_ctx->is_first_frame) + { + p_ctx->is_first_frame = 0; + } + p_frame->pts = p_ctx->pts_offsets[p_ctx->frame_num % NI_FIFO_SZ]; + p_frame->flags = p_ctx->flags_array[p_ctx->frame_num % NI_FIFO_SZ]; + p_frame->pkt_pos = p_ctx->pkt_pos[p_ctx->frame_num % NI_FIFO_SZ]; + ni_log2(p_ctx, NI_LOG_DEBUG, "p_frame->pts = %u, frame_num = %d, p_frame->dts = %u\n", + p_frame->pts, p_ctx->frame_num, p_frame->dts); + } + else if (p_ctx->is_dec_pkt_512_aligned) + { + if (p_ctx->is_first_frame) + { + p_ctx->is_first_frame = 0; + p_frame->pkt_pos = p_ctx->pkt_pos[0]; + + if (p_frame->dts == NI_NOPTS_VALUE) + { + p_frame->pts = NI_NOPTS_VALUE; + } + // if not a bitstream retrieve the pts of the frame corresponding to the first YUV output + else if((p_ctx->pts_offsets[0] != NI_NOPTS_VALUE) && (p_ctx->pkt_index != -1)) + { + ni_metadata_dec_frame_t* p_metadata = + (ni_metadata_dec_frame_t*)((uint8_t*)p_frame->p_buffer + + p_frame->data_len[0] + p_frame->data_len[1] + + p_frame->data_len[2] + p_frame->data_len[3]); + int num_fw_pkts = + (int)p_metadata->metadata_common.ui64_data.frame_offset / 512; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: num_fw_pkts %d frame_offset %" PRIu64 "\n", + __func__, num_fw_pkts, + p_metadata->metadata_common.ui64_data.frame_offset); + int idx = 0; + uint64_t cumul = p_ctx->pkt_offsets_index[0]; + bool bFound = (num_fw_pkts >= cumul); + while (cumul < num_fw_pkts) // look for pts index + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: cumul %" PRIu64 "\n", __func__, cumul); + if (idx == NI_MAX_DEC_REJECT) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "Invalid index computation > " + "NI_MAX_DEC_REJECT!\n"); + break; + } else + { + idx ++; + cumul += p_ctx->pkt_offsets_index[idx]; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: idx %d pkt_offsets_index[idx] %" PRIu64 "\n", + __func__, idx, p_ctx->pkt_offsets_index[idx]); + } + } + //if ((idx != NI_MAX_DEC_REJECT) && (idx >= 0)) + if ((idx != NI_MAX_DEC_REJECT) && bFound) + { + p_frame->pts = p_ctx->pts_offsets[idx]; + p_frame->flags = p_ctx->flags_array[idx]; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: (first frame) idx %d last_dts %" PRId64 "" + " dts %" PRId64 " last_pts %" PRId64 " pts %" PRId64 "\n", + __func__, idx, p_ctx->last_dts, p_frame->dts, + p_ctx->last_pts, p_frame->pts); + } else if (idx != NI_MAX_DEC_REJECT && + p_ctx->session_run_state == SESSION_RUN_STATE_RESETTING) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): session %u recovering and " + "adjusting ts.\n", + __func__, p_ctx->session_id); + p_frame->pts = p_ctx->pts_offsets[idx]; + p_frame->flags = p_ctx->flags_array[idx]; + p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; + } + else // use pts = 0 as offset + { + p_frame->pts = 0; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: (zero default) dts %" PRId64 " pts " + "%" PRId64 "\n", + __func__, p_frame->dts, p_frame->pts); + } + } + else + { + p_frame->pts = 0; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: (not bitstream) dts %" PRId64 " pts " + "%" PRId64 "\n", + __func__, p_frame->dts, p_frame->pts); + } + } + else + { + int64_t pts_delta = p_frame->dts - p_ctx->last_dts; + p_frame->pts = p_ctx->last_pts + pts_delta; + p_frame->pkt_pos = p_ctx->last_pkt_pos + (frame_offset - p_ctx->last_frame_offset); + + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: (!is_first_frame idx) last_dts %" PRId64 "" + " dts %" PRId64 " pts_delta %" PRId64 " last_pts " + "%" PRId64 " pts %" PRId64 "\n", + __func__, p_ctx->last_dts, p_frame->dts, pts_delta, + p_ctx->last_pts, p_frame->pts); + } + } + else + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: frame_offset %" PRIu64 "\n", __func__, + frame_offset); + if (p_ctx->is_first_frame) + { + p_ctx->is_first_frame = 0; + } + // search for the pkt_offsets of received frame according to frame_offset. + // here we get the index(i) which promises (p_ctx->pkt_offsets_index_min[i] <= frame_offset && p_ctx->pkt_offsets_index[i] > frame_offset) + // i = -1 if not found + i = rotated_array_binary_search(p_ctx->pkt_offsets_index_min, + p_ctx->pkt_offsets_index, NI_FIFO_SZ, + frame_offset); + if (i >= 0) + { + p_frame->pts = p_ctx->pts_offsets[i]; + p_frame->flags = p_ctx->flags_array[i]; + p_frame->pkt_pos = p_ctx->pkt_pos[i]; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: (found pts) dts %" PRId64 " pts " + "%" PRId64 " frame_offset %" PRIu64 " i %d " + "pkt_offsets_index_min %" PRIu64 " " + "pkt_offsets_index %" PRIu64 " pkt_pos %" PRIu64 "\n", + __func__, p_frame->dts, p_frame->pts, frame_offset, i, + p_ctx->pkt_offsets_index_min[i], + p_ctx->pkt_offsets_index[i], + p_ctx->pkt_pos[i]); + + p_frame->p_custom_sei_set = p_ctx->pkt_custom_sei_set[i]; + p_ctx->pkt_custom_sei_set[i] = NULL; + } else + { + //backup solution pts + if (p_param->dec_input_params.skip_pts_guess && p_ctx->last_pts != NI_NOPTS_VALUE) + { + // if skip guess_correct_pts, use pts interval to get the correct pts + p_frame->pts = p_ctx->last_pts + (p_ctx->last_pts_interval > 0 ? p_ctx->last_pts_interval : 1); + } + else + { + p_frame->pts = p_ctx->last_pts + (p_frame->dts - p_ctx->last_dts); + } + p_frame->pkt_pos = p_ctx->last_pkt_pos + (frame_offset - p_ctx->last_frame_offset); + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: Frame pts %" PRId64 " not found for offset " + "%" PRIu64 "\n", p_frame->pts, frame_offset); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s: (not found use default) dts %" PRId64 " pts %" PRId64 + "\n", + __func__, p_frame->dts, p_frame->pts); + } + } + + p_frame->orignal_pts = p_frame->pts; + p_ctx->last_pkt_pos = p_frame->pkt_pos; + p_ctx->last_frame_offset = frame_offset; + if (!p_param->dec_input_params.skip_pts_guess) + p_frame->pts = guess_correct_pts(p_ctx, p_frame->pts, p_frame->dts); + if (p_frame->pts != NI_NOPTS_VALUE && p_ctx->last_pts != NI_NOPTS_VALUE) + p_ctx->last_pts_interval = p_frame->pts - p_ctx->last_pts; + p_ctx->last_pts = p_frame->pts; + if (p_frame->dts != NI_NOPTS_VALUE && p_ctx->last_dts != NI_NOPTS_VALUE) + p_ctx->last_dts_interval = p_frame->dts - p_ctx->last_dts; + p_ctx->last_dts = p_frame->dts; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: (best_effort_timestamp) pts %" PRId64 "\n", + __func__, p_frame->pts); + p_ctx->frame_num++; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): received data: [0x%08x]\n", __func__, rx_size); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_frame->start_of_stream=%u, " + "p_frame->end_of_stream=%u, p_frame->video_width=%u, " + "p_frame->video_height=%u\n", + __func__, p_frame->start_of_stream, p_frame->end_of_stream, + p_frame->video_width, p_frame->video_height); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): p_frame->data_len[0/1/2]=%u/%u/%u\n", __func__, + p_frame->data_len[0], p_frame->data_len[1], p_frame->data_len[2]); + + if (p_ctx->frame_num % 500 == 0) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Decoder pts queue size = %d dts queue size = %d\n\n", + p_ctx->pts_table->list.count, p_ctx->dts_queue->list.count); + // scan and clean up + ni_timestamp_scan_cleanup(p_ctx->pts_table, p_ctx->dts_queue, + p_ctx->buffer_pool); + } + +#ifdef MEASURE_LATENCY + if ((p_frame->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) + { + uint64_t abs_time_ns = ni_gettime_ns(); + ni_lat_meas_q_t *q = (ni_lat_meas_q_t *)p_ctx->frame_time_q; + ni_log2(p_ctx, NI_LOG_INFO, "DTS:%" PRId64 ",DELTA:%" PRId64 ",dLAT:%" PRIu64 ";\n", + p_frame->dts, abs_time_ns - q->last_benchmark_time, + ni_lat_meas_q_check_latency(q, abs_time_ns, p_frame->dts)); + q->last_benchmark_time = abs_time_ns; + } +#endif + +END: + + ni_pthread_mutex_unlock(&p_ctx->mutex); + + if (get_first_metadata && p_data_buffer) + ni_aligned_free(p_data_buffer); + if (sequence_change && p_ctx->frame_num) + { + if (p_ctx->actual_video_width == p_frame->video_width && + p_ctx->active_video_height == p_frame->video_height) + { + p_ctx->pixel_format_changed = 1; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): format changed\n", __func__); + } + } + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): bad exit, retval = %d\n", __func__, retval); + if (retval == NI_RETCODE_ERROR_VPU_RECOVERY) + { + low_delay_signal(p_ctx); + } + + return retval; + } else + { + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit, rx_size = %d\n", __func__, rx_size); + if (low_delay_notify) + { + low_delay_signal(p_ctx); + } + + return rx_size; + } +} + +/*!****************************************************************************** +* \brief Retrieve a YUV p_frame from decoder +* +* \param +* +* \return +*******************************************************************************/ +int ni_hwdownload_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame, niFrameSurface1_t* hwdesc) +{ + int retval = NI_RETCODE_SUCCESS; + int rx_size = 0; + uint64_t frame_offset = 0; + uint8_t *p_data_buffer; + int metadata_hdr_size = NI_FW_META_DATA_SZ - + NI_MAX_NUM_OF_DECODER_OUTPUTS * sizeof(niFrameSurface1_t); + uint32_t total_bytes_to_read = 0; + uint32_t read_size_bytes = 0; + uint32_t ui32LBA = 0; + + //ni_log2(p_ctx, NI_LOG_DEBUG, "hwcontext.c:ni_hwdl_frame() hwdesc %d %d %d\n", + // hwdesc->ui16FrameIdx, + // hwdesc->i8InstID, + // hwdesc->ui16session_ID); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if ((!p_ctx) || (!p_frame)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + p_data_buffer = (uint8_t *)p_frame->p_buffer; + + if (!p_frame->p_data[0] || !p_data_buffer) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): No receive buffer allocated.\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (0 == p_frame->data_len[0]) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): p_frame->data_len[0] = 0!.\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (hwdesc->encoding_type == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) + { + p_frame->data_len[2] = 0; + } else if (hwdesc->encoding_type == NI_PIXEL_PLANAR_FORMAT_TILED4X4) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): NI_PIXEL_PLANAR_FORMAT_TILED4X4 not supported in download.\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + total_bytes_to_read = p_frame->data_len[0] + p_frame->data_len[1] + + p_frame->data_len[2];// +metadata_hdr_size; + unsigned int bytes_read_so_far = 0; + uint32_t output_chunk_offset = hwdesc->ui32nodeAddress / FRAME_CHUNK_INDEX_SIZE; //for reading output1 or output2 + uint32_t output_minor_offset = hwdesc->ui32nodeAddress - output_chunk_offset * FRAME_CHUNK_INDEX_SIZE; + ni_log2(p_ctx, NI_LOG_DEBUG, "Total bytes to download %u, start offset = %u, chunkOffset " + "%u, minorOffset %u\n", + total_bytes_to_read, hwdesc->ui32nodeAddress, + output_chunk_offset, output_minor_offset); + + ni_log2(p_ctx, NI_LOG_DEBUG, "total_bytes_to_read %u max_nvme_io_size %u ylen %u cr len " + "%u cb len %u hdr %d\n", + total_bytes_to_read, p_ctx->max_nvme_io_size, + p_frame->data_len[0], p_frame->data_len[1], + p_frame->data_len[2], metadata_hdr_size); + + //Apply read configuration here + retval = + ni_config_session_rw(p_ctx, SESSION_READ_CONFIG, 1, + (output_minor_offset << NI_CODEC_HW_PAYLOAD_OFFSET) | + NI_CODEC_HW_ENABLE | NI_CODEC_HW_DOWNLOAD, + hwdesc->ui16FrameIdx); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, hwdesc->src_cpu, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Config HW download read desc success, retval %d total_bytes_to_read %u\n", + retval, total_bytes_to_read); + } + + read_size_bytes = total_bytes_to_read; + ui32LBA = READ_INSTANCE_R(p_ctx->session_id, hwdesc->src_cpu); + ui32LBA += output_chunk_offset; + if (read_size_bytes % NI_MEM_PAGE_ALIGNMENT) + { + read_size_bytes = ( (read_size_bytes / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT) + NI_MEM_PAGE_ALIGNMENT; + } + + retval = ni_nvme_send_read_cmd( + (ni_device_handle_t)(int64_t)hwdesc->device_handle, + NI_INVALID_DEVICE_HANDLE, p_data_buffer, read_size_bytes, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, hwdesc->src_cpu, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "HW download read desc success, retval %d total_bytes_to_read %u\n", + retval, total_bytes_to_read); + } + + //Unset applied read configuration here + retval = ni_config_session_rw(p_ctx, SESSION_READ_CONFIG, 0, 0, 0); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, hwdesc->src_cpu, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "Unconfig HW download read desc success, retval %d total_bytes_to_read %u\n", + retval, total_bytes_to_read); + } + + bytes_read_so_far = total_bytes_to_read; + // Note: session status is NOT reset but tracked between send + // and recv to catch and recover from a loop condition + + if (p_ctx->is_auto_dl) + rx_size = (int)bytes_read_so_far; + else + { + rx_size = + ni_create_frame(p_frame, bytes_read_so_far, &frame_offset, false); + p_ctx->frame_pkt_offset = frame_offset; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): received data: [0x%08x]\n", + __func__, rx_size); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_frame->start_of_stream=%u, " + "p_frame->end_of_stream=%u, p_frame->video_width=%u, " + "p_frame->video_height=%u\n", + __func__, p_frame->start_of_stream, p_frame->end_of_stream, + p_frame->video_width, p_frame->video_height); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_ctx->frame_num %" PRIu64 ", " + "p_frame->data_len[0/1/2]=%u/%u/%u\n", + __func__, p_ctx->frame_num, p_frame->data_len[0], p_frame->data_len[1], + p_frame->data_len[2]); + + //if (decq_count % 500 == 0) + //{ + // ni_log2(p_ctx, NI_LOG_DEBUG, "Decoder pts queue size = %d dts queue size = %d\n\n", + // p_ctx->pts_table->list.count, p_ctx->dts_queue)->list.count); + // // scan and clean up + // ni_timestamp_scan_cleanup(p_ctx->pts_table, p_ctx->dts_queue, p_ctx->buffer_pool); + //} + +END: + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): bad exit, retval = %d\n", __func__, retval); + return retval; + } else + { + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit, rx_size = %d\n", __func__, rx_size); + return rx_size; + } +} + +ni_retcode_t ni_hwframe_clone(ni_session_context_t *p_ctx, + ni_frameclone_desc_t *p_frameclone_desc) +{ + int retval = NI_RETCODE_SUCCESS; + uint8_t *p_data = NULL; + uint32_t dataLen; + uint32_t ui32LBA = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + dataLen = (sizeof(ni_frameclone_desc_t) + NI_MEM_PAGE_ALIGNMENT - 1) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_data, 0, dataLen); + memcpy(p_data, p_frameclone_desc, sizeof(ni_frameclone_desc_t)); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): ui16DstIdx %u, ui16SrcIdx %u, size %u, offset %u\n", __func__, + p_frameclone_desc->ui16DstIdx, p_frameclone_desc->ui16SrcIdx, + p_frameclone_desc->ui32Size, p_frameclone_desc->ui32Offset); + + ui32LBA = CONFIG_SESSION_FRAME_COPY_W(p_ctx->session_id); + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, NI_INVALID_EVENT_HANDLE, + p_data, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), + OPT_1); + CHECK_VPU_RECOVERY(retval); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed!\n", + __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + +END: + ni_aligned_free(p_data); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): bad exit, retval = %d\n", __func__, retval); + } + return retval; +} + +/*!****************************************************************************** +* \brief Close an xcoder upload instance +* +* \param p_ctx pointer to uploader session context +* +* \return NI_RETCODE_SUCCESS +*******************************************************************************/ +ni_retcode_t ni_uploader_session_close(ni_session_context_t* p_ctx) +{ +#ifndef _WIN32 + if (p_ctx->isP2P) + { + if (p_ctx->netint_fd) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: close driver fd %d\n", __func__, + p_ctx->netint_fd); + close(p_ctx->netint_fd); + } + } +#endif + return NI_RETCODE_SUCCESS; +} + +/*!****************************************************************************** +* \brief Send a p_config command to configure uploading parameters. +* +* \param ni_session_context_t p_ctx - xcoder Context +* \param[in] pool_size pool size to create +* \param[in] pool 0 = normal pool, 1 = P2P pool +* +* \return - NI_RETCODE_SUCCESS on success, +* NI_RETCODE_ERROR_INVALID_SESSION +* NI_RETCODE_ERROR_NVME_CMD_FAILED on failure +*******************************************************************************/ +ni_retcode_t ni_config_instance_set_uploader_params(ni_session_context_t *p_ctx, + uint32_t pool_size, + uint32_t pool) +{ + void* p_uploader_config = NULL; + ni_uploader_config_t* p_cfg = NULL; + uint32_t buffer_size = sizeof(ni_encoder_config_t); + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + if (ni_posix_memalign(&p_uploader_config, sysconf(_SC_PAGESIZE), + buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_uploader_config, 0, buffer_size);// + + p_cfg = (ni_uploader_config_t*)p_uploader_config; + p_cfg->ui16picWidth = p_ctx->active_video_width; + p_cfg->ui16picHeight = p_ctx->active_video_height; + p_cfg->ui8poolSize = pool_size; + p_cfg->ui8PixelFormat = p_ctx->pixel_format; + p_cfg->ui8Pool = pool; + p_cfg->ui32lumaLinesize = 0; // cannot support config linesize yet because ni_frames_init is called when filter graph is created (no frame linesize info) + p_cfg->ui32chromaLinesize = 0; + bool isrgb = ((NI_PIX_FMT_RGBA == p_cfg->ui8PixelFormat) || (NI_PIX_FMT_BGRA == p_cfg->ui8PixelFormat) || + (NI_PIX_FMT_ARGB == p_cfg->ui8PixelFormat) || (NI_PIX_FMT_ABGR == p_cfg->ui8PixelFormat) || + (NI_PIX_FMT_BGR0 == p_cfg->ui8PixelFormat)); + if(p_cfg->ui16picWidth > NI_MAX_RESOLUTION_WIDTH || p_cfg->ui16picHeight > NI_MAX_RESOLUTION_HEIGHT || + p_cfg->ui16picWidth < NI_MIN_RESOLUTION_WIDTH_SCALER || p_cfg->ui16picHeight < NI_MIN_RESOLUTION_HEIGHT_SCALER || + ((p_cfg->ui16picWidth > NI_MAX_RESOLUTION_RGBA_WIDTH || p_cfg->ui16picHeight > NI_MAX_RESOLUTION_RGBA_HEIGHT) && isrgb)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Resolution %d x %d not supported for %d format!\n", p_cfg->ui16picWidth, p_cfg->ui16picHeight, p_cfg->ui8PixelFormat); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "ni_config_instance_set_uploader_params():%d x %d x Format %d with %d framepool\n", + p_cfg->ui16picWidth, p_cfg->ui16picHeight, p_cfg->ui8PixelFormat, p_cfg->ui8poolSize); + + //configure the session here + ui32LBA = + CONFIG_INSTANCE_SetEncPara_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_uploader_config, buffer_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + //Close the session since we can't configure it + retval = ni_encoder_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_uploader_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + } + + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + else + { + p_ctx->pool_type = p_cfg->ui8Pool ? NI_POOL_TYPE_P2P : NI_POOL_TYPE_NORMAL; + } + +END: + + ni_aligned_free(p_uploader_config); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} + +/*!****************************************************************************** +* \brief Send a p_config command to configure decoding parameters. +* +* \param ni_session_context_t p_ctx - xcoder Context +* \param uint32_t max_pkt_size - overwrite maximum packet size if nonzero +* +* \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, NI_RETCODE_ERROR_NVME_CMD_FAILED on failure +*******************************************************************************/ +ni_retcode_t ni_config_instance_set_decoder_params(ni_session_context_t* p_ctx, uint32_t max_pkt_size) +{ + void* p_decoder_config = NULL; + uint32_t buffer_size = sizeof(ni_decoder_config_t); + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + if (ni_cmp_fw_api_ver((char*)&p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6rT") < 0) + { + ni_log2(p_ctx, NI_LOG_INFO, "%s() FW rev %s < 6rT-- load balancing might be affected\n", __func__, + (char*)&p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX]); + } + + buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; + if (ni_posix_memalign(&p_decoder_config, sysconf(_SC_PAGESIZE), buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate p_decoder_config buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_decoder_config, 0, buffer_size); + + ni_set_custom_dec_template(p_ctx, p_decoder_config, p_ctx->p_session_config, max_pkt_size); + retval = ni_validate_custom_dec_template(p_ctx->p_session_config, p_ctx, p_decoder_config, p_ctx->param_err_msg, sizeof(p_ctx->param_err_msg)); + if (NI_RETCODE_PARAM_WARN == retval) + { + ni_log2(p_ctx, NI_LOG_INFO, "WARNING: %s . %s\n", __func__, p_ctx->param_err_msg); + fflush(stdout); + } + else if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s failed. %s\n", __func__, + p_ctx->param_err_msg); + fflush(stdout); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + // configure the session here + ui32LBA = CONFIG_INSTANCE_SetDecPara_W(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); + + //Flip the bytes!! + //p_cfg = (ni_decoder_config_t*)p_decoder_config; + //p_cfg->i32picWidth = ni_htonl(p_cfg->i32picWidth); + //p_cfg->i32picHeight = ni_htonl(p_cfg->i32picHeight); + //p_cfg->i32meBlkMode = ni_htonl(p_cfg->i32meBlkMode); + //p_cfg->i32frameRateInfo = ni_htonl(p_cfg->i32frameRateInfo); + //p_cfg->i32vbvBufferSize = ni_htonl(p_cfg->i32vbvBufferSize); + //p_cfg->i32userQpMax = ni_htonl(p_cfg->i32userQpMax); + //p_cfg->i32maxIntraSize = ni_htonl(p_cfg->i32maxIntraSize); + //p_cfg->i32userMaxDeltaQp = ni_htonl(p_cfg->i32userMaxDeltaQp); + //p_cfg->i32userMinDeltaQp = ni_htonl(p_cfg->i32userMinDeltaQp); + //p_cfg->i32userQpMin = ni_htonl(p_cfg->i32userQpMin); + //p_cfg->i32bitRate = ni_htonl(p_cfg->i32bitRate); + //p_cfg->i32bitRateBL = ni_htonl(p_cfg->i32bitRateBL); + //p_cfg->i32srcBitDepth = ni_htonl(p_cfg->i32srcBitDepth); + //p_cfg->hdrEnableVUI = ni_htonl(p_cfg->hdrEnableVUI); + //p_cfg->ui32VuiDataSizeBits = ni_htonl(p_cfg->ui32VuiDataSizeBits); + //p_cfg->ui32VuiDataSizeBytes = ni_htonl(p_cfg->ui32VuiDataSizeBytes); + //p_cfg->i32hwframes = ni_htonl(p_cfg->i32hwframes); + // flip the 16 bytes of the reserved field using 32 bits pointers + //for (i = 0; i < (16 >> 2); i++) + //{ + // ((uint32_t*)p_cfg->ui8Reserved)[i] = ni_htonl(((uint32_t*)p_cfg->ui8Reserved)[i]); + //} + //// flip the NI_MAX_VUI_SIZE bytes of the VUI field using 32 bits pointers + //for (i = 0; i < (NI_MAX_VUI_SIZE >> 2); i++) // apply on 32 bits + //{ + // ((uint32_t*)p_cfg->ui8VuiRbsp)[i] = ni_htonl(((uint32_t*)p_cfg->ui8VuiRbsp)[i]); + //} + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: ui32LBA = 0x%x\n", __func__, ui32LBA); + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_decoder_config, buffer_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + //Close the session since we can't configure it + retval = ni_decoder_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: ni_encoder_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + } + + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + +END: + + ni_aligned_free(p_decoder_config); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + return retval; +} + +/*!****************************************************************************** + * \brief read a hardware descriptor from a scaler session + * + * \param[in] p_ctx pointer to session context + * \param[out] p_frame pointer to frame to write hw descriptor + * + * \return NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_FAILURE + *******************************************************************************/ +ni_retcode_t ni_scaler_session_read_hwdesc( + ni_session_context_t *p_ctx, + ni_frame_t *p_frame) +{ + ni_retcode_t retval; + ni_instance_buf_info_t sInstanceBuf = {0}; + niFrameSurface1_t *pFrameSurface; + int query_retry = 0; + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + return NI_RETCODE_ERROR_INVALID_SESSION; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + + for (;;) + { + query_retry++; + + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_UPLOAD, + NI_DEVICE_TYPE_SCALER, &sInstanceBuf); + + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_3); + + if (retval == NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE) + { + if (query_retry >= 1000) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning hwdesc read fail rc %d\n", retval); + LRETURN; + } + } + else if (retval != NI_RETCODE_SUCCESS) + { + LRETURN; + } + else + { + pFrameSurface = (niFrameSurface1_t *) p_frame->p_data[3]; + pFrameSurface->ui16FrameIdx = sInstanceBuf.hw_inst_ind.frame_index; + pFrameSurface->ui16session_ID = p_ctx->session_id; + pFrameSurface->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + pFrameSurface->src_cpu = (uint8_t) NI_DEVICE_TYPE_SCALER; + pFrameSurface->output_idx = 0; + + /* A frame index of zero is invalid, the memory acquisition failed */ + if (pFrameSurface->ui16FrameIdx == 0) + { + if (query_retry >= 1000) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Warning: 2D could not acquire frame\n"); + retval = NI_RETCODE_FAILURE; + LRETURN; + } + ni_usleep(100); + continue; + } + + ni_log2(p_ctx, NI_LOG_DEBUG, + "Session=0x%x: %s got FrameIndex=%u\n", + p_ctx->session_id, + __func__, + pFrameSurface->ui16FrameIdx); + + LRETURN; + } + } + +END: + + ni_pthread_mutex_unlock(&p_ctx->mutex); + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s Warning scalar read hwdesc fail rc %d or ind !\n", + __func__, retval); + retval = NI_RETCODE_FAILURE; + } + + return retval; +} + +/*!****************************************************************************** +* \brief Grab bitdepth factor from NI_PIX_FMT +* +* \param[in] pix_fmt ni_pix_fmt_t +* +* \return 1 or 2 for success, -1 for error +*******************************************************************************/ +int ni_get_bitdepth_factor_from_pixfmt(int pix_fmt) +{ + switch (pix_fmt) + { + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_8_TILED4X4: + return 1; + case NI_PIX_FMT_YUV420P10LE: + case NI_PIX_FMT_P010LE: + case NI_PIX_FMT_10_TILED4X4: + return 2; + default: + { + ni_log(NI_LOG_ERROR, "ERROR: %s() non applicable format %d\n", __func__, + pix_fmt); + break; + } + } + return -1; +} + +/*!****************************************************************************** +* \brief Grab planar info from NI_PIX_FMT +* +* \param[in] pix_fmt ni_pix_fmt_t +* +* \return 0 or 1 for success, -1 for error +*******************************************************************************/ +int ni_get_planar_from_pixfmt(int pix_fmt) +{ + switch (pix_fmt) + { + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_YUV420P10LE: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + return 1; + break; + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + return 0; + break; + default: + { + ni_log(NI_LOG_ERROR, "ERROR: %s() non applicable format %d\n", __func__, + pix_fmt); + break; + } + } + return -1; +} + +#ifndef _WIN32 +/*!***************************************************************************** + * \brief Get an address offset from a hw descriptor + * + * \param[in] p_ctx ni_session_context_t to be referenced + * \param[in] hwdesc Pointer to caller allocated niFrameSurface1_t + * \param[out] p_offset Value of offset + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + ******************************************************************************/ +ni_retcode_t ni_get_memory_offset(ni_session_context_t *p_ctx, const niFrameSurface1_t *hwdesc, + uint32_t *p_offset) +{ + if (!hwdesc) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed null parameter\n", __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (hwdesc->ui16FrameIdx <= NI_GET_MIN_HWDESC_P2P_BUF_ID(p_ctx->ddr_config) || + hwdesc->ui16FrameIdx > NI_GET_MAX_HWDESC_P2P_BUF_ID(p_ctx->ddr_config)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() pass invalid data. " + "FrameIdx %d OOR (%d,%d]. DDR config %d \n", __func__, hwdesc->ui16FrameIdx, + NI_GET_MIN_HWDESC_P2P_BUF_ID(p_ctx->ddr_config), NI_GET_MAX_HWDESC_P2P_BUF_ID(p_ctx->ddr_config), + p_ctx->ddr_config); + return NI_RETCODE_INVALID_PARAM; + } + + *p_offset = (hwdesc->ui16FrameIdx - NI_GET_MIN_HWDESC_P2P_BUF_ID(p_ctx->ddr_config)) * + NI_HWDESC_UNIFIED_MEMBIN_SIZE; + + return NI_RETCODE_SUCCESS; +} +#endif + +/* AI functions */ +ni_retcode_t ni_config_instance_network_binary(ni_session_context_t *p_ctx, + void *nb_data, uint32_t nb_size) +{ + void *p_ai_config = NULL; + void *p_nb_data = NULL; + uint32_t buffer_size; + // uint8_t *p_data; + // uint32_t transferred, this_size; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + uint32_t config_size; + void *p_buffer = NULL; + uint32_t dataLen; + ni_instance_buf_info_t buf_info = {0}; + int retry_count = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } + + ni_pthread_mutex_lock(&p_ctx->mutex); + + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + + config_size = (sizeof(ni_ai_config_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_ai_config, sysconf(_SC_PAGESIZE), config_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot allocate ai config buffer.\n"); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + + ((ni_ai_config_t *)p_ai_config)->ui32NetworkBinarySize = nb_size; + ni_calculate_sha256(nb_data, nb_size, + ((ni_ai_config_t *)p_ai_config)->ui8Sha256); + + buffer_size = + (nb_size + (NI_MEM_PAGE_ALIGNMENT - 1)) & ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_nb_data, sysconf(_SC_PAGESIZE), buffer_size)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot allocate encConf buffer.\n"); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + + memcpy(p_nb_data, nb_data, nb_size); + + /* configure network binary size to be written */ + ui32LBA = CONFIG_INSTANCE_SetAiPara_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): LBA 0x%x, nb_size %u\n", __func__, ui32LBA, + nb_size); + + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_ai_config, config_size, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + //Close the session since we can't configure it + retval = ni_ai_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_ai_session_close failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, + p_ctx->session_id); + } + + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } - if (p_ctx->is_dec_pkt_512_aligned) + dataLen = (sizeof(ni_network_layer_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - if (p_ctx->is_first_frame) - { - p_ctx->is_first_frame = 0; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot allocate buffer.\n"); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } - if (p_frame->dts == NI_NOPTS_VALUE) + for (;;) + { + /* test if the model is already exist. if not, then continue to write binary data */ + memset(p_buffer, 0, dataLen); + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6J") >= 0) { - p_frame->pts = NI_NOPTS_VALUE; + ui32LBA = QUERY_INSTANCE_NL_SIZE_V2_R(p_ctx->session_id, + NI_DEVICE_TYPE_AI); + } else + { + ui32LBA = + QUERY_INSTANCE_NL_SIZE_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); } - // if not a bitstream retrieve the pts of the frame corresponding to the first YUV output - else if((p_ctx->pts_offsets[0] != NI_NOPTS_VALUE) && (p_ctx->pkt_index != -1)) + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (retval != NI_RETCODE_SUCCESS) { - ni_metadata_dec_frame_t* p_metadata = - (ni_metadata_dec_frame_t*)((uint8_t*)p_frame->p_buffer + - p_frame->data_len[0] + p_frame->data_len[1] + - p_frame->data_len[2] + p_frame->data_len[3]); - int num_fw_pkts = - (int)p_metadata->metadata_common.ui64_data.frame_offset / 512; - ni_log(NI_LOG_DEBUG, "%s: num_fw_pkts %d frame_offset %" PRIu64 "\n", - __func__, num_fw_pkts, - p_metadata->metadata_common.ui64_data.frame_offset); - int idx = 0; - uint64_t cumul = p_ctx->pkt_offsets_index[0]; - bool bFound = (num_fw_pkts >= cumul); - while (cumul < num_fw_pkts) // look for pts index - { - ni_log(NI_LOG_DEBUG, "%s: cumul %" PRIu64 "\n", __func__, cumul); - if (idx == NI_MAX_DEC_REJECT) - { - ni_log(NI_LOG_ERROR, - "Invalid index computation > " - "NI_MAX_DEC_REJECT!\n"); - break; - } else - { - idx ++; - cumul += p_ctx->pkt_offsets_index[idx]; - ni_log(NI_LOG_DEBUG, - "%s: idx %d pkt_offsets_index[idx] %" PRIu64 "\n", - __func__, idx, p_ctx->pkt_offsets_index[idx]); - } - } - //if ((idx != NI_MAX_DEC_REJECT) && (idx >= 0)) - if ((idx != NI_MAX_DEC_REJECT) && bFound) - { - p_frame->pts = p_ctx->pts_offsets[idx]; - p_frame->flags = p_ctx->flags_array[idx]; - p_ctx->last_pts = p_frame->pts; - p_ctx->last_dts = p_frame->dts; - ni_log(NI_LOG_DEBUG, - "%s: (first frame) idx %d last_dts %" PRId64 "" - " dts %" PRId64 " last_pts %" PRId64 " pts %" PRId64 "\n", - __func__, idx, p_ctx->last_dts, p_frame->dts, - p_ctx->last_pts, p_frame->pts); - } else if (idx != NI_MAX_DEC_REJECT && - p_ctx->session_run_state == SESSION_RUN_STATE_RESETTING) - { - ni_log(NI_LOG_DEBUG, - "xcoder_dec_receive(): session %u recovering and " - "adjusting ts.\n", - __func__, p_ctx->session_id); - p_frame->pts = p_ctx->pts_offsets[idx]; - p_frame->flags = p_ctx->flags_array[idx]; - p_ctx->last_pts = p_frame->pts; - p_ctx->last_dts = p_frame->dts; - p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; - } - else // use pts = 0 as offset - { - p_frame->pts = 0; - ni_log(NI_LOG_DEBUG, - "%s: (zero default) dts %" PRId64 " pts " - "%" PRId64 "\n", - __func__, p_frame->dts, p_frame->pts); - } + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; } - else + if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size > 0) { - p_frame->pts = 0; - ni_log(NI_LOG_DEBUG, - "%s: (not bitstream) dts %" PRId64 " pts " - "%" PRId64 "\n", - __func__, p_frame->dts, p_frame->pts); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): network binary registered\n", __func__); + LRETURN; } - } - else - { - int64_t pts_delta = p_frame->dts - p_ctx->last_dts; - p_frame->pts = p_ctx->last_pts + pts_delta; - ni_log(NI_LOG_DEBUG, - "%s: (!is_first_frame idx) last_dts %" PRId64 "" - " dts %" PRId64 " pts_delta %" PRId64 " last_pts " - "%" PRId64 " pts %" PRId64 "\n", - __func__, p_ctx->last_dts, p_frame->dts, pts_delta, - p_ctx->last_pts, p_frame->pts); - } - } - else - { - ni_log(NI_LOG_DEBUG, "%s: frame_offset %" PRIu64 "\n", __func__, - frame_offset); - if (p_ctx->is_first_frame) + /* if this model is not ready, try to require nbuffer to write */ + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, + NI_DEVICE_TYPE_AI, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (retval != NI_RETCODE_SUCCESS) { - p_ctx->is_first_frame = 0; + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): Query Write buffer Failed\n", __func__); + LRETURN; } - // search for the pkt_offsets of received frame according to frame_offset. - // here we get the index(i) which promises (p_ctx->pkt_offsets_index_min[i] <= frame_offset && p_ctx->pkt_offsets_index[i] > frame_offset) - // i = -1 if not found - i = rotated_array_binary_search(p_ctx->pkt_offsets_index_min, - p_ctx->pkt_offsets_index, NI_FIFO_SZ, - frame_offset); - if (i >= 0) + if (buf_info.buf_avail_size < nb_size) { - p_frame->pts = p_ctx->pts_offsets[i]; - p_frame->flags = p_ctx->flags_array[i]; - p_ctx->last_pts = p_frame->pts; - p_ctx->last_dts = p_frame->dts; - ni_log(NI_LOG_DEBUG, - "%s: (found pts) dts %" PRId64 " pts " - "%" PRId64 " frame_offset %" PRIu64 " i %d " - "pkt_offsets_index_min %" PRIu64 " " - "pkt_offsets_index %" PRIu64 "\n", - __func__, p_frame->dts, p_frame->pts, frame_offset, i, - p_ctx->pkt_offsets_index_min[i], - p_ctx->pkt_offsets_index[i]); - - p_frame->p_custom_sei_set = p_ctx->pkt_custom_sei_set[i]; - p_ctx->pkt_custom_sei_set[i] = NULL; + /* + * Cannot aquire the write access to nbuffer because someone else on the go, + * Retry to see if model is ready. + */ + ni_log2(p_ctx, NI_LOG_TRACE, + "AI write query failed or buf_size %u < " + "frame_size %u.\n", buf_info.buf_avail_size, nb_size); } else { - //backup solution pts - p_frame->pts = p_ctx->last_pts + (p_frame->dts - p_ctx->last_dts); - ni_log(NI_LOG_ERROR, - "ERROR: NO pts found consider increasing NI_FIFO_SZ!\n"); - ni_log(NI_LOG_DEBUG, - "%s: (not found use default) dts %" PRId64 " pts %" PRId64 - "\n", - __func__, p_frame->dts, p_frame->pts); + /* Grant write access to nbuffer */ + ni_log2(p_ctx, NI_LOG_DEBUG, + "Info ai write query success, available buf " + "size %u >= frame size %u !\n", + buf_info.buf_avail_size, nb_size); + break; + } + retry_count++; + /* Wait for at least 30s */ + if (retry_count < NI_MAX_AI_NETWORK_BINARY_BUFFER_QUERY_RETRIES) + { + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(100); + ni_pthread_mutex_lock(&p_ctx->mutex); + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, "AI network binary configuration polling timeout\n"); + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; } } - p_frame->pts = guess_correct_pts(p_ctx, p_frame->pts, p_frame->dts); - p_ctx->last_pts = p_frame->pts; - if (p_frame->dts != NI_NOPTS_VALUE && p_ctx->last_dts != NI_NOPTS_VALUE) - p_ctx->last_dts_interval = p_frame->dts - p_ctx->last_dts; - p_ctx->last_dts = p_frame->dts; - ni_log(NI_LOG_DEBUG, "%s: (best_effort_timestamp) pts %" PRId64 "\n", - __func__, p_frame->pts); - p_ctx->frame_num++; - } - -#ifdef XCODER_DUMP_ENABLED - fwrite(p_frame->data[0], rx_size, 1, p_ctx->p_dump[1]); -#endif - - ni_log(NI_LOG_DEBUG, "%s(): received data: [0x%08x]\n", __func__, rx_size); - ni_log(NI_LOG_DEBUG, - "%s(): p_frame->start_of_stream=%u, " - "p_frame->end_of_stream=%u, p_frame->video_width=%u, " - "p_frame->video_height=%u\n", - __func__, p_frame->start_of_stream, p_frame->end_of_stream, - p_frame->video_width, p_frame->video_height); - ni_log(NI_LOG_DEBUG, "%s(): p_frame->data_len[0/1/2]=%u/%u/%u\n", __func__, - p_frame->data_len[0], p_frame->data_len[1], p_frame->data_len[2]); +#if 1 + /* write network binary data */ + ui32LBA = WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): write nb LBA 0x%x\n", __func__, ui32LBA); + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_nb_data, buffer_size, ui32LBA); + ni_log2(p_ctx, NI_LOG_DEBUG, "write complete retval %d\n", retval); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + //Close the session since we can't configure it + retval = ni_ai_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: ni_ai_session_close failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, + p_ctx->session_id); + } - if (p_ctx->frame_num % 500 == 0) - { - ni_log(NI_LOG_DEBUG, - "Decoder pts queue size = %d dts queue size = %d\n\n", - p_ctx->pts_table->list.count, p_ctx->dts_queue->list.count); - // scan and clean up - ni_timestamp_scan_cleanup(p_ctx->pts_table, p_ctx->dts_queue, - p_ctx->buffer_pool); - } + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } -#ifdef MEASURE_LATENCY - if ((p_frame->dts != NI_NOPTS_VALUE) && (p_ctx->frame_time_q != NULL)) - { - abs_time_ns = ni_gettime_ns(); - ni_log(NI_LOG_INFO, "DTS:%lld,DELTA:%lu,dLAT:%lu;\n", p_frame->dts, - abs_time_ns - p_ctx->prev_read_frame_time, - ni_lat_meas_q_check_latency((ni_lat_meas_q_t *)p_ctx->frame_time_q, - abs_time_ns, p_frame->dts)); - p_ctx->prev_read_frame_time = abs_time_ns; - } -#endif +#else + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): write nb buffer_size %u\n", __func__, + buffer_size); + for (transferred = 0; transferred < buffer_size; transferred += this_size) + { + this_size = p_ctx->max_nvme_io_size < (buffer_size - transferred) ? + p_ctx->max_nvme_io_size : + (buffer_size - transferred); -END: + if (this_size & (4096 - 1)) + { + this_size = (this_size + (4096 - 1)) & ~(4096 - 1); + } + /* write network binary data */ + ui32LBA = WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_AI) + + (transferred >> 12); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): write nb LBA 0x%x, this_size %u, page_offset %u\n", + __func__, ui32LBA, this_size, (transferred >> 12)); + p_data = (uint8_t *)p_nb_data + transferred; + retval = ni_nvme_send_write_cmd( + p_ctx->blk_io_handle, p_ctx->event_handle, + (uint8_t *)p_nb_data + transferred, this_size, ui32LBA); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): write retval %d\n", __func__, retval); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log( + NI_LOG_ERROR, + "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + //Close the session since we can't configure it + retval = ni_ai_session_close(p_ctx, 0); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log( + NI_LOG_ERROR, + "ERROR: ni_ai_session_close failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, + p_ctx->session_id); + } - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_TRACE, "%s(): bad exit, retval = %d\n", __func__, retval); - return retval; - } else - { - ni_log(NI_LOG_TRACE, "%s(): exit, rx_size = %d\n", __func__, rx_size); - return rx_size; + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } } -} - -/*!****************************************************************************** -* \brief Retrieve a YUV p_frame from decoder -* -* \param -* -* \return -*******************************************************************************/ -int ni_hwdownload_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame, niFrameSurface1_t* hwdesc) -{ - int retval = NI_RETCODE_SUCCESS; - int rx_size = 0; - uint64_t frame_offset = 0; - uint16_t yuvW = 0; - uint16_t yuvH = 0; - uint8_t *p_data_buffer; - int i = 0; - int metadata_hdr_size = NI_FW_META_DATA_SZ - - NI_MAX_NUM_OF_DECODER_OUTPUTS * sizeof(niFrameSurface1_t); - int sei_size = 0; - uint32_t total_bytes_to_read = 0; - uint32_t read_size_bytes = 0; - uint32_t actual_read_size = 0; - static long long decq_count = 0LL; - int keep_processing = 1; - int query_retry = 0; - uint32_t ui32LBA = 0; - //ni_log(NI_LOG_DEBUG, "hwcontext.c:ni_hwdl_frame() hwdesc %d %d %d\n", - // hwdesc->ui16FrameIdx, - // hwdesc->i8InstID, - // hwdesc->ui16session_ID); +#endif - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); +END: + ni_pthread_mutex_unlock(&p_ctx->mutex); - if ((!p_ctx) || (!p_frame)) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - return NI_RETCODE_INVALID_PARAM; - } + ni_aligned_free(p_ai_config); + ni_aligned_free(p_nb_data); + ni_aligned_free(p_buffer); - if (NI_INVALID_SESSION_ID == p_ctx->session_id) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; - } + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); - p_data_buffer = (uint8_t *)p_frame->p_buffer; + return retval; +} - for (i = 0; i < NI_MAX_NUM_DATA_POINTERS - 1; i++) //discount the hwdesc - { - if (!p_frame->p_data[i]) +ni_retcode_t ni_ai_query_network_ready(ni_session_context_t *p_ctx) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + void *p_buffer = NULL; + uint32_t ui32LBA = 0; + int retry_count = 0; + uint32_t dataLen = (sizeof(ni_network_layer_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %s(): No receive buffer allocated.\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: Cannot allocate buffer.\n"); + retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } - } - - if (0 == p_frame->data_len[0]) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): p_frame->data_len[0] = 0!.\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } + for(;;) + { + memset(p_buffer, 0, dataLen); + ui32LBA = + QUERY_INSTANCE_NL_SIZE_V2_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + } + if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size > 0) + { + ni_log2(p_ctx, NI_LOG_INFO, "%s(): network binary registered\n", __func__); + break; + } - if (hwdesc->encoding_type == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) - { - p_frame->data_len[2] = 0; - } - total_bytes_to_read = p_frame->data_len[0] + p_frame->data_len[1] + - p_frame->data_len[2];// +metadata_hdr_size; - unsigned int bytes_read_so_far = 0; - uint32_t output_chunk_offset = hwdesc->ui32nodeAddress / FRAME_CHUNK_INDEX_SIZE; //for reading output1 or output2 - uint32_t output_minor_offset = hwdesc->ui32nodeAddress - output_chunk_offset * FRAME_CHUNK_INDEX_SIZE; - ni_log(NI_LOG_DEBUG, "Total bytes to download %u, start offset = %u, chunkOffset " - "%u, minorOffset %u\n", - total_bytes_to_read, hwdesc->ui32nodeAddress, - output_chunk_offset, output_minor_offset); + retry_count++; + /* Wait for at least 30s */ + if (retry_count < NI_MAX_AI_NETWORK_BINARY_BUFFER_QUERY_RETRIES) + { + ni_usleep(100); + } else + { + ni_log2(p_ctx, NI_LOG_DEBUG, "AI network binary configuration polling timeout\n"); + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; + } + } +END: - ni_log(NI_LOG_DEBUG, "total_bytes_to_read %u max_nvme_io_size %u ylen %u cr len " - "%u cb len %u hdr %d\n", - total_bytes_to_read, p_ctx->max_nvme_io_size, - p_frame->data_len[0], p_frame->data_len[1], - p_frame->data_len[2], metadata_hdr_size); + ni_aligned_free(p_buffer); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); - //Apply read configuration here - retval = - ni_config_session_rw(p_ctx, SESSION_READ_CONFIG, 1, - (output_minor_offset << NI_CODEC_HW_PAYLOAD_OFFSET) | - NI_CODEC_HW_ENABLE | NI_CODEC_HW_DOWNLOAD, - hwdesc->ui16FrameIdx); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, hwdesc->src_cpu, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - read_size_bytes = total_bytes_to_read; - ui32LBA = READ_INSTANCE_R(p_ctx->session_id, hwdesc->src_cpu); - ui32LBA += output_chunk_offset; - if (read_size_bytes % NI_MEM_PAGE_ALIGNMENT) - { - read_size_bytes = ( (read_size_bytes / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT) + NI_MEM_PAGE_ALIGNMENT; - } + return retval; - retval = ni_nvme_send_read_cmd( - (ni_device_handle_t)(int64_t)hwdesc->device_handle, - NI_INVALID_DEVICE_HANDLE, p_data_buffer, read_size_bytes, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_read, hwdesc->src_cpu, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); - if (retval < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; - } else - { - ni_log(NI_LOG_DEBUG, - "decoder read desc success, retval %d " - "total_bytes_to_read include sei %u sei_size %d\n", - __func__, retval, total_bytes_to_read, sei_size); - } +} - //Unset applied read configuration here - retval = ni_config_session_rw(p_ctx, SESSION_READ_CONFIG, 0, 0, 0); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, hwdesc->src_cpu, - p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); +ni_retcode_t ni_ai_session_write(ni_session_context_t *p_ctx, + ni_frame_t *p_frame) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + ni_instance_buf_info_t buf_info = {0}; + uint32_t frame_size_bytes; + uint32_t sent_size = 0; + int32_t query_retry = 0; - bytes_read_so_far = total_bytes_to_read; - // Note: session status is NOT reset but tracked between send - // and recv to catch and recover from a loop condition + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); - if (p_ctx->is_auto_dl) - rx_size = (int)bytes_read_so_far; - else - { - rx_size = - ni_create_frame(p_frame, bytes_read_so_far, &frame_offset, false); - p_ctx->frame_pkt_offset = frame_offset; - } + if (!p_ctx || !p_frame) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): passed parameters is null\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + return retval; + } + if (p_frame->data_len[0] == 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() invalid data length\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + return retval; + } -#ifdef XCODER_DUMP_ENABLED - fwrite(p_frame->data[0], rx_size, 1, p_ctx->p_dump[1]); -#endif + ni_pthread_mutex_lock(&p_ctx->mutex); - ni_log(NI_LOG_DEBUG, "xcoder_dec_receive(): received data: [0x%08x]\n", - __func__, rx_size); - ni_log(NI_LOG_DEBUG, - "xcoder_dec_receive(): p_frame->start_of_stream=%u, " - "p_frame->end_of_stream=%u, p_frame->video_width=%u, " - "p_frame->video_height=%u\n", - __func__, p_frame->start_of_stream, p_frame->end_of_stream, - p_frame->video_width, p_frame->video_height); - ni_log(NI_LOG_DEBUG, - "%s(): p_ctx->frame_num %" PRIu64 ", " - "p_frame->data_len[0/1/2]=%u/%u/%u\n", - __func__, p_ctx->frame_num, p_frame->data_len[0], p_frame->data_len[1], - p_frame->data_len[2]); - //if (decq_count % 500 == 0) - //{ - // ni_log(NI_LOG_DEBUG, "Decoder pts queue size = %d dts queue size = %d\n\n", - // p_ctx->pts_table->list.count, p_ctx->dts_queue)->list.count); - // // scan and clean up - // ni_timestamp_scan_cleanup(p_ctx->pts_table, p_ctx->dts_queue, p_ctx->buffer_pool); - //} + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } -END: + frame_size_bytes = p_frame->data_len[0]; + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): frame_size_bytes %u\n", __func__, + frame_size_bytes); - if (NI_RETCODE_SUCCESS != retval) + for (;;) { - ni_log(NI_LOG_ERROR, "%s(): bad exit, retval = %d\n", __func__, retval); - return retval; - } else + if (p_ctx->session_statistic.ui32WrBufAvailSize >= frame_size_bytes) + { + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32WrBufAvailSize; + ni_log2(p_ctx, NI_LOG_DEBUG, + "Info ai write query success, available buf " + "size %u >= frame size %u !\n", + buf_info.buf_avail_size, frame_size_bytes); + break; + } + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6K") >= 0) + { + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_AI, + &p_ctx->session_statistic); + CHECK_ERR_RC(p_ctx, retval, &p_ctx->session_statistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32WrBufAvailSize; + } else + { + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, + NI_DEVICE_TYPE_AI, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + } + if (NI_RETCODE_SUCCESS != retval || + buf_info.buf_avail_size < frame_size_bytes) + { + ni_log2(p_ctx, NI_LOG_TRACE, + "AI write query failed or buf_size < frame_size. Retry %d\n", + query_retry); + // extend to 5000 retries for 8K encode on FPGA + if (query_retry >= NI_MAX_ENCODER_QUERY_RETRIES) + { + ni_log2(p_ctx, NI_LOG_DEBUG, + "AI write query exceeded max retries: %d\n", + NI_MAX_ENCODER_QUERY_RETRIES); + p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); + query_retry++; + } + } + + ui32LBA = WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); + ni_log2(p_ctx, NI_LOG_DEBUG, "Ai session write: p_data = %p, p_frame->buffer_size = %u, " + "p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", + p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, + ui32LBA); + + sent_size = frame_size_bytes; + if (sent_size & (NI_MEM_PAGE_ALIGNMENT - 1)) { - ni_log(NI_LOG_TRACE, "%s(): exit, rx_size = %d\n", __func__, rx_size); - return rx_size; + sent_size = (sent_size + NI_MEM_PAGE_ALIGNMENT - 1) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); } -} -/*!****************************************************************************** -* \brief Close an xcoder upload instance -* -* \param p_ctx pointer to uploader session context -* -* \return NI_RETCODE_SUCCESS -*******************************************************************************/ -ni_retcode_t ni_uploader_session_close(ni_session_context_t* p_ctx) -{ -#ifndef _WIN32 - if (p_ctx->isP2P) + retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_frame->p_buffer, sent_size, ui32LBA); + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6K") >= 0) { - if (p_ctx->netint_fd) + if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_DEBUG, "%s: close driver fd %d\n", __func__, - p_ctx->netint_fd); - close(p_ctx->netint_fd); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_AI, + &p_ctx->session_statistic); + CHECK_ERR_RC(p_ctx, retval, &p_ctx->session_statistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + } else + { + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_write, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; } } -#endif - return NI_RETCODE_SUCCESS; + + p_ctx->frame_num++; + + retval = frame_size_bytes; + +END: + + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; } -/*!****************************************************************************** -* \brief Send a p_config command to configure uploading parameters. -* -* \param ni_session_context_t p_ctx - xcoder Context -* \param[in] pool_size pool size to create -* \param[in] pool 0 = normal pool, 1 = P2P pool -* -* \return - NI_RETCODE_SUCCESS on success, -* NI_RETCODE_ERROR_INVALID_SESSION -* NI_RETCODE_ERROR_NVME_CMD_FAILED on failure -*******************************************************************************/ -ni_retcode_t ni_config_instance_set_uploader_params(ni_session_context_t *p_ctx, - uint32_t pool_size, - uint32_t pool) +ni_retcode_t ni_ai_session_read(ni_session_context_t *p_ctx, + ni_packet_t *p_packet) { - void* p_uploader_config = NULL; - ni_uploader_config_t* p_cfg = NULL; - uint32_t buffer_size = sizeof(ni_encoder_config_t); - ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t ui32LBA = 0; - int i = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + uint32_t actual_read_size = 0; + int retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + ni_instance_buf_info_t buf_info = {0}; - if (!p_ctx) + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx || !p_packet || !p_packet->p_data) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); retval = NI_RETCODE_INVALID_PARAM; - LRETURN; + return retval; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; - if (ni_posix_memalign(&p_uploader_config, sysconf(_SC_PAGESIZE), - buffer_size)) + for (;;) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; - } - memset(p_uploader_config, 0, buffer_size);// - - p_cfg = (ni_uploader_config_t*)p_uploader_config; - p_cfg->ui16picWidth = p_ctx->active_video_width; - p_cfg->ui16picHeight = p_ctx->active_video_height; - p_cfg->ui8poolSize = pool_size; - p_cfg->ui8PixelFormat = p_ctx->pixel_format; - p_cfg->ui8Pool = pool; + if (p_ctx->session_statistic.ui32RdBufAvailSize >= p_packet->data_len) + { + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32RdBufAvailSize; + ni_log2(p_ctx, NI_LOG_DEBUG, + "Info ai read query success, available buf " + "size %u >= frame size %u !\n", + buf_info.buf_avail_size, p_packet->data_len); + break; + } + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6K") >= 0) + { + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_AI, + &p_ctx->session_statistic); + CHECK_ERR_RC(p_ctx, retval, &p_ctx->session_statistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32RdBufAvailSize; + } else + { + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_READ, + NI_DEVICE_TYPE_AI, &buf_info); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, + &(p_ctx->session_id), OPT_1); + } + ni_log2(p_ctx, NI_LOG_TRACE, + "Info ai read query rc %d, available buf size %u, " + "frame_num=%" PRIu64 ", pkt_num=%" PRIu64 "\n", + retval, buf_info.buf_avail_size, p_ctx->frame_num, + p_ctx->pkt_num); - ni_log(NI_LOG_DEBUG, "ni_config_instance_set_uploader_params():%d x %d x Format %d with %d framepool\n", - p_cfg->ui16picWidth, p_cfg->ui16picHeight, p_cfg->ui8PixelFormat, p_cfg->ui8poolSize); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Buffer info query failed in ai read!!!!\n"); + LRETURN; + } else if (0 == buf_info.buf_avail_size) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Info ai read available buf size %u, eos %u !\n", + buf_info.buf_avail_size, p_packet->end_of_stream); + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + } + ni_log2(p_ctx, NI_LOG_DEBUG, "Ai read buf_avail_size %u\n", buf_info.buf_avail_size); - //configure the session here - ui32LBA = - CONFIG_INSTANCE_SetEncPara_W(p_ctx->session_id, NI_DEVICE_TYPE_ENCODER); + assert(buf_info.buf_avail_size >= p_packet->data_len); - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_uploader_config, buffer_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS != retval) + ui32LBA = READ_INSTANCE_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + actual_read_size = p_packet->data_len; + if (actual_read_size & (NI_MEM_PAGE_ALIGNMENT - 1)) { - ni_log(NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - //Close the session since we can't configure it - retval = ni_encoder_session_close(p_ctx, 0); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, "ERROR: ni_uploader_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - } + actual_read_size = (actual_read_size + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + } - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_packet->p_data, actual_read_size, ui32LBA); + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6K") >= 0) + { + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_AI, + &p_ctx->session_statistic); + CHECK_ERR_RC(p_ctx, retval, &p_ctx->session_statistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + } else + { + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } } + retval = p_packet->data_len; + END: - ni_aligned_free(p_uploader_config); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } -/*!****************************************************************************** -* \brief Send a p_config command to configure decoding parameters. -* -* \param ni_session_context_t p_ctx - xcoder Context -* \param uint32_t max_pkt_size - overwrite maximum packet size if nonzero -* -* \return - NI_RETCODE_SUCCESS on success, NI_RETCODE_ERROR_INVALID_SESSION, NI_RETCODE_ERROR_NVME_CMD_FAILED on failure -*******************************************************************************/ -ni_retcode_t ni_config_instance_set_decoder_params(ni_session_context_t* p_ctx, uint32_t max_pkt_size) +static void ni_unreference_network_data(ni_network_data_t *network_data) { - void* p_decoder_config = NULL; - ni_decoder_config_t* p_cfg = NULL; - uint32_t buffer_size = sizeof(ni_decoder_config_t); - ni_retcode_t retval = NI_RETCODE_SUCCESS; - int i = 0; - uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); - - if (!p_ctx) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } + if (network_data) + { + ni_memfree(network_data->inset); + ni_memfree(network_data->linfo.in_param); + } +} - if (NI_INVALID_SESSION_ID == p_ctx->session_id) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; - } +ni_retcode_t ni_config_read_inout_layers(ni_session_context_t *p_ctx, + ni_network_data_t *p_network) +{ + void *p_buffer = NULL; + void *p_info = NULL; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + uint32_t ui32LBA = 0; + uint32_t dataLen; + int32_t query_retry = 0; + int l; + ni_network_layer_params_t *layer_param; + uint32_t buffer_size; + uint32_t this_size; + ni_network_data_t *network_data = NULL; + uint32_t total_io_num; - buffer_size = ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) * NI_MEM_PAGE_ALIGNMENT; - if (ni_posix_memalign(&p_decoder_config, sysconf(_SC_PAGESIZE), buffer_size)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate p_decoder_config buffer\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; - } - memset(p_decoder_config, 0, buffer_size); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); - ni_set_custom_dec_template(p_ctx, p_decoder_config, p_ctx->p_session_config, max_pkt_size); - retval = ni_validate_custom_dec_template(p_ctx->p_session_config, p_ctx, p_decoder_config, p_ctx->param_err_msg, sizeof(p_ctx->param_err_msg)); - if (NI_RETCODE_PARAM_WARN == retval) - { - ni_log(NI_LOG_INFO, "WARNING: %s . %s\n", __func__, p_ctx->param_err_msg); - fflush(stdout); - } - else if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, "ERROR: %s failed. %s\n", __func__, - p_ctx->param_err_msg); - fflush(stdout); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } + if (!p_ctx || !p_network) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } - // configure the session here - ui32LBA = CONFIG_INSTANCE_SetDecPara_W(p_ctx->session_id, NI_DEVICE_TYPE_DECODER); + network_data = p_ctx->network_data; + if (network_data->linfo.in_param != NULL) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s(): network parameters data is already initialized\n", + __func__); + retval = NI_RETCODE_SUCCESS; + LRETURN; + } - //Flip the bytes!! - //p_cfg = (ni_decoder_config_t*)p_decoder_config; - //p_cfg->i32picWidth = ni_htonl(p_cfg->i32picWidth); - //p_cfg->i32picHeight = ni_htonl(p_cfg->i32picHeight); - //p_cfg->i32meBlkMode = ni_htonl(p_cfg->i32meBlkMode); - //p_cfg->i32frameRateInfo = ni_htonl(p_cfg->i32frameRateInfo); - //p_cfg->i32vbvBufferSize = ni_htonl(p_cfg->i32vbvBufferSize); - //p_cfg->i32userQpMax = ni_htonl(p_cfg->i32userQpMax); - //p_cfg->i32maxIntraSize = ni_htonl(p_cfg->i32maxIntraSize); - //p_cfg->i32userMaxDeltaQp = ni_htonl(p_cfg->i32userMaxDeltaQp); - //p_cfg->i32userMinDeltaQp = ni_htonl(p_cfg->i32userMinDeltaQp); - //p_cfg->i32userQpMin = ni_htonl(p_cfg->i32userQpMin); - //p_cfg->i32bitRate = ni_htonl(p_cfg->i32bitRate); - //p_cfg->i32bitRateBL = ni_htonl(p_cfg->i32bitRateBL); - //p_cfg->i32srcBitDepth = ni_htonl(p_cfg->i32srcBitDepth); - //p_cfg->hdrEnableVUI = ni_htonl(p_cfg->hdrEnableVUI); - //p_cfg->ui32VuiDataSizeBits = ni_htonl(p_cfg->ui32VuiDataSizeBits); - //p_cfg->ui32VuiDataSizeBytes = ni_htonl(p_cfg->ui32VuiDataSizeBytes); - //p_cfg->i32hwframes = ni_htonl(p_cfg->i32hwframes); - // flip the 16 bytes of the reserved field using 32 bits pointers - //for (i = 0; i < (16 >> 2); i++) - //{ - // ((uint32_t*)p_cfg->ui8Reserved)[i] = ni_htonl(((uint32_t*)p_cfg->ui8Reserved)[i]); - //} - //// flip the NI_MAX_VUI_SIZE bytes of the VUI field using 32 bits pointers - //for (i = 0; i < (NI_MAX_VUI_SIZE >> 2); i++) // apply on 32 bits - //{ - // ((uint32_t*)p_cfg->ui8VuiRbsp)[i] = ni_htonl(((uint32_t*)p_cfg->ui8VuiRbsp)[i]); - //} + ni_pthread_mutex_lock(&p_ctx->mutex); - ni_log(NI_LOG_DEBUG, "%s: ui32LBA = 0x%x\n", __func__, ui32LBA); - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_decoder_config, buffer_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - //Close the session since we can't configure it - retval = ni_decoder_session_close(p_ctx, 0); - if (NI_RETCODE_SUCCESS != retval) + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR: ni_encoder_session_close failed: blk_io_handle: %" PRIx64 ", hw_id, %u, xcoder_inst_id: %d\n", (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; } - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - } + /* query available size can be read. */ + dataLen = (sizeof(ni_instance_buf_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_buffer, 0, dataLen); -END: + for (;;) + { + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6J") >= 0) + { + ui32LBA = QUERY_INSTANCE_NL_SIZE_V2_R(p_ctx->session_id, + NI_DEVICE_TYPE_AI); + } else + { + ui32LBA = + QUERY_INSTANCE_NL_SIZE_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + } + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } - ni_aligned_free(p_decoder_config); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); - return retval; -} + if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size > 0) + { + break; + } -/*!****************************************************************************** - * \brief read a hardware descriptor from a scaler session - * - * \param[in] p_ctx pointer to session context - * \param[out] p_frame pointer to frame to write hw descriptor - * - * \return NI_RETCODE_INVALID_PARAM - * NI_RETCODE_ERROR_INVALID_SESSION - * NI_RETCODE_ERROR_MEM_ALOC - * NI_RETCODE_ERROR_NVME_CMD_FAILED - * NI_RETCODE_FAILURE - *******************************************************************************/ -ni_retcode_t ni_scaler_session_read_hwdesc( - ni_session_context_t *p_ctx, - ni_frame_t *p_frame) -{ - ni_retcode_t retval; - ni_instance_buf_info_t sInstanceBuf = {0}; - niFrameSurface1_t *pFrameSurface; - int query_retry = 0; + query_retry++; + if (query_retry > 50000) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): exceeded max query retries: %d\n", + __func__, query_retry - 1); + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(200); + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; + } - if (!p_ctx) + if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size == 0) + { + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; + } + + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6J") >= 0) + { + network_data->input_num = + ((ni_instance_buf_info_t *)p_buffer)->buf_avail_size >> 16; + network_data->output_num = + ((ni_instance_buf_info_t *)p_buffer)->buf_avail_size & 0xFFFF; + } else + { + network_data->input_num = 4; + network_data->output_num = 4; + } + + total_io_num = network_data->input_num + network_data->output_num; + + network_data->linfo.in_param = (ni_network_layer_params_t *)calloc( + total_io_num, sizeof(ni_network_layer_params_t)); + if (!network_data->linfo.in_param) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): Unable to allocate network layer params\n", __func__); - return NI_RETCODE_INVALID_PARAM; + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; } + network_data->linfo.out_param = + network_data->linfo.in_param + network_data->input_num; - if (p_ctx->session_id == NI_INVALID_SESSION_ID) + network_data->inset = (ni_network_layer_offset_t *)calloc( + total_io_num, sizeof(ni_network_layer_offset_t)); + if (!network_data->inset) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): Unable to allocate network offset\n", __func__); - return NI_RETCODE_ERROR_INVALID_SESSION; + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; } + network_data->outset = network_data->inset + network_data->input_num; - for (;;) + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6J") >= 0) { - query_retry++; + /* query the real network layer data */ + this_size = sizeof(ni_network_layer_params_t) * total_io_num; + dataLen = (this_size + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_info, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate info buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_info, 0, dataLen); - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_UPLOAD, - NI_DEVICE_TYPE_SCALER, &sInstanceBuf); + ui32LBA = QUERY_INSTANCE_NL_V2_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_info, dataLen, ui32LBA); + if ((int32_t)retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + memcpy(network_data->linfo.in_param, p_info, this_size); + } else + { + /* query the real network layer data */ + this_size = sizeof(ni_network_layer_params_t) * total_io_num; + dataLen = (this_size + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_info, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate info buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_info, 0, dataLen); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + ui32LBA = QUERY_INSTANCE_NL_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_info, dataLen, ui32LBA); + if ((int32_t)retval < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + memcpy(network_data->linfo.in_param, p_info, this_size); - if (retval != NI_RETCODE_SUCCESS) + for (l = 0, network_data->input_num = 0; l < 4; l++) { - if (query_retry >= 1000) + layer_param = &network_data->linfo.in_param[l]; + if (layer_param->num_of_dims == 0) { - ni_log(NI_LOG_DEBUG, "Warning hwdesc read fail rc %d\n", retval); - LRETURN; + break; } + network_data->input_num++; } - else - { - pFrameSurface = (niFrameSurface1_t *) p_frame->p_data[3]; - pFrameSurface->ui16FrameIdx = sInstanceBuf.hw_inst_ind.frame_index; - pFrameSurface->ui16session_ID = p_ctx->session_id; - pFrameSurface->device_handle = - (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); - pFrameSurface->src_cpu = (uint8_t) NI_DEVICE_TYPE_SCALER; - pFrameSurface->output_idx = 0; - /* A frame index of zero is invalid, the memory acquisition failed */ - if (pFrameSurface->ui16FrameIdx == 0) + for (l = 0, network_data->output_num = 0; l < 4; l++) + { + layer_param = &network_data->linfo.out_param[l]; + if (layer_param->num_of_dims == 0) { - if (query_retry >= 1000) - { - ni_log(NI_LOG_ERROR, "Warning: 2D could not acquire frame\n"); - retval = NI_RETCODE_FAILURE; - LRETURN; - } - continue; + break; } - LRETURN; + network_data->output_num++; } } -END: + for (l = 0, buffer_size = 0; l < network_data->input_num; l++) + { + layer_param = &network_data->linfo.in_param[l]; + this_size = ni_ai_network_layer_size(layer_param); + this_size = + (this_size + NI_AI_HW_ALIGN_SIZE - 1) & ~(NI_AI_HW_ALIGN_SIZE - 1); + network_data->inset[l].offset = buffer_size; + buffer_size += this_size; - if (NI_RETCODE_SUCCESS != retval) + ni_log2(p_ctx, + NI_LOG_DEBUG, + "%s(): network input layer %d: dims %u, %u/%u/%u/%u, f %d, q %d\n", + __func__, l, layer_param->num_of_dims, layer_param->sizes[0], + layer_param->sizes[1], layer_param->sizes[2], layer_param->sizes[3], + layer_param->data_format, layer_param->quant_format); + } + + for (l = 0, buffer_size = 0; l < network_data->output_num; l++) { - ni_log(NI_LOG_DEBUG, - "Warning scalar read hwdesc fail rc %d or ind " - "!\n", - __func__, retval); - retval = NI_RETCODE_FAILURE; + layer_param = &network_data->linfo.out_param[l]; + this_size = ni_ai_network_layer_size(layer_param); + this_size = + (this_size + NI_AI_HW_ALIGN_SIZE - 1) & ~(NI_AI_HW_ALIGN_SIZE - 1); + network_data->outset[l].offset = buffer_size; + buffer_size += this_size; + + ni_log2(p_ctx, + NI_LOG_DEBUG, + "%s(): network output layer %d: dims %u, %u/%u/%u/%u, f %d, q %d\n", + __func__, l, layer_param->num_of_dims, layer_param->sizes[0], + layer_param->sizes[1], layer_param->sizes[2], layer_param->sizes[3], + layer_param->data_format, layer_param->quant_format); } - return retval; -} + memcpy(p_network, network_data, sizeof(ni_network_data_t)); -/*!****************************************************************************** -* \brief Grab bitdepth factor from NI_PIX_FMT -* -* \param[in] pix_fmt ni_pix_fmt_t -* -* \return 1 or 2 for success, -1 for error -*******************************************************************************/ -int ni_get_bitdepth_factor_from_pixfmt(int pix_fmt) -{ - switch (pix_fmt) - { - case NI_PIX_FMT_YUV420P: - case NI_PIX_FMT_NV12: - return 1; - case NI_PIX_FMT_YUV420P10LE: - case NI_PIX_FMT_P010LE: - return 2; - default: + retval = NI_RETCODE_SUCCESS; + +END: + ni_pthread_mutex_unlock(&p_ctx->mutex); + + if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR: %s() non applicable format %d\n", __func__, - pix_fmt); - break; + ni_unreference_network_data(network_data); } - } - return -1; + ni_aligned_free(p_buffer); + ni_aligned_free(p_info); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + return retval; } -/*!****************************************************************************** -* \brief Grab planar info from NI_PIX_FMT -* -* \param[in] pix_fmt ni_pix_fmt_t -* -* \return 0 or 1 for success, -1 for error -*******************************************************************************/ -int ni_get_planar_from_pixfmt(int pix_fmt) +ni_retcode_t ni_ai_session_open(ni_session_context_t *p_ctx) { - switch (pix_fmt) - { - case NI_PIX_FMT_YUV420P: - case NI_PIX_FMT_YUV420P10LE: - return 1; - break; - case NI_PIX_FMT_NV12: - case NI_PIX_FMT_P010LE: - return 0; - break; - default: + ni_retcode_t retval = NI_RETCODE_SUCCESS; + void *p_buffer = NULL; + uint32_t ui32LBA = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() non applicable format %d\n", __func__, - pix_fmt); - break; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; } - } - return -1; -} -#ifndef _WIN32 -/*!***************************************************************************** - * \brief Get an address offset from a hw descriptor - * - * \param[in] p_ctx ni_session_context_t to be referenced - * \param[in] hwdesc Pointer to caller allocated niFrameSurface1_t - * \param[out] p_offset Value of offset - * - * \return On success NI_RETCODE_SUCCESS - * On failure NI_RETCODE_INVALID_PARAM - ******************************************************************************/ -ni_retcode_t ni_get_memory_offset(ni_session_context_t *p_ctx, const niFrameSurface1_t *hwdesc, - uint32_t *p_offset) -{ - if (!hwdesc) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed null parameter\n", __func__); - return NI_RETCODE_INVALID_PARAM; - } + //Check if there is an instance or we need a new one + if (NI_INVALID_SESSION_ID == p_ctx->session_id) + { + p_ctx->device_type = NI_DEVICE_TYPE_AI; + p_ctx->pts_table = NULL; + p_ctx->dts_queue = NULL; + p_ctx->buffer_pool = NULL; + p_ctx->status = 0; + p_ctx->key_frame_type = 0; + p_ctx->keyframe_factor = 1; + p_ctx->frame_num = 0; + p_ctx->pkt_num = 0; + p_ctx->rc_error_count = 0; + p_ctx->force_frame_type = 0; + p_ctx->ready_to_close = 0; + //Sequence change tracking reated stuff + p_ctx->active_video_width = 0; + p_ctx->active_video_height = 0; + p_ctx->p_all_zero_buf = NULL; + p_ctx->actual_video_width = 0; + p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; + memset(&(p_ctx->param_err_msg[0]), 0, sizeof(p_ctx->param_err_msg)); + + //malloc zero data buffer + if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), + NI_DATA_BUFFER_LEN)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_ctx->p_all_zero_buf, 0, NI_DATA_BUFFER_LEN); + + //malloc data buffer + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), + NI_DATA_BUFFER_LEN)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + + //Set session ID to be invalid. In case we cannot open session, the session id wold remain invalid. + //In case we can open sesison, the session id would become valid. + ((ni_session_stats_t *)p_buffer)->ui16SessionId = + (uint16_t)NI_INVALID_SESSION_ID; + + // First uint32_t is either an invaild session ID or a valid session ID, depending on if session could be opened + ui32LBA = OPEN_SESSION_CODEC(NI_DEVICE_TYPE_AI, 0, p_ctx->hw_action); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): LBA 0x%x, hw_action %d\n", __func__, + ui32LBA, p_ctx->hw_action); + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); + LRETURN; + } + //Open will return a session status structure with a valid session id if it worked. + //Otherwise the invalid session id set before the open command will stay + if ((uint16_t)NI_INVALID_SESSION_ID == + ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId)) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): p_ctx->device_handle=%" PRIx64 + ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", + __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, + p_ctx->session_id); + ni_ai_session_close(p_ctx, 0); + retval = NI_RETCODE_ERROR_INVALID_SESSION; + LRETURN; + } + p_ctx->session_id = + ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); + p_ctx->session_timestamp = ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_high); + p_ctx->session_timestamp = (p_ctx->session_timestamp << 32) | + ni_htonl(((ni_session_stats_t *)p_buffer)->ui32Session_timestamp_low); + ni_log2(p_ctx, NI_LOG_DEBUG, "Ai open session ID:0x%x,timestamp:%" PRIu64 "\n", + p_ctx->session_id, p_ctx->session_timestamp); + + ni_log2(p_ctx, NI_LOG_DEBUG, "Open session completed\n"); + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_ctx->device_handle=%" PRIx64 + ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", + __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, + p_ctx->session_id); + + //Send keep alive timeout Info + uint64_t keep_alive_timeout = + p_ctx->keep_alive_timeout * 1000000; //send us to FW + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, + keep_alive_timeout); + ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); + retval = + ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + CHECK_VPU_RECOVERY(retval); + + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): nvme write keep_alive_timeout command " + "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", + __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } - if (hwdesc->ui16FrameIdx <= NI_GET_MIN_HWDESC_P2P_BUF_ID(p_ctx->ddr_config) || - hwdesc->ui16FrameIdx > NI_GET_MAX_HWDESC_P2P_BUF_ID(p_ctx->ddr_config)) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() pass invalid data\n", __func__); - return NI_RETCODE_INVALID_PARAM; + p_ctx->network_data = + (ni_network_data_t *)calloc(1, sizeof(ni_network_data_t)); + if (!p_ctx->network_data) + { + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR %s(): Unable to allocate network_data memory\n"); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } } - *p_offset = (hwdesc->ui16FrameIdx - NI_GET_MIN_HWDESC_P2P_BUF_ID(p_ctx->ddr_config)) * - NI_HWDESC_UNIFIED_MEMBIN_SIZE; + // init for frame pts calculation + p_ctx->is_first_frame = 1; + p_ctx->last_pts = 0; + p_ctx->last_dts = 0; + p_ctx->active_video_width = 0; + p_ctx->active_video_height = 0; + p_ctx->actual_video_width = 0; - return NI_RETCODE_SUCCESS; +END: + + ni_aligned_free(p_buffer); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + return retval; } -#endif -/* AI functions */ -ni_retcode_t ni_config_instance_network_binary(ni_session_context_t *p_ctx, - void *nb_data, uint32_t nb_size) +ni_retcode_t ni_ai_session_close(ni_session_context_t *p_ctx, int eos_recieved) { - void *p_ai_config = NULL; - void *p_nb_data = NULL; - uint32_t buffer_size; - // uint8_t *p_data; - // uint32_t transferred, this_size; ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t ui32LBA = 0; - uint32_t config_size; - int32_t retry_count = 0; void *p_buffer = NULL; - uint32_t dataLen; + uint32_t ui32LBA = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; + return NI_RETCODE_INVALID_PARAM; } + ni_pthread_mutex_lock(&p_ctx->mutex); + if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): Invalid session ID, return.\n", __func__); + retval = NI_RETCODE_SUCCESS; LRETURN; } - config_size = (sizeof(ni_ai_config_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & - ~(NI_MEM_PAGE_ALIGNMENT - 1); - if (ni_posix_memalign(&p_ai_config, sysconf(_SC_PAGESIZE), config_size)) + //malloc data buffer + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) { - ni_log(NI_LOG_ERROR, "ERROR: Cannot allocate ai config buffer.\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", + NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - ((ni_ai_config_t *)p_ai_config)->ui32NetworkBinarySize = nb_size; - ni_calculate_sha256(nb_data, nb_size, - ((ni_ai_config_t *)p_ai_config)->ui8Sha256); + ui32LBA = CLOSE_SESSION_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); - buffer_size = - (nb_size + (NI_MEM_PAGE_ALIGNMENT - 1)) & ~(NI_MEM_PAGE_ALIGNMENT - 1); - if (ni_posix_memalign(&p_nb_data, sysconf(_SC_PAGESIZE), buffer_size)) + int retry = 0; + while (retry < NI_SESSION_CLOSE_RETRY_MAX) { - ni_log(NI_LOG_ERROR, "ERROR: Cannot allocate encConf buffer.\n"); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; + ni_log2(p_ctx, NI_LOG_DEBUG, + "%s(): p_ctx->blk_io_handle=%" PRIx64 ", p_ctx->hw_id=%d, " + "p_ctx->session_id=%d, close_mode=1\n", + __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, + p_ctx->session_id); + + if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, NI_DATA_BUFFER_LEN, ui32LBA) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): command failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + p_ctx->session_id = NI_INVALID_SESSION_ID; + break; + } else + { + //Close should always succeed + retval = NI_RETCODE_SUCCESS; + p_ctx->session_id = NI_INVALID_SESSION_ID; + break; + } + /* + else if(((ni_session_closed_status_t *)p_buffer)->session_closed) + { + retval = NI_RETCODE_SUCCESS; + p_ctx->session_id = NI_INVALID_SESSION_ID; + break; + } + else + { + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): wait for close\n", __func__); + ni_usleep(NI_SESSION_CLOSE_RETRY_INTERVAL_US); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + } + */ + retry++; } - /* FIXME: can be avoided? */ - memcpy(p_nb_data, nb_data, nb_size); +END: - /* configure network binary size to be written */ - ui32LBA = CONFIG_INSTANCE_SetAiPara_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); - ni_log(NI_LOG_DEBUG, "%s(): LBA 0x%x, nb_size %u\n", __func__, ui32LBA, - nb_size); + ni_unreference_network_data(p_ctx->network_data); + ni_memfree(p_ctx->network_data); - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_ai_config, config_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS != retval) + ni_aligned_free(p_buffer); + ni_aligned_free(p_ctx->p_all_zero_buf); + + //Sequence change related stuff cleanup here + p_ctx->active_video_width = 0; + p_ctx->active_video_height = 0; + p_ctx->actual_video_width = 0; + + //End of sequence change related stuff cleanup + ni_buffer_pool_free(p_ctx->buffer_pool); + p_ctx->buffer_pool = NULL; + + ni_log2(p_ctx, NI_LOG_DEBUG, "%s(): CTX[Card:%" PRIx64 " / HW:%d / INST:%d]\n", + __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, + p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); + + return retval; +} + +ni_retcode_t ni_ai_multi_config_frame(ni_session_context_t *p_ctx, + ni_frame_config_t p_cfg_in[], + int numInCfgs, + ni_frame_config_t *p_cfg_out) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + ni_network_buffer_t *p_data = NULL; + void *p_read_data = NULL; + uint32_t dataLen; + uint32_t ui32LBA = 0; + + if (!p_ctx) { - ni_log(NI_LOG_ERROR, - "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - //Close the session since we can't configure it - retval = ni_ai_session_close(p_ctx, 0); - if (NI_RETCODE_SUCCESS != retval) + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } + + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + return NI_RETCODE_ERROR_INVALID_SESSION; + } + ni_pthread_mutex_lock(&p_ctx->mutex); + ni_instance_buf_info_t buf_info = {0}; + int32_t query_retry = 0; + for (;;) + { + if (p_ctx->session_statistic.ui32WrBufAvailSize > 0) { - ni_log(NI_LOG_ERROR, - "ERROR: ni_ai_session_close failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, - p_ctx->session_id); + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32WrBufAvailSize; + ni_log2(p_ctx, NI_LOG_DEBUG, + "Info ai write query success, available buf " + "size %u !\n", + buf_info.buf_avail_size); + break; } - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_AI, + &p_ctx->session_statistic); + CHECK_ERR_RC(p_ctx, retval, &p_ctx->session_statistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32WrBufAvailSize; + if (NI_RETCODE_SUCCESS != retval || + buf_info.buf_avail_size == 0) + { + ni_log2(p_ctx, NI_LOG_TRACE, + "AI write query failed or buf_size < frame_size. Retry %d\n", + query_retry); + // extend to 5000 retries for 8K encode on FPGA + if (query_retry >= NI_MAX_ENCODER_QUERY_RETRIES) + { + ni_log2(p_ctx, NI_LOG_TRACE, + "AI write query exceeded max retries: %d\n", + NI_MAX_ENCODER_QUERY_RETRIES); + p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; + retval = NI_RETCODE_SUCCESS; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); + query_retry++; + } } - /* test if the model is already exist. if not, then continue to write binary data */ - dataLen = (sizeof(ni_network_layer_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & - ~(NI_MEM_PAGE_ALIGNMENT - 1); - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) + dataLen = (sizeof(ni_network_buffer_t) + NI_MEM_PAGE_ALIGNMENT - 1) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + + if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR: Cannot allocate buffer.\n"); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; } - memset(p_buffer, 0, dataLen); - ui32LBA = QUERY_INSTANCE_NL_SIZE_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); - if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, dataLen, ui32LBA) < 0) + memset(p_data, 0x00, dataLen); + p_data->ui16Width = p_cfg_in[0].picture_width; + p_data->ui16Height = p_cfg_in[0].picture_height; + p_data->ui16Option = p_cfg_in[0].options; + p_data->ui8PoolSize = p_cfg_in[0].rgba_color; + p_data->ui8MultiIn = 1; + for(int i = 0; i < numInCfgs; i++){ + p_data->ui16FrameIdx[i] = p_cfg_in[i].frame_index; + ni_log2(p_ctx, NI_LOG_DEBUG, "Dev alloc frame[%d]: frame_index %u, hw=%d\n", + i,p_data->ui16FrameIdx[i], p_data->ui8MultiIn); + } + + + ui32LBA = + CONFIG_INSTANCE_SetAiFrm_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); + + retval = + ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_data, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), + OPT_1); + if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + ni_log2(p_ctx, + NI_LOG_ERROR, + "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed!\n", + __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } - if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size > 0) + END: + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_aligned_free(p_data); + if (p_read_data != NULL) { - ni_log(NI_LOG_DEBUG, "%s(): network binary registered\n", __func__); - LRETURN; + ni_aligned_free(p_read_data); } + return retval; +} -#if 1 - /* write network binary data */ - ui32LBA = WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); - ni_log(NI_LOG_DEBUG, "%s(): write nb LBA 0x%x\n", __func__, ui32LBA); - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_nb_data, buffer_size, ui32LBA); - ni_log(NI_LOG_DEBUG, "write complete retval %d\n", retval); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_write, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, - "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - //Close the session since we can't configure it - retval = ni_ai_session_close(p_ctx, 0); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, - "ERROR: ni_ai_session_close failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, - p_ctx->session_id); - } +ni_retcode_t ni_ai_alloc_dst_frame(ni_session_context_t *p_ctx, + niFrameSurface1_t *p_out_surface) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + ni_network_buffer_t *p_data = NULL; + void *p_read_data = NULL; + uint32_t dataLen; + uint32_t ui32LBA = 0; + + if (!p_ctx) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + __func__); + return NI_RETCODE_INVALID_PARAM; + } - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + if (p_ctx->session_id == NI_INVALID_SESSION_ID) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + return NI_RETCODE_ERROR_INVALID_SESSION; } -#else - ni_log(NI_LOG_DEBUG, "%s(): write nb buffer_size %u\n", __func__, - buffer_size); - for (transferred = 0; transferred < buffer_size; transferred += this_size) + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rL") < 0) { - this_size = p_ctx->max_nvme_io_size < (buffer_size - transferred) ? - p_ctx->max_nvme_io_size : - (buffer_size - transferred); + ni_log2(p_ctx, NI_LOG_ERROR, + "Error: %s function not supported on device with FW API version < 6rL\n", + __func__); + return NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION; + } - if (this_size & (4096 - 1)) + ni_pthread_mutex_lock(&p_ctx->mutex); + + int query_retry = 0; + dataLen = + (sizeof(ni_instance_buf_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_read_data, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_read_data, 0, dataLen); + + for (;;) + { + ui32LBA = QUERY_INSTANCE_HW_OUT_SIZE_R(p_ctx->session_id, + NI_DEVICE_TYPE_AI); + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_read_data, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), + OPT_1); + if (retval != NI_RETCODE_SUCCESS) { - this_size = (this_size + (4096 - 1)) & ~(4096 - 1); + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; } - /* write network binary data */ - ui32LBA = WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_AI) + - (transferred >> 12); - ni_log(NI_LOG_DEBUG, - "%s(): write nb LBA 0x%x, this_size %u, page_offset %u\n", - __func__, ui32LBA, this_size, (transferred >> 12)); - p_data = (uint8_t *)p_nb_data + transferred; - retval = ni_nvme_send_write_cmd( - p_ctx->blk_io_handle, p_ctx->event_handle, - (uint8_t *)p_nb_data + transferred, this_size, ui32LBA); - ni_log(NI_LOG_DEBUG, "%s(): write retval %d\n", __func__, retval); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_write, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS != retval) + + if (((ni_instance_buf_info_t *)p_read_data)->hw_inst_ind.buffer_avail > 0) { - ni_log( - NI_LOG_ERROR, - "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - //Close the session since we can't configure it - retval = ni_ai_session_close(p_ctx, 0); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log( - NI_LOG_ERROR, - "ERROR: ni_ai_session_close failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, - p_ctx->session_id); - } + p_out_surface->ui16FrameIdx = ((ni_instance_buf_info_t *)p_read_data)->hw_inst_ind.frame_index; + p_out_surface->ui16session_ID = p_ctx->session_id; + p_out_surface->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + p_out_surface->bit_depth = p_ctx->bit_depth_factor; + p_out_surface->src_cpu = (uint8_t)NI_DEVICE_TYPE_AI; + p_out_surface->output_idx = 0; + break; + } - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + query_retry++; + if (query_retry > 2000) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): exceeded max query retries: %d\n", + __func__, query_retry - 1); + retval = NI_RETCODE_EAGAIN; LRETURN; } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(200); + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; } -#endif - + if (((ni_instance_buf_info_t *)p_read_data)->hw_inst_ind.buffer_avail == 0) + { + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; + } END: - - ni_aligned_free(p_ai_config); - ni_aligned_free(p_nb_data); - ni_aligned_free(p_buffer); - - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); - + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_aligned_free(p_data); + if (p_read_data != NULL) + { + ni_aligned_free(p_read_data); + } return retval; } -ni_retcode_t ni_ai_session_write(ni_session_context_t *p_ctx, - ni_frame_t *p_frame) +ni_retcode_t ni_ai_alloc_hwframe(ni_session_context_t *p_ctx, int width, + int height, int options, int pool_size, + int frame_index) { ni_retcode_t retval = NI_RETCODE_SUCCESS; - int i = 0; + ni_network_buffer_t *p_data = NULL; + void *p_read_data = NULL; + uint32_t dataLen; uint32_t ui32LBA = 0; - ni_instance_buf_info_t buf_info = {0}; - uint32_t frame_size_bytes; - uint32_t sent_size = 0; - int32_t query_retry = 0; - int32_t query_count = 0; - - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); - if (!p_ctx || !p_frame) + if (!p_ctx) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): passed parameters is null\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; + return NI_RETCODE_INVALID_PARAM; } - if (p_frame->data_len[0] == 0) + if (p_ctx->session_id == NI_INVALID_SESSION_ID) { - ni_log(NI_LOG_ERROR, "ERROR: %s() invalid data length\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + __func__); + return NI_RETCODE_ERROR_INVALID_SESSION; } - if (NI_INVALID_SESSION_ID == p_ctx->session_id) + ni_pthread_mutex_lock(&p_ctx->mutex); + + if (options == NI_AI_FLAG_IO) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; - } + int query_retry = 0; + dataLen = + (sizeof(ni_instance_buf_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_read_data, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_read_data, 0, dataLen); - frame_size_bytes = p_frame->data_len[0]; - ni_log(NI_LOG_DEBUG, "%s(): frame_size_bytes %u\n", __func__, - frame_size_bytes); + for (;;) + { + ui32LBA = QUERY_INSTANCE_HW_OUT_SIZE_R(p_ctx->session_id, + NI_DEVICE_TYPE_AI); + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_read_data, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), + OPT_1); + if (retval != NI_RETCODE_SUCCESS) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + + if (((ni_instance_buf_info_t *)p_read_data)->buf_avail_size > 0) + { + break; + } + + query_retry++; + if (query_retry > 2000) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): exceeded max query retries: %d\n", + __func__, query_retry - 1); + retval = NI_RETCODE_EAGAIN; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(200); + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; + } - if (!p_frame->end_of_stream) + if (((ni_instance_buf_info_t *)p_read_data)->buf_avail_size == 0) + { + retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + LRETURN; + } + } else { + ni_instance_buf_info_t buf_info = {0}; + int32_t query_retry = 0; for (;;) { - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_WRITE, - NI_DEVICE_TYPE_AI, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, - &(p_ctx->session_id)); + if (p_ctx->session_statistic.ui32WrBufAvailSize > 0) + { + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32WrBufAvailSize; + ni_log2(p_ctx, NI_LOG_DEBUG, + "Info ai write query success, available buf " + "size %u !\n", + buf_info.buf_avail_size); + break; + } + retval = ni_query_session_statistic_info(p_ctx, NI_DEVICE_TYPE_AI, + &p_ctx->session_statistic); + CHECK_ERR_RC(p_ctx, retval, &p_ctx->session_statistic, + nvme_admin_cmd_xcoder_query, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_2); + buf_info.buf_avail_size = + p_ctx->session_statistic.ui32WrBufAvailSize; if (NI_RETCODE_SUCCESS != retval || - buf_info.buf_avail_size < frame_size_bytes) + buf_info.buf_avail_size == 0) { - - ni_log(NI_LOG_TRACE, "AI write query failed or buf_size < " - "frame_size. Retry %d\n", query_retry); + ni_log2(p_ctx, NI_LOG_TRACE, + "AI write query failed or buf_size < frame_size. Retry %d\n", + query_retry); // extend to 5000 retries for 8K encode on FPGA if (query_retry >= NI_MAX_ENCODER_QUERY_RETRIES) { - ni_log(NI_LOG_ERROR, - "ERROR: ai query buf info exceeding max retries: " - "%d, ", + ni_log2(p_ctx, NI_LOG_TRACE, + "AI write query exceeded max retries: %d\n", NI_MAX_ENCODER_QUERY_RETRIES); p_ctx->status = NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL; retval = NI_RETCODE_SUCCESS; LRETURN; } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(NI_RETRY_INTERVAL_100US); + ni_pthread_mutex_lock(&p_ctx->mutex); query_retry++; - ni_usleep(100); - } else - { - ni_log(NI_LOG_DEBUG, "Info ai write query success, available buf " - "size %u >= frame size %u !\n", - buf_info.buf_avail_size, frame_size_bytes); - break; } } - } - - ui32LBA = WRITE_INSTANCE_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); - ni_log(NI_LOG_DEBUG, "Ai session write: p_data = %p, p_frame->buffer_size = %u, " - "p_ctx->frame_num = %" PRIu64 ", LBA = 0x%x\n", - p_frame->p_data, p_frame->buffer_size, p_ctx->frame_num, - ui32LBA); - sent_size = frame_size_bytes; - if (sent_size & (NI_MEM_PAGE_ALIGNMENT - 1)) - { - sent_size = (sent_size + NI_MEM_PAGE_ALIGNMENT - 1) & + dataLen = (sizeof(ni_network_buffer_t) + NI_MEM_PAGE_ALIGNMENT - 1) & ~(NI_MEM_PAGE_ALIGNMENT - 1); - } - - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_frame->p_buffer, sent_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_write, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - if (retval < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; - } - p_ctx->frame_num++; + if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + return NI_RETCODE_ERROR_MEM_ALOC; + } - retval = frame_size_bytes; + memset(p_data, 0x00, dataLen); + p_data->ui16FrameIdx[0] = frame_index; + p_data->ui16Width = width; + p_data->ui16Height = height; + p_data->ui16Option = options; + p_data->ui8PoolSize = pool_size; + p_data->ui8MultiIn = 0; + ni_log2(p_ctx, NI_LOG_DEBUG, "Dev alloc frame: frame_index %u\n", + p_data->ui16FrameIdx[0]); -END: + ui32LBA = + CONFIG_INSTANCE_SetAiFrm_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + retval = + ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_data, dataLen, ui32LBA); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_config, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), + OPT_1); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log2(p_ctx, + NI_LOG_ERROR, + "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 + ", hw_id, %u, xcoder_inst_id: %d\n", + (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): nvme command failed!\n", + __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } + } +END: + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_aligned_free(p_data); + if (p_read_data != NULL) + { + ni_aligned_free(p_read_data); + } return retval; } -ni_retcode_t ni_ai_session_read(ni_session_context_t *p_ctx, - ni_packet_t *p_packet) +/*!****************************************************************************** + * \brief read a hardware descriptor from a scaler session + * + * \param[in] p_ctx pointer to session context + * \param[out] p_frame pointer to frame to write hw descriptor + * + * \return NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_INVALID_SESSION + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + * NI_RETCODE_FAILURE + *******************************************************************************/ +ni_retcode_t ni_ai_session_read_hwdesc(ni_session_context_t *p_ctx, + ni_frame_t *p_frame) { - uint32_t actual_read_size = 0; - uint8_t *p_data = NULL; int retval = NI_RETCODE_SUCCESS; - uint32_t ui32LBA = 0; - ni_instance_buf_info_t buf_info = {0}; int retry_count = 0; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); - if (!p_ctx || !p_packet || !p_packet->p_data) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } + ni_pthread_mutex_lock(&p_ctx->mutex); if (NI_INVALID_SESSION_ID == p_ctx->session_id) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", __func__); retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; @@ -10962,590 +15692,683 @@ ni_retcode_t ni_ai_session_read(ni_session_context_t *p_ctx, for (;;) { - retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_READ, - NI_DEVICE_TYPE_AI, &buf_info); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_query, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - - ni_log(NI_LOG_DEBUG, "Info ai read query rc %d, available buf size %u, " - "frame_num=%" PRIu64 ", pkt_num=%" PRIu64 "\n", - retval, buf_info.buf_avail_size, p_ctx->frame_num, - p_ctx->pkt_num); + retry_count++; + ni_instance_buf_info_t sInstanceBuf = {0}; + niFrameSurface1_t *pFrameSurface; + retval = ni_query_instance_buf_info(p_ctx, INST_BUF_INFO_RW_READ_BY_AI, + NI_DEVICE_TYPE_AI, &sInstanceBuf); + CHECK_ERR_RC(p_ctx, retval, 0, nvme_admin_cmd_xcoder_query, + p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id), + OPT_3); - if (NI_RETCODE_SUCCESS != retval) + if (retval == NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE) { - ni_log(NI_LOG_DEBUG, "Buffer info query failed in ai read!!!!\n"); - LRETURN; - } else if (0 == buf_info.buf_avail_size) + if (retry_count >= 500) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning hwdesc read fail rc %d\n", + retval); + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(100); + ni_pthread_mutex_lock(&p_ctx->mutex); + } + else if (retval != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_DEBUG, "Info ai read available buf size %u, eos %u !\n", - buf_info.buf_avail_size, p_packet->end_of_stream); - retval = NI_RETCODE_SUCCESS; LRETURN; } else { - break; - } - } - ni_log(NI_LOG_DEBUG, "Ai read buf_avail_size %u\n", buf_info.buf_avail_size); - - assert(buf_info.buf_avail_size == p_packet->data_len); - - ui32LBA = READ_INSTANCE_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); - actual_read_size = buf_info.buf_avail_size; - if (actual_read_size & (NI_MEM_PAGE_ALIGNMENT - 1)) - { - actual_read_size = (actual_read_size + (NI_MEM_PAGE_ALIGNMENT - 1)) & - ~(NI_MEM_PAGE_ALIGNMENT - 1); - } - - retval = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_packet->p_data, actual_read_size, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_cmd_xcoder_read, p_ctx->device_type, - p_ctx->hw_id, &(p_ctx->session_id)); - if (retval < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; - } + pFrameSurface = (niFrameSurface1_t *)p_frame->p_data[3]; + pFrameSurface->ui16FrameIdx = sInstanceBuf.hw_inst_ind.frame_index; + pFrameSurface->ui16session_ID = p_ctx->session_id; + pFrameSurface->device_handle = + (int32_t)((int64_t)p_ctx->blk_io_handle & 0xFFFFFFFF); + pFrameSurface->src_cpu = (uint8_t)NI_DEVICE_TYPE_AI; + pFrameSurface->output_idx = 0; - retval = p_packet->data_len; + /* A frame index of zero is invalid, the memory acquisition failed */ + if (pFrameSurface->ui16FrameIdx == 0) + { + if (retry_count >= 500) + { + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning hwdesc read fail rc %d\n", + retval); + retval = NI_RETCODE_EAGAIN; + LRETURN; + } + ni_pthread_mutex_unlock(&p_ctx->mutex); + ni_usleep(100); + ni_pthread_mutex_lock(&p_ctx->mutex); + continue; + } + LRETURN; + } + } END: - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_pthread_mutex_unlock(&p_ctx->mutex); + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); return retval; } -ni_retcode_t ni_config_read_inout_layers(ni_session_context_t *p_ctx, - ni_network_data_t *p_network) +/*!***************************************************************************** + * \brief Get DDR configuration of Quadra device + * + * \param[in/out] p_ctx pointer to a session context with valid file handle + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_get_ddr_configuration(ni_session_context_t *p_ctx) { void *p_buffer = NULL; - void *p_info = NULL; + ni_nvme_identity_t *p_id_data; ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t ui32LBA = 0; - uint32_t dataLen; - int32_t query_retry = 0; - int l; - uint32_t offset = 0; - ni_network_layer_params_t *layer_param; - uint32_t buffer_size; - uint32_t this_size; + ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; + uint32_t ui32LBA = IDENTIFY_DEVICE_R; + ni_device_handle_t device_handle = p_ctx->blk_io_handle; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); - if (!p_ctx || !p_network) + if (NI_INVALID_DEVICE_HANDLE == device_handle) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid passed parameters\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } - /* query available size can be read. */ - dataLen = (sizeof(ni_network_layer_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & - ~(NI_MEM_PAGE_ALIGNMENT - 1); - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), + NI_NVME_IDENTITY_CMD_DATA_SZ)) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer.\n", NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } - memset(p_buffer, 0, dataLen); - - for (;;) - { - ui32LBA = - QUERY_INSTANCE_NL_SIZE_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); - if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, dataLen, ui32LBA) < 0) - { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; - } - - if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size > 0) - { - break; - } - - query_retry++; - if (query_retry > 10000) - { - ni_log(NI_LOG_DEBUG, "%s: query retry exceeds\n", __func__); - } - ni_usleep(200); - continue; - } - - if (((ni_instance_buf_info_t *)p_buffer)->buf_avail_size == 0) - { - retval = NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; - LRETURN; - } - assert(((ni_instance_buf_info_t *)p_buffer)->buf_avail_size == - sizeof(ni_network_layer_info_t)); - - /* query the real network layer data */ - dataLen = (sizeof(ni_network_layer_info_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & - ~(NI_MEM_PAGE_ALIGNMENT - 1); - if (ni_posix_memalign(&p_info, sysconf(_SC_PAGESIZE), dataLen)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate info buffer\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; - } - memset(p_info, 0, dataLen); + memset(p_buffer, 0, NI_NVME_IDENTITY_CMD_DATA_SZ); - ui32LBA = QUERY_INSTANCE_NL_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); - if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_info, dataLen, ui32LBA) < 0) + if (ni_nvme_send_read_cmd(device_handle, event_handle, p_buffer, + NI_NVME_IDENTITY_CMD_DATA_SZ, ui32LBA) < 0) { - ni_log(NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } - p_network->linfo = *((ni_network_layer_info_t *)p_info); + p_id_data = (ni_nvme_identity_t *) p_buffer; - for (l = 0, p_network->input_num = 0, buffer_size = 0; - l < NI_MAX_NETWORK_INPUT_NUM; l++) + if (p_id_data->memory_cfg == NI_QUADRA_MEMORY_CONFIG_SR_4G) { - layer_param = &p_network->linfo.in_param[l]; - if (layer_param->num_of_dims == 0) - { - break; - } - this_size = ni_ai_network_layer_size(layer_param); - this_size = - (this_size + NI_AI_HW_ALIGN_SIZE - 1) & ~(NI_AI_HW_ALIGN_SIZE - 1); - p_network->inset[l].offset = buffer_size; - buffer_size += this_size; - - p_network->input_num++; - ni_log( - NI_LOG_DEBUG, - "%s(): network input layer %d: dims %u, %u/%u/%u/%u, f %d, q %d\n", - __func__, l, layer_param->num_of_dims, layer_param->sizes[0], - layer_param->sizes[1], layer_param->sizes[2], layer_param->sizes[3], - layer_param->data_format, layer_param->quant_format); + p_ctx->ddr_config = 6; } - - for (l = 0, p_network->output_num = 0, buffer_size = 0; - l < NI_MAX_NETWORK_OUTPUT_NUM; l++) + else { - layer_param = &p_network->linfo.out_param[l]; - if (layer_param->num_of_dims == 0) - { - break; - } - this_size = ni_ai_network_layer_size(layer_param); - this_size = - (this_size + NI_AI_HW_ALIGN_SIZE - 1) & ~(NI_AI_HW_ALIGN_SIZE - 1); - p_network->outset[l].offset = buffer_size; - buffer_size += this_size; - - p_network->output_num++; - ni_log( - NI_LOG_DEBUG, - "%s(): network output layer %d: dims %u, %u/%u/%u/%u, f %d, q %d\n", - __func__, l, layer_param->num_of_dims, layer_param->sizes[0], - layer_param->sizes[1], layer_param->sizes[2], layer_param->sizes[3], - layer_param->data_format, layer_param->quant_format); - } - - retval = NI_RETCODE_SUCCESS; - + if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rJ") >= 0) + { + p_ctx->ddr_config = (p_id_data->memory_cfg == NI_QUADRA_MEMORY_CONFIG_SR) + ? 3 : ((p_id_data->memory_cfg == NI_QUADRA_MEMORY_CONFIG_DR)? 4 : 5); + } + else if (ni_cmp_fw_api_ver( + (char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6rD") >= 0) + { + p_ctx->ddr_config = (p_id_data->memory_cfg == NI_QUADRA_MEMORY_CONFIG_SR) + ? 3 : 4; + } else + { + p_ctx->ddr_config = (p_id_data->memory_cfg == NI_QUADRA_MEMORY_CONFIG_SR) + ? 1 : 2; + } + } + + ni_log2(p_ctx, NI_LOG_DEBUG, "Memory configuration %d\n",p_ctx->ddr_config); END: ni_aligned_free(p_buffer); - ni_aligned_free(p_info); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): retval: %d\n", __func__, retval); + return retval; } -ni_retcode_t ni_ai_session_open(ni_session_context_t *p_ctx) +/*!***************************************************************************** + * \brief Set DDR configuration of Quadra device + * + * \param[in] p_ctx pointer to a session context with valid file handle + * \param[in] ddr_priority_mode ddr priority mode + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_set_ddr_configuration(ni_session_context_t *p_ctx, + uint8_t ddr_priority_mode) { - ni_retcode_t retval = NI_RETCODE_SUCCESS; - uint32_t buffer_size = 0; void *p_buffer = NULL; - uint32_t ui32LBA = 0; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + ni_ddr_priority_config_t *p_cfg = NULL; + uint32_t ui32LBA = CONFIG_SESSION_DDR_PRIORITY_W(p_ctx->session_id); + ni_device_handle_t device_handle = p_ctx->blk_io_handle; - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + + ni_log2(p_ctx, NI_LOG_INFO, "set ddr priority %d\n", + ddr_priority_mode); - if (!p_ctx) + if (NI_INVALID_DEVICE_HANDLE == device_handle) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid passed parameters\n", __func__); retval = NI_RETCODE_INVALID_PARAM; LRETURN; } - //Check if there is an instance or we need a new one - if (NI_INVALID_SESSION_ID == p_ctx->session_id) + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), + NI_NVME_IDENTITY_CMD_DATA_SZ)) { - p_ctx->device_type = NI_DEVICE_TYPE_AI; - p_ctx->pts_table = NULL; - p_ctx->dts_queue = NULL; - p_ctx->buffer_pool = NULL; - p_ctx->status = 0; - p_ctx->key_frame_type = 0; - p_ctx->keyframe_factor = 1; - p_ctx->frame_num = 0; - p_ctx->pkt_num = 0; - p_ctx->rc_error_count = 0; - p_ctx->force_frame_type = 0; - p_ctx->ready_to_close = 0; - //Sequence change tracking reated stuff - p_ctx->active_video_width = 0; - p_ctx->active_video_height = 0; - p_ctx->p_all_zero_buf = NULL; - p_ctx->actual_video_width = 0; - p_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; - - memset(&(p_ctx->param_err_msg[0]), 0, sizeof(p_ctx->param_err_msg)); + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } - //malloc zero data buffer - if (ni_posix_memalign(&p_ctx->p_all_zero_buf, sysconf(_SC_PAGESIZE), - NI_DATA_BUFFER_LEN)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc all zero buffer failed\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; - } - memset(p_ctx->p_all_zero_buf, 0, NI_DATA_BUFFER_LEN); + memset(p_buffer, 0, NI_NVME_IDENTITY_CMD_DATA_SZ); + p_cfg = (ni_ddr_priority_config_t *)p_buffer; + p_cfg->ddr_mode = ddr_priority_mode; + if (ni_nvme_send_write_cmd(p_ctx->blk_io_handle, NI_INVALID_EVENT_HANDLE, + p_buffer,NI_DATA_BUFFER_LEN, ui32LBA) < 0) + { + ni_log2(p_ctx, NI_LOG_ERROR, "DDR priority setting failed with mode %d\n", + ddr_priority_mode); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; + } +END: + ni_aligned_free(p_buffer); + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): retval: %d\n", __func__, retval); - //malloc data buffer - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), - NI_DATA_BUFFER_LEN)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; - } - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); + return retval; +} - //Set session ID to be invalid. In case we cannot open session, the session id wold remain invalid. - //In case we can open sesison, the session id would become valid. - ((ni_session_stats_t *)p_buffer)->ui16SessionId = - (uint16_t)NI_INVALID_SESSION_ID; +/*!***************************************************************************** + * \brief Allocate memory for the metadata header and auxillary data for + * encoder input data. + * + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct + * + * \param[in] extra_len Length header and auxillary data + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + *****************************************************************************/ +ni_retcode_t ni_encoder_metadata_buffer_alloc(ni_frame_t *p_frame, + int extra_len) +{ + void *metadata_buffer = NULL; + int retval = NI_RETCODE_SUCCESS; - // First uint32_t is either an invaild session ID or a valid session ID, depending on if session could be opened - ui32LBA = OPEN_SESSION_CODEC(NI_DEVICE_TYPE_AI, 0, p_ctx->hw_action); - ni_log(NI_LOG_DEBUG, "%s(): LBA 0x%x, hw_action %d\n", __func__, - ui32LBA, p_ctx->hw_action); - retval = - ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - if (retval != NI_RETCODE_SUCCESS) - { - ni_log(NI_LOG_ERROR, "ERROR ni_nvme_send_read_cmd\n"); - LRETURN; - } - //Open will return a session status structure with a valid session id if it worked. - //Otherwise the invalid session id set before the open command will stay - if ((uint16_t)NI_INVALID_SESSION_ID == - ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId)) - { - ni_log(NI_LOG_ERROR, - "ERROR %s(): p_ctx->device_handle=%" PRIx64 - ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); - ni_ai_session_close(p_ctx, 0); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; - } - p_ctx->session_id = - ni_ntohs(((ni_session_stats_t *)p_buffer)->ui16SessionId); - p_ctx->session_timestamp = - ni_htonll(((ni_session_stats_t *)p_buffer)->ui64Session_timestamp); - ni_log(NI_LOG_DEBUG, "Ai open session ID:0x%x,timestamp:%" PRIu64 "\n", - p_ctx->session_id, p_ctx->session_timestamp); + if ((!p_frame) || (extra_len <= 0)) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s passed parameters are null or not supported, " + "p_frame %p, extra_len %d", + __func__, p_frame, extra_len); + return NI_RETCODE_INVALID_PARAM; + } - ni_log(NI_LOG_DEBUG, "Open session completed\n"); - ni_log(NI_LOG_DEBUG, - "%s(): p_ctx->device_handle=%" PRIx64 - ", p_ctx->hw_id=%d, p_ctx->session_id=%d\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); + int buffer_size = extra_len; + if (buffer_size % NI_MEM_PAGE_ALIGNMENT) + { + buffer_size = ((buffer_size / NI_MEM_PAGE_ALIGNMENT) + 1) * + NI_MEM_PAGE_ALIGNMENT; + } - //Send keep alive timeout Info - uint64_t keep_alive_timeout = - p_ctx->keep_alive_timeout * 1000000; //send us to FW - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - memcpy(p_buffer, &keep_alive_timeout, sizeof(keep_alive_timeout)); - ni_log(NI_LOG_DEBUG, "%s keep_alive_timeout %" PRIx64 "\n", __func__, - keep_alive_timeout); - ui32LBA = CONFIG_SESSION_KeepAliveTimeout_W(p_ctx->session_id); - retval = - ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, NI_DATA_BUFFER_LEN, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - CHECK_VPU_RECOVERY(retval); + // Check if previous metadata buffer needs to be freed + if ((p_frame->metadata_buffer_size != buffer_size) && + (p_frame->metadata_buffer_size > 0)) + { + ni_log(NI_LOG_DEBUG, + "%s: free current p_frame metadata buffer, " + "p_frame->buffer_size=%u\n", + __func__, p_frame->metadata_buffer_size); + p_frame->metadata_buffer_size = 0; + ni_aligned_free(p_frame->p_metadata_buffer); + } - if (NI_RETCODE_SUCCESS != retval) + // Check if new metadata buffer needs to be allocated + if (p_frame->metadata_buffer_size != buffer_size) + { + if (ni_posix_memalign(&metadata_buffer, sysconf(_SC_PAGESIZE), + buffer_size)) { ni_log(NI_LOG_ERROR, - "ERROR %s(): nvme write keep_alive_timeout command " - "failed, blk_io_handle: %" PRIx64 ", hw_id, %d\n", - __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + "ERROR %d: %s() Cannot allocate metadata buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } + + // init once after allocation + memset(metadata_buffer, 0, buffer_size); + p_frame->metadata_buffer_size = buffer_size; + p_frame->p_metadata_buffer = metadata_buffer; + + ni_log(NI_LOG_DEBUG, "%s: allocated new metadata buffer\n", __func__); + } else + { + ni_log(NI_LOG_DEBUG, "%s: reuse metadata buffer\n", __func__); } - // init for frame pts calculation - p_ctx->is_first_frame = 1; - p_ctx->last_pts = 0; - p_ctx->last_dts = 0; - p_ctx->active_video_width = 0; - p_ctx->active_video_height = 0; - p_ctx->actual_video_width = 0; + ni_log(NI_LOG_DEBUG, + "%s: success: p_frame->p_metadata_buffer %p " + "p_frame->metadata_buffer_size=%u\n", + __func__, p_frame->p_metadata_buffer, p_frame->metadata_buffer_size); END: - ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); + if (NI_RETCODE_SUCCESS != retval) + { + ni_aligned_free(metadata_buffer); + } + return retval; } -ni_retcode_t ni_ai_session_close(ni_session_context_t *p_ctx, int eos_recieved) +/*!***************************************************************************** + * \brief Allocate memory for the non-4k-aligned part at the start of YUV data for + * encoder input data. + * + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct + * + * \param[in] start_len Length of non-4k-aligned part at the start of YUV data + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + *****************************************************************************/ +ni_retcode_t ni_encoder_start_buffer_alloc(ni_frame_t *p_frame) { - ni_retcode_t retval = NI_RETCODE_SUCCESS; - void *p_buffer = NULL; - uint32_t ui32LBA = 0; - int counter = 0; - int ret = 0; - - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + void *start_buffer = NULL; + int retval = NI_RETCODE_SUCCESS; - if (!p_ctx) + if (!p_frame) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); + ni_log(NI_LOG_ERROR, + "ERROR: %s passed parameters are null or not supported, " + "p_frame %p\n", + __func__, p_frame); return NI_RETCODE_INVALID_PARAM; } - if (NI_INVALID_SESSION_ID == p_ctx->session_id) + // Check if new start buffer needs to be allocated + if (!p_frame->start_buffer_size) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - retval = NI_RETCODE_ERROR_INVALID_SESSION; - LRETURN; + if (ni_posix_memalign(&start_buffer, sysconf(_SC_PAGESIZE), + NI_MEM_PAGE_ALIGNMENT*NI_MAX_NUM_SW_FRAME_DATA_POINTERS)) + { + ni_log(NI_LOG_ERROR, + "ERROR %d: %s() Cannot allocate start buffer.\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + + // init once after allocation + memset(start_buffer, 0, NI_MEM_PAGE_ALIGNMENT*NI_MAX_NUM_SW_FRAME_DATA_POINTERS); + p_frame->start_buffer_size = NI_MEM_PAGE_ALIGNMENT*NI_MAX_NUM_SW_FRAME_DATA_POINTERS; + p_frame->p_start_buffer = start_buffer; + + ni_log(NI_LOG_DEBUG, "%s: allocated new start buffer\n", __func__); + } else + { + ni_log(NI_LOG_DEBUG, "%s: reuse start buffer\n", __func__); } - //malloc data buffer - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN)) + ni_log(NI_LOG_DEBUG, + "%s: success: p_frame->p_start_buffer %p " + "p_frame->start_buffer_size=%u\n", + __func__, p_frame->p_start_buffer, p_frame->start_buffer_size); + +END: + + if (NI_RETCODE_SUCCESS != retval) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc data buffer failed\n", - NI_ERRNO, __func__); - retval = NI_RETCODE_ERROR_MEM_ALOC; - LRETURN; + ni_aligned_free(start_buffer); } - memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - ui32LBA = CLOSE_SESSION_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + return retval; +} - int retry = 0; - while (retry < NI_SESSION_CLOSE_RETRY_MAX) +ni_retcode_t ni_ai_session_query_metrics(ni_session_context_t *p_ctx, + ni_network_perf_metrics_t *p_metrics) +{ + ni_retcode_t retval = NI_RETCODE_SUCCESS; + void *p_buffer = NULL; + uint32_t dataLen; + uint32_t ui32LBA = 0; + + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): enter\n", __func__); + if (!p_ctx || !p_metrics) { - ni_log(NI_LOG_DEBUG, - "%s(): p_ctx->blk_io_handle=%" PRIx64 ", p_ctx->hw_id=%d, " - "p_ctx->session_id=%d, close_mode=1\n", - __func__, (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, - p_ctx->session_id); + ni_log2(p_ctx, NI_LOG_ERROR, + "ERROR: %s() passed parameters are null!, return\n", __func__); + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; + } - if (ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_buffer, NI_DATA_BUFFER_LEN, ui32LBA) < 0) + if (ni_cmp_fw_api_ver((char*) &p_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6N") >= 0) + { + dataLen = + (sizeof(ni_network_perf_metrics_t) + (NI_MEM_PAGE_ALIGNMENT - 1)) & + ~(NI_MEM_PAGE_ALIGNMENT - 1); + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), dataLen)) { - ni_log(NI_LOG_ERROR, "ERROR %s(): command failed\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - break; - } else + ni_log2(p_ctx, NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", + NI_ERRNO, __func__); + retval = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(p_buffer, 0, sizeof(ni_network_perf_metrics_t)); + + ui32LBA = + QUERY_INSTANCE_METRICS_R(p_ctx->session_id, NI_DEVICE_TYPE_AI); + retval = + ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, + p_buffer, dataLen, ui32LBA); + if ((int32_t)retval != NI_RETCODE_SUCCESS) { - //Close should always succeed - retval = NI_RETCODE_SUCCESS; - p_ctx->session_id = NI_INVALID_SESSION_ID; - break; + ni_log2(p_ctx, NI_LOG_ERROR, "%s(): NVME command Failed\n", __func__); + retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; + LRETURN; } - /* - else if(((ni_session_closed_status_t *)p_buffer)->session_closed) - { - retval = NI_RETCODE_SUCCESS; - p_ctx->session_id = NI_INVALID_SESSION_ID; - break; - } - else + CHECK_ERR_RC(p_ctx, retval, 0, nvme_cmd_xcoder_read, p_ctx->device_type, + p_ctx->hw_id, &(p_ctx->session_id), OPT_1); + + *p_metrics = *((ni_network_perf_metrics_t *)p_buffer); + } else { - ni_log(NI_LOG_DEBUG, "%s(): wait for close\n", __func__); - ni_usleep(NI_SESSION_CLOSE_RETRY_INTERVAL_US); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - } - */ - retry++; + p_metrics->total_cycles = (uint32_t)(-1); + p_metrics->total_idle_cycles = (uint32_t)(-1); } - END: ni_aligned_free(p_buffer); - ni_aligned_free(p_ctx->p_all_zero_buf); - - //Sequence change related stuff cleanup here - p_ctx->active_video_width = 0; - p_ctx->active_video_height = 0; - p_ctx->actual_video_width = 0; + ni_log2(p_ctx, NI_LOG_TRACE, "%s(): exit\n", __func__); - //End of sequence change related stuff cleanup - ni_buffer_pool_free(p_ctx->buffer_pool); - p_ctx->buffer_pool = NULL; + return retval; +} - ni_log(NI_LOG_DEBUG, "%s(): CTX[Card:%" PRIx64 " / HW:%d / INST:%d]\n", - __func__, (int64_t)p_ctx->device_handle, p_ctx->hw_id, - p_ctx->session_id); - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); +/*!***************************************************************************** + * \brief Send namespace num / Opmode and SRIOv index/value to the device with + * specified logic block address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] Key Represents either namespace num or opmode + * \param[in] Value Represents either SRIOv index or opmode value + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_config_ns_qos(ni_device_handle_t device_handle, + uint32_t key, + uint32_t value) +{ + char buf[NI_DATA_BUFFER_LEN] = {'\0'}; + buf[0] = (uint8_t)key; + buf[1] = (uint8_t)value; + // event handle could be ignored + return ni_nvme_send_write_cmd(device_handle, NI_INVALID_EVENT_HANDLE, + (void *)buf, NI_DATA_BUFFER_LEN, + CONFIG_GLOBAL_NAMESPACE_NUM); +} -#ifdef XCODER_DUMP_ENABLED - if (p_ctx->p_dump[0]) +char *ni_get_core_name(ni_core_type_t eCoreType) +{ + char *CoreName; + switch (eCoreType) { - fclose(p_ctx->p_dump[0]); - p_ctx->p_dump[0] = NULL; + case ALL_CORE: + CoreName = (char *)"all"; + break; + case NVME_CORE: + CoreName = (char *)"np"; + break; + case EP_CORE: + CoreName = (char *)"ep"; + break; + case DP_CORE: + CoreName = (char *)"dp"; + break; + case TP_CORE: + CoreName = (char *)"tp"; + break; + case FP_CORE: + CoreName = (char *)"fp"; + break; + default: + CoreName = (char *)"Not Found"; + break; } - if (p_ctx->p_dump[1]) + return CoreName; +} + +uint32_t ni_get_log_lba(ni_core_type_t eCoreType) +{ + uint32_t lba; + switch (eCoreType) { - fclose(p_ctx->p_dump[1]); - p_ctx->p_dump[1] = NULL; + case NVME_CORE: + lba = NVME_LOG_OFFSET_IN_4K; + break; + case EP_CORE: + lba = EP_LOG_OFFSET_IN_4K; + break; + case DP_CORE: + lba = DP_LOG_OFFSET_IN_4K; + break; + case TP_CORE: + lba = TP_LOG_OFFSET_IN_4K; + break; + case FP_CORE: + lba = FP_LOG_OFFSET_IN_4K; + break; + default: + ni_log(NI_LOG_ERROR, "%s:() Invalid core ID:%u\n", __func__, eCoreType); + lba = 0; + break; } -#endif - ni_log(NI_LOG_TRACE, "%s(): exit\n", __func__); - - return retval; + return lba; } -ni_retcode_t ni_ai_alloc_hwframe(ni_session_context_t *p_ctx, int frame_index) +ni_retcode_t ni_dump_log_single_core(ni_session_context_t *p_ctx, void* p_data, uint32_t core_id, bool gen_log_file) { + int32_t rc; + uint32_t lba = 0; + uint32_t data_len = CPU_LOG_BUFFER_SIZE; + char *core_name = NULL; + FILE *p_file = NULL; ni_retcode_t retval = NI_RETCODE_SUCCESS; - ni_network_buffer_t *p_data = NULL; - uint32_t dataLen; - uint32_t ui32LBA = 0; - if (!p_ctx) + if (!p_ctx || !p_data) { - ni_log(NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n", - __func__); + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: ERROR invalid pointer p_ctx %p p_data %p\n", + __func__, __LINE__, p_ctx, p_data); return NI_RETCODE_INVALID_PARAM; } - if (p_ctx->session_id == NI_INVALID_SESSION_ID) + memset(p_data, 0, CPU_LOG_BUFFER_SIZE); + *(uint8_t *)p_data = 0x55; + + lba = ni_get_log_lba((ni_core_type_t)core_id); + if (lba == 0) { - ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID, return.\n", - __func__); - return NI_RETCODE_ERROR_INVALID_SESSION; + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: ERROR core_id %u\n", + __func__, __LINE__, core_id); + return NI_RETCODE_INVALID_PARAM; } - dataLen = (sizeof(ni_network_buffer_t) + NI_MEM_PAGE_ALIGNMENT - 1) & - ~(NI_MEM_PAGE_ALIGNMENT - 1); + core_name = ni_get_core_name((ni_core_type_t)core_id); - if (ni_posix_memalign((void **)&p_data, sysconf(_SC_PAGESIZE), dataLen)) + rc = ni_nvme_send_read_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, p_data, data_len, lba); + + if (rc != NI_RETCODE_SUCCESS) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer\n", - NI_ERRNO, __func__); - return NI_RETCODE_ERROR_MEM_ALOC; + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: ERROR %d: nvme read %s core failed\n", + __func__, __LINE__, rc, core_name); + } + else if (gen_log_file) + { + //generate log file e.g. raw_dp_slot_0_0000.bin + char filename[32] = "raw_"; + strcat(filename, core_name); + strcat(filename, "_slot_"); + bool pcie_id_name = false; + char devFilePath[1024] = {0}; +#ifdef __linux__ + char devFDPath[1024] = {0}; + char pcie[64] = {0}; + char domain[5] = {0}, slot[3] = {0}, dev[3] = {0}, func[2] = {0}; + //p_ctx->blk_dev_name might be empty so look up the file name + snprintf(devFDPath, sizeof(devFDPath), "/proc/self/fd/%d", p_ctx->blk_io_handle); + ssize_t len = readlink(devFDPath, devFilePath, sizeof(devFilePath)-1); + if (len != -1) { + devFilePath[len] = '\0'; + } + if (strstr(devFilePath, "/dev/nvme") != NULL) + { + get_dev_pcie_addr(devFilePath, pcie, domain, slot, dev, func); + if (strlen(pcie) > 0 && strlen(slot) > 0 && strlen(domain) > 0) + { + strcat(filename, slot); + strcat(filename, "_"); + strcat(filename, domain); + pcie_id_name = true; + } + } +#endif + if (!pcie_id_name) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: For dev %d can't look up PCI domain and slot info. Defaulting to slot=hw_id and domain=0000\n", + __func__, __LINE__, p_ctx->blk_io_handle); + char num[4] = {0}; + snprintf(num, 4, "%d", p_ctx->hw_id); + strcat(filename, num); + strcat(filename, "_0000"); + } + strcat(filename, ".bin"); + ni_log2(p_ctx, NI_LOG_INFO, "For dev %d %s core %s creating file %s\n", + p_ctx->blk_io_handle, devFilePath, core_name, filename); + p_file = fopen(filename, "wb"); + if (p_file) + { + /* Write out the stream header */ + if (fwrite((uint8_t *)p_data , + data_len, 1, p_file) != 1) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: Error: writing data %u bytes error!\n", + __func__, __LINE__, data_len); + ni_log2(p_ctx, NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + retval = NI_RETCODE_FAILURE; + } + if (fflush(p_file)) + { + ni_log2(p_ctx, NI_LOG_ERROR, "Error: writing data frame flush failed! errno %d\n", + ferror(p_file)); + retval = NI_RETCODE_FAILURE; + } + fclose(p_file); + } + else + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: Error: cannot open %s\n", + __func__, __LINE__, filename); + retval = NI_RETCODE_FAILURE; + } } - // memset(p_data, 0x00, dataLen); - p_data->ui32Address = frame_index; + return retval; +} - ni_log(NI_LOG_DEBUG, "Dev alloc frame: frame_index %u\n", p_data->ui32Address); +ni_retcode_t ni_dump_log_all_cores(ni_session_context_t *p_ctx, void* p_data, bool gen_log_file) +{ + int i = 1; - ui32LBA = CONFIG_INSTANCE_SetAiFrm_W(p_ctx->session_id, NI_DEVICE_TYPE_AI); + if (!p_ctx || !p_data) + { + ni_log2(p_ctx, NI_LOG_ERROR, "%s:():%d: ERROR invalid pointer p_ctx %p p_data %p\n", + __func__, __LINE__, p_ctx, p_data); + return NI_RETCODE_INVALID_PARAM; + } - retval = ni_nvme_send_write_cmd(p_ctx->blk_io_handle, p_ctx->event_handle, - p_data, dataLen, ui32LBA); - CHECK_ERR_RC(p_ctx, retval, nvme_admin_cmd_xcoder_config, - p_ctx->device_type, p_ctx->hw_id, &(p_ctx->session_id)); - if (NI_RETCODE_SUCCESS != retval) + for (i = NVME_CORE; i< NUM_OF_CORES; i++) { - ni_log(NI_LOG_ERROR, - "ERROR: ni_nvme_send_admin_cmd failed: blk_io_handle: %" PRIx64 - ", hw_id, %u, xcoder_inst_id: %d\n", - (int64_t)p_ctx->blk_io_handle, p_ctx->hw_id, p_ctx->session_id); - ni_log(NI_LOG_ERROR, "ERROR %s(): nvme command failed!\n", __func__); - retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; - LRETURN; + ni_dump_log_single_core(p_ctx, p_data, i, gen_log_file); + p_data = (void*)((uint8_t *)p_data + CPU_LOG_BUFFER_SIZE); } -END: - ni_aligned_free(p_data); - return retval; + return NI_RETCODE_SUCCESS; } -/*!***************************************************************************** - * \brief Get DDR configuration of Quadra device - * - * \param[in/out] p_ctx pointer to a session context with valid file handle - * - * \return On success NI_RETCODE_SUCCESS - * On failure NI_RETCODE_INVALID_PARAM - * NI_RETCODE_ERROR_MEM_ALOC - * NI_RETCODE_ERROR_NVME_CMD_FAILED - ******************************************************************************/ -ni_retcode_t ni_device_get_ddr_configuration(ni_session_context_t *p_ctx) +ni_retcode_t ni_send_to_target(niFrameSurface1_t *source, uint64_t ui64DestAddr, uint32_t ui32FrameSize) { void *p_buffer = NULL; - ni_nvme_identity_t *p_id_data; ni_retcode_t retval = NI_RETCODE_SUCCESS; - ni_event_handle_t event_handle = NI_INVALID_EVENT_HANDLE; - uint32_t ui32LBA = IDENTIFY_DEVICE_R; - ni_device_handle_t device_handle = p_ctx->blk_io_handle; - - ni_log(NI_LOG_TRACE, "%s(): enter\n", __func__); + uint32_t ui32LBA = 0; - if (NI_INVALID_DEVICE_HANDLE == device_handle) + if (source->ui16session_ID == NI_INVALID_SESSION_ID) { - ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid passed parameters\n", - __func__); - retval = NI_RETCODE_INVALID_PARAM; + ni_log(NI_LOG_ERROR, "ERROR %s(): Invalid session ID\n", __func__); + retval = NI_RETCODE_ERROR_INVALID_SESSION; LRETURN; } - if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), - NI_NVME_IDENTITY_CMD_DATA_SZ)) + /* allocate memory aligned buffer */ + retval = ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN); + if (retval != 0) { - ni_log(NI_LOG_ERROR, "ERROR %d: %s() Cannot allocate buffer.\n", - NI_ERRNO, __func__); retval = NI_RETCODE_ERROR_MEM_ALOC; LRETURN; } - memset(p_buffer, 0, NI_NVME_IDENTITY_CMD_DATA_SZ); + memset(p_buffer, 0, NI_DATA_BUFFER_LEN); - if (ni_nvme_send_read_cmd(device_handle, event_handle, p_buffer, - NI_NVME_IDENTITY_CMD_DATA_SZ, ui32LBA) < 0) + /* Add payload */ + memcpy(p_buffer, &ui64DestAddr, sizeof(uint64_t)); + memcpy((uint8_t *) p_buffer + 8, &ui32FrameSize, sizeof(uint32_t)); + memcpy((uint8_t *) p_buffer + 12, &source->ui16FrameIdx, sizeof(uint16_t)); + memcpy((uint8_t *) p_buffer + 14, MAGIC_P2P_VALUE, 4); + + ui32LBA = SEND_P2P_BUF_W; + + retval = ni_nvme_send_write_cmd((ni_device_handle_t)(int64_t)source->device_handle, + NI_INVALID_DEVICE_HANDLE, p_buffer, + NI_DATA_BUFFER_LEN, ui32LBA); + + if (retval < 0) { + ni_log(NI_LOG_ERROR, "%s: NVME command failed\n", __func__); retval = NI_RETCODE_ERROR_NVME_CMD_FAILED; LRETURN; } - p_id_data = (ni_nvme_identity_t *) p_buffer; - p_ctx->ddr_config = (p_id_data->memory_cfg == NI_QUADRA_MEMORY_CONFIG_SR) - ? 1 : 2; - - ni_log(NI_LOG_DEBUG, "Memory configuration %d\n",p_ctx->ddr_config); END: - - ni_aligned_free(p_buffer); - ni_log(NI_LOG_TRACE, "%s(): retval: %d\n", __func__, retval); - return retval; } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.h index a3549fa0..d240bcc8 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_api_priv.h @@ -20,15 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** + * \file ni_device_api_priv.h * - * \file xcoder_api.h - * - * @date April 1, 2018 - * - * \brief - * - * @author - * + * \brief Private definitions used by ni_device_api.c for video processing + * tasks ******************************************************************************/ #pragma once @@ -55,7 +50,9 @@ typedef enum INST_BUF_INFO_RW_UPLOAD = 2, INST_BUF_INFO_RW_READ_BUSY = 3, INST_BUF_INFO_RW_WRITE_BUSY = 4, - INST_BUF_INFO_R_ACQUIRE = 5 + INST_BUF_INFO_R_ACQUIRE = 5, + INST_BUF_INFO_RW_WRITE_BY_EP = 6, + INST_BUF_INFO_RW_READ_BY_AI = 7, } ni_instance_buf_info_rw_type_t; // mapping of a subset of NI_RETCODE_NVME_SC_* of ni_retcode_t, returned by // fw in regular i/o environment. @@ -83,17 +80,40 @@ typedef struct _ni_instance_mgr_general_status { uint8_t active_sub_instances_cnt; // Number of active sub-instance in that instance uint8_t process_load_percent; // Processing load in percentage - uint8_t error_count; - uint8_t fatal_error; + union{ + uint8_t error_count; + uint8_t pcie_load; + }; + union{ + uint8_t fatal_error; + uint8_t pcie_throughput; + }; uint32_t fw_model_load; uint8_t cmd_queue_count; uint8_t fw_video_mem_usage; uint8_t fw_share_mem_usage; uint8_t fw_p2p_mem_usage; uint8_t active_hwupload_sub_inst_cnt; // number of hwuploader instances - uint8_t ui8reserved[3]; + uint8_t fw_load; + uint8_t fw_video_shared_mem_usage; + uint8_t process_load_percent_upper; // Processing load upper 8 bits + uint8_t process_load_percent_overall; // Processing load among all namespaces + uint8_t active_sub_instances_cnt_overall ; // Number of active sub-instance among all namespaces + uint32_t fw_model_load_overall; // Model load among all namespaces + uint8_t admin_nsid; // declares if there is info from admin namespace + uint8_t tp_fw_load; //uint8_t rsrv; } ni_instance_mgr_general_status_t; +#define NI_VERSION_CHARACTER_COUNT 8 + +typedef struct _ni_log_fl_fw_versions +{ + uint8_t last_ran_fl_version[NI_VERSION_CHARACTER_COUNT]; + uint8_t nor_flash_fl_version[NI_VERSION_CHARACTER_COUNT]; + uint8_t current_fw_revision[NI_VERSION_CHARACTER_COUNT]; + uint8_t nor_flash_fw_revision[NI_VERSION_CHARACTER_COUNT]; +} ni_log_fl_fw_versions_t; + typedef struct _ni_instance_mgr_stream_info { uint16_t picture_width; // Picture Width @@ -116,7 +136,8 @@ typedef struct _ni_session_stats uint32_t ui32LastTransactionCompletionStatus; uint32_t ui32LastErrorTransactionId; uint32_t ui32LastErrorStatus; - uint64_t ui64Session_timestamp; // session start timestamp + uint32_t ui32Session_timestamp_high; // session start timestamp high + uint32_t ui32Session_timestamp_low; // session start timestamp low uint32_t reserved[1]; } ni_session_stats_t; // 32 bytes (has to be 8 byte aligned) @@ -134,7 +155,9 @@ typedef struct _ni_instance_mgr_allocation_info uint16_t frame_index; uint16_t session_id; uint8_t output_index; - uint8_t reserved0[3]; + uint8_t input_index; + uint8_t orientation; + uint8_t reserved0; uint32_t reserved; } ni_instance_mgr_allocation_info_t; @@ -184,7 +207,8 @@ typedef struct _ni_metadata_common uint16_t frame_width; uint16_t frame_height; uint16_t frame_type; - uint16_t reserved; + uint8_t has_b_frame; + uint8_t pkt_delay_cnt; } ni_metadata_common_t; // 48 bytes @@ -218,6 +242,9 @@ typedef struct _ni_metadata_enc_frame uint8_t use_cur_src_as_long_term_pic; uint8_t use_long_term_ref; //uint32_t reserved; + uint16_t start_len[3]; + uint8_t inconsecutive_transfer; + uint8_t reserved; } ni_metadata_enc_frame_t; typedef struct _ni_metadata_enc_bstream_rev61 @@ -244,11 +271,24 @@ typedef struct _ni_metadata_enc_bstream uint32_t ssimY; uint32_t ssimU; uint32_t ssimV; - uint32_t reserved; + //Added for Revision 6p + int16_t max_mv_x[2]; // 1/4 pixel unit + int16_t min_mv_x[2]; // 1/4 pixel unit + int16_t max_mv_y[2]; // 1/4 pixel unit + int16_t min_mv_y[2]; // 1/4 pixel unit + uint16_t frame_size; + uint16_t inter_total_count; // the inter includ the skip mode + uint16_t intra_total_count; + uint8_t gop_size; + uint8_t reserved_bytes[3]; + uint32_t reserved[4]; } ni_metadata_enc_bstream_t; /*!****** encoder paramters *********************************************/ +#define TUNE_BFRAME_VISUAL_MEDIUM 1 +#define TUNE_BFRAME_VISUAL_HIGH 2 + typedef enum _ni_gop_preset_idx { GOP_PRESET_IDX_DEFAULT = @@ -264,6 +304,7 @@ typedef enum _ni_gop_preset_idx GOP_PRESET_IDX_RA_IB = 8, /*!*< Random Access, cyclic gopsize = 8 */ GOP_PRESET_IDX_SP = 9, /*!*< Consecutive P, gopsize=1, similar to 2 but */ /* uses 1 instead of 2 reference frames */ + GOP_PRESET_IDX_HIERARCHICAL_IPPPP = 10, /*!*< Hierarchical P, cyclic gopsize = 4 */ } ni_gop_preset_idx_t; /*!* @@ -425,8 +466,8 @@ typedef struct _ni_t408_config_t int32_t rdoSkip; /*!*< It skips RDO(rate distortion optimization). */ int32_t lambdaScalingEnable; /*!*< It enables lambda scaling using custom GOP. */ int32_t enable_transform_8x8; /*!*< It enables 8x8 intra prediction and 8x8 transform. */ - int32_t avc_slice_mode; - int32_t avc_slice_arg; /*!*< The number of MB for a slice when avc_slice_mode is set with 1 */ + int32_t slice_mode; + int32_t slice_arg; /*!*< The number of MB for a slice when slice_mode is set with 1 */ int32_t intra_mb_refresh_mode; int32_t intra_mb_refresh_arg; int32_t enable_mb_level_rc; /*!*< It enables MB-level rate control. */ @@ -467,7 +508,7 @@ typedef struct _ni_encoder_config_t uint32_t ui32sourceEndian; /**> 0=no HDR in VUI, 1=add HDR info to VUI **/ - uint32_t hdrEnableVUI; //TODO: to be deprecated + uint32_t hdrEnableVUI; /* Ignored by Quadra. Kept for backward and forward compatibility. */ uint32_t ui32VuiDataSizeBits; /**< size of VUI RBSP in bits **/ uint32_t ui32VuiDataSizeBytes; /**< size of VUI RBSP in bytes up to NI_MAX_VUI_SIZE **/ int32_t i32hwframes; @@ -507,21 +548,74 @@ typedef struct _ni_encoder_config_t uint8_t ui8videoFullRange; uint32_t ui32setLongTermInterval; /* sets long-term reference interval */ uint32_t ui32QLevel; /* JPEG Quantization scale (0-9) */ - // not to be exposed to customers ---> int8_t i8chromaQpOffset; int32_t i32tolCtbRcInter; int32_t i32tolCtbRcIntra; int16_t i16bitrateWindow; + // experimental parameters, not to be set by user ---> uint8_t ui8inLoopDSRatio; uint8_t ui8blockRCSize; + // <--- experimental parameters, not to be set by user uint8_t ui8rcQpDeltaRange; - // <--- not to be exposed to customers uint8_t ui8LowDelay; uint8_t ui8setLongTermCount; /* sets long-term reference frames count */ uint16_t ui16maxFrameSize; uint8_t ui8enableSSIM; - uint8_t ui8VuiRbsp[NI_MAX_VUI_SIZE]; /**< VUI raw byte sequence **/ + uint8_t ui8hdr10_enable; + uint16_t ui16hdr10_dx0; + uint16_t ui16hdr10_dy0; + uint16_t ui16hdr10_dx1; + uint16_t ui16hdr10_dy1; + uint16_t ui16hdr10_dx2; + uint16_t ui16hdr10_dy2; + uint16_t ui16hdr10_wx; + uint16_t ui16hdr10_wy; + uint32_t ui32hdr10_maxluma; + uint32_t ui32hdr10_minluma; + int8_t i8skipFrameEnable; + int8_t i8maxConsecutiveSkipFrameNum; + int8_t i8enableipRatio; + uint8_t u8skipFrameInterval; + uint16_t ui16iFrameSizeRatio; + uint8_t rsvd2; uint8_t ui8fixedframerate; + uint8_t ui8av1ErrResilientMode; + uint8_t ui8intraResetRefresh; /**< reset intra refresh on force IDR frame. */ + int16_t i16ctbRowQpStep; + uint8_t ui8NewRCEnable; // <--- experimental parameters, not to be set by user + uint8_t ui8temporalLayersEnable; + uint8_t ui8AiEnhanceMode; + uint8_t ui8enable2PassGopPatern; + uint32_t ui32lumaLinesize; + uint32_t ui32chromaLinesize; + uint32_t ui32cropWidth; + uint32_t ui32cropHeight; + uint32_t ui32horOffset; + uint32_t ui32verOffset; + uint8_t ui8AiEnhanceLevel; + int8_t i8crfMax; // <--- experimental parameters, not to be set by user /* prevent quadra from reducing the ratefactor below the given value */ + int32_t i32qcomp; + // experimental parameters, not to be set by user ---> + uint8_t ui8noMbtree; + uint8_t ui8noHWMultiPassSupport; + int8_t i8cuTreeFactor; + // <--- experimental parameters, not to be set by user + int32_t i32ipRatio; + int32_t i32pbRatio; + int32_t i32cplxDecay; + uint32_t ui32vbvMaxRate; + int8_t i8ppsInitQp; + uint8_t ui8bitrateMode; + int8_t i8pass1Qp; // <--- experimental parameters, not to be set by user + int8_t i8crfDecimal; + int8_t i8hvsBaseMbComplexity; + int8_t i8statisticOutputLevel; + uint8_t ui8crfMaxIframeEnable; + uint32_t ui32vbvMinRate; + uint8_t ui8disableBframeRDOQ; + int32_t i32forceBframeQpFactor; + uint8_t ui8tuneBframeVisual; + uint8_t ui8EnableAcqLimit; } ni_encoder_config_t; typedef struct _ni_uploader_config_t @@ -532,6 +626,8 @@ typedef struct _ni_uploader_config_t uint8_t ui8PixelFormat; uint8_t ui8Pool; uint8_t ui8rsvd[1]; + uint32_t ui32lumaLinesize; + uint32_t ui32chromaLinesize; } ni_uploader_config_t; // struct describing resolution change. @@ -545,6 +641,9 @@ typedef struct _ni_resolution // bit depth factor int32_t bit_depth_factor; + + int32_t luma_linesize; + int32_t chroma_linesize; } ni_resolution_t; #define NI_MINIMUM_CROPPED_LENGTH 48 @@ -572,8 +671,13 @@ typedef struct { uint8_t ui8CropMode; uint8_t ui8ScaleEnabled; uint8_t ui8SemiPlanarEnabled; - uint8_t ui8Rsvd1; - uint16_t ui16Rsvd2; + // ui8EnablePpuScaleAdapt 0: disable 1: enable long-edge adapt 2: enable short-edge adapt + // 3: enable long-edge adapt 4: enable short-edge adapt + // 1 and 2 is that default rounding down to 2, and don't check change in area before and after + // 3 and 4 is that default rounding up to 2, and will check change in area before and after + uint8_t ui8EnablePpuScaleAdapt; + uint8_t ui8EnablePpuScaleLimit; + uint8_t ui8ScaleResCeil; // even is up, odd is down (odd+1) ni_decode_cropping_rectangle sCroppingRectable; ni_decoder_output_picture_size sOutputPictureSize; }ni_decoder_output_config_t; @@ -586,9 +690,17 @@ typedef struct _ni_decoder_config_t uint32_t fps_number; uint32_t fps_denominator; uint8_t ui8MCMode; - uint8_t ui8rsrv[3]; + uint8_t ui8DisablePictureReordering; + uint8_t ui8EnablelowDelayCheck; + uint8_t ui8MaxExtraHwFrameCnt; uint32_t ui32MaxPktSize; ni_decoder_output_config_t asOutputConfig[NI_MAX_NUM_OF_DECODER_OUTPUTS]; + uint8_t ui8EcPolicy; + uint8_t ui8EnableAdvancedEc; + uint8_t ui8DisableAdaptiveBuffers; + uint8_t ui8reserved; + uint32_t ui32SourceWidth; + uint32_t ui32SourceHeight; } ni_decoder_config_t; typedef struct _ni_ai_config_t @@ -599,7 +711,13 @@ typedef struct _ni_ai_config_t typedef struct _ni_network_buffer { - uint32_t ui32Address; + uint16_t ui16FrameScale; + uint16_t ui16Width; + uint16_t ui16Height; + uint16_t ui16Option; + uint8_t ui8PoolSize; + uint8_t ui8MultiIn; + uint16_t ui16FrameIdx[4]; } ni_network_buffer_t; typedef struct _ni_scaler_config @@ -610,6 +728,12 @@ typedef struct _ni_scaler_config uint32_t ui32Reserved[3]; } ni_scaler_config_t; +typedef struct _ni_ddr_priority_config +{ + uint8_t ddr_mode; + uint8_t ui8Reserved[7]; +} ni_ddr_priority_config_t; + // the following enum and struct are copied from firmware/nvme/vpuapi/vpuapi.h /*!* * \brief @@ -636,6 +760,19 @@ typedef enum #define NI_QUADRA_MEMORY_CONFIG_DR 0 #define NI_QUADRA_MEMORY_CONFIG_SR 1 +#define NI_QUADRA_MEMORY_CONFIG_SR2_REMOVE_P2P 2 +#define NI_QUADRA_MEMORY_CONFIG_SR_4G 3 + + +#define NI_MAX_AI_NETWORK_BINARY_BUFFER_QUERY_RETRIES 300000 +#define NI_MAX_DEC_SESSION_READ_QUERY_EOS_RETRIES 15000 +#define NI_RETRY_INTERVAL_200US 200 +#define NI_RETRY_INTERVAL_100US 100 + +// size of meta data sent together with bitstream: from f/w encoder to app for FW/SW before rev 6.1 +#define NI_FW_ENC_BITSTREAM_META_DATA_SIZE 32 +// size of meta data sent together with bitstream: from f/w encoder to app for FW/SW before rev 6.o +#define NI_FW_ENC_BITSTREAM_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_o 48 int ni_create_frame(ni_frame_t* p_frame, uint32_t read_length, uint64_t* frame_offset, bool is_hw_frame); @@ -670,10 +807,13 @@ void ni_populate_device_capability_struct(ni_device_capability_t* p_cap, void * int ni_xcoder_session_query(ni_session_context_t *p_ctx, ni_device_type_t device_type); +int ni_xcoder_session_query_detail(ni_session_context_t *p_ctx, + ni_device_type_t device_type, void *detail_data, int ver); ni_retcode_t ni_config_instance_set_decoder_params(ni_session_context_t* p_ctx, uint32_t max_pkt_size); ni_retcode_t ni_decoder_session_open(ni_session_context_t *p_ctx); ni_retcode_t ni_decoder_session_close(ni_session_context_t *p_ctx, int eos_recieved); +ni_retcode_t ni_decoder_session_send_eos(ni_session_context_t *p_ctx); ni_retcode_t ni_decoder_session_flush(ni_session_context_t *p_ctx); int ni_decoder_session_write(ni_session_context_t *p_ctx, ni_packet_t *p_packet); @@ -681,22 +821,29 @@ int ni_decoder_session_read(ni_session_context_t *p_ctx, ni_frame_t *p_frame); ni_retcode_t ni_encoder_session_open(ni_session_context_t *p_ctx); ni_retcode_t ni_encoder_session_close(ni_session_context_t *p_ctx, int eos_recieved); -ni_retcode_t ni_encoder_session_flush(ni_session_context_t *p_ctx); +ni_retcode_t ni_encoder_session_send_eos(ni_session_context_t *p_ctx); int ni_encoder_session_write(ni_session_context_t *p_ctx, ni_frame_t *p_frame); int ni_encoder_session_read(ni_session_context_t *p_ctx, ni_packet_t *p_packet); ni_retcode_t ni_encoder_session_sequence_change(ni_session_context_t *p_ctx, ni_resolution_t *p_resoluion); //int ni_encoder_session_reconfig(ni_session_context_t *p_ctx, ni_session_config_t *p_config, ni_param_change_flags_t change_flags); ni_retcode_t ni_query_general_status(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_general_status_t* p_gen_status); +ni_retcode_t ni_query_detail_status(ni_session_context_t* p_ctx, ni_device_type_t device_type, void* p_detail_status, int ver); + ni_retcode_t ni_query_stream_info(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_stream_info_t* p_stream_info); ni_retcode_t ni_query_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_stream_complete_t* p_stream_complete); ni_retcode_t ni_query_instance_buf_info(ni_session_context_t* p_ctx, ni_instance_buf_info_rw_type_t rw_type, ni_device_type_t device_type, ni_instance_buf_info_t *p_inst_buf_info); ni_retcode_t ni_query_session_stats(ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_session_stats_t* p_session_stats, int rc, int opcode); +ni_retcode_t +ni_query_session_statistic_info(ni_session_context_t *p_ctx, + ni_device_type_t device_type, + ni_session_statistic_t *p_session_statistic); ni_retcode_t ni_config_session_rw(ni_session_context_t* p_ctx, ni_session_config_rw_type_t rw_type, uint8_t enable, uint8_t hw_action, uint16_t frame_id); ni_retcode_t ni_config_instance_sos(ni_session_context_t* p_ctx, ni_device_type_t device_type); ni_retcode_t ni_config_instance_eos(ni_session_context_t* p_ctx, ni_device_type_t device_type); +ni_retcode_t ni_config_instance_flush(ni_session_context_t* p_ctx, ni_device_type_t device_type); ni_retcode_t ni_config_instance_set_encoder_params(ni_session_context_t* p_ctx); ni_retcode_t ni_config_instance_update_encoder_params(ni_session_context_t* p_ctx, ni_param_change_flags_t change_flags); ni_retcode_t ni_config_instance_set_encoder_frame_params(ni_session_context_t* p_ctx, ni_encoder_frame_params_t* p_params); @@ -785,6 +932,16 @@ int ni_hwupload_session_read_hwdesc(ni_session_context_t *p_ctx, *******************************************************************************/ int ni_hwdownload_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame, niFrameSurface1_t* hwdesc); +/*!****************************************************************************** +* \brief Copy a src hw frame to a dst hw frame +* +* \param +* +* \return +*******************************************************************************/ +ni_retcode_t ni_hwframe_clone(ni_session_context_t *p_ctx, + ni_frameclone_desc_t *p_frameclone_desc); + /*!***************************************************************************** * \brief clear a particular xcoder instance buffer/data * @@ -794,8 +951,7 @@ int ni_hwdownload_session_read(ni_session_context_t* p_ctx, ni_frame_t* p_frame, * or NI_RETCODE_ERROR_NVME_CMD_FAILED on * failure ******************************************************************************/ -ni_retcode_t ni_clear_instance_buf(niFrameSurface1_t *surface, - int32_t device_handle); +ni_retcode_t ni_clear_instance_buf(niFrameSurface1_t *surface); /*!****************************************************************************** * \brief condif a scaler instance @@ -970,6 +1126,20 @@ ni_retcode_t ni_get_memory_offset(ni_session_context_t * p_ctx, const niFrameSur ******************************************************************************/ ni_retcode_t ni_device_get_ddr_configuration(ni_session_context_t *p_ctx); +/*!***************************************************************************** + * \brief Set DDR configuration of Quadra device + * + * \param[in] p_ctx pointer to a session context with valid file handle + * \param[in] ddr_priority_mode ddr priority mode + * + * \return On success NI_RETCODE_SUCCESS + * On failure NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_set_ddr_configuration(ni_session_context_t *p_ctx, + uint8_t ddr_priority_mode); + #define NI_AI_HW_ALIGN_SIZE 64 @@ -977,13 +1147,68 @@ ni_retcode_t ni_ai_session_open(ni_session_context_t *p_ctx); ni_retcode_t ni_ai_session_close(ni_session_context_t *p_ctx, int eos_received); ni_retcode_t ni_config_instance_network_binary(ni_session_context_t *p_ctx, void *nb_data, uint32_t nb_size); +ni_retcode_t ni_ai_query_network_ready(ni_session_context_t *p_ctx); ni_retcode_t ni_ai_session_write(ni_session_context_t *p_ctx, ni_frame_t *p_frame); ni_retcode_t ni_ai_session_read(ni_session_context_t *p_ctx, ni_packet_t *p_packet); ni_retcode_t ni_config_read_inout_layers(ni_session_context_t *p_ctx, ni_network_data_t *p_network); -ni_retcode_t ni_ai_alloc_hwframe(ni_session_context_t *p_ctx, int frame_index); +ni_retcode_t ni_ai_alloc_hwframe(ni_session_context_t *p_ctx, int width, + int height, int options, int pool_size, + int frame_index); +ni_retcode_t ni_ai_alloc_dst_frame(ni_session_context_t *p_ctx, + niFrameSurface1_t *p_out_surface); +ni_retcode_t ni_ai_multi_config_frame(ni_session_context_t *p_ctx, + ni_frame_config_t p_cfg_in[], + int numInCfgs, + ni_frame_config_t *p_cfg_out); + +ni_retcode_t ni_ai_session_read_hwdesc(ni_session_context_t *p_ctx, + ni_frame_t *p_frame); +/*!***************************************************************************** + * \brief Allocate memory for the metadata header and auxillary data for + * encoder input data. + * + * \param[in] p_frame Pointer to a caller allocated ni_frame_t struct + * + * \param[in] extra_len Length header and auxillary data + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_INVALID_PARAM + * NI_RETCODE_ERROR_MEM_ALOC + *****************************************************************************/ +ni_retcode_t ni_encoder_metadata_buffer_alloc(ni_frame_t *p_frame, + int extra_len); + +ni_retcode_t ni_encoder_start_buffer_alloc(ni_frame_t *p_frame); + +ni_retcode_t ni_ai_session_query_metrics(ni_session_context_t *p_ctx, + ni_network_perf_metrics_t *p_metrics); + + +/*!***************************************************************************** + * \brief Send namespace num / Opmode and SRIOv index/value to the device with + * specified logic block address. + * + * \param[in] device_handle Device handle obtained by calling ni_device_open + * \param[in] Key Represents either namespace num or opmode + * \param[in] Value Represents either SRIOv index or opmode value + * + * \return On success + * NI_RETCODE_SUCCESS + * On failure + * NI_RETCODE_ERROR_MEM_ALOC + * NI_RETCODE_ERROR_NVME_CMD_FAILED + ******************************************************************************/ +ni_retcode_t ni_device_config_ns_qos(ni_device_handle_t device_handle, + uint32_t key, uint32_t value); + +ni_retcode_t ni_dump_log_single_core(ni_session_context_t *p_ctx, void* p_data, uint32_t core_id, bool gen_log_file); +ni_retcode_t ni_dump_log_all_cores(ni_session_context_t *p_ctx, void* p_data, bool gen_log_file); +ni_retcode_t ni_send_to_target(niFrameSurface1_t *source, uint64_t ui64DestAddr, uint32_t ui32FrameSize); #ifdef __cplusplus } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.c index 2867bda9..a6f09158 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.c @@ -22,12 +22,11 @@ /*!***************************************************************************** * \file ni_device_test.c * - * \brief Example code on how to programmatically work with NI Quadra using - * libxcoder API - * + * \brief Application for performing video processing with libxcoder API. + * Its code provides examples on how to programatically use libxcoder + * API. ******************************************************************************/ - #ifdef _WIN32 #include #include "ni_getopt.h" @@ -52,11 +51,15 @@ #include "ni_bitstream.h" #include "ni_p2p_ioctl.h" -typedef struct _ni_err_rc_txt_entry -{ - ni_retcode_t rc; - const char *txt; -} ni_err_rc_txt_entry_t; +#ifdef _WIN32 +#include +#include +#ifdef lseek +#undef lseek +#endif +#define lseek(f,p,w) _lseeki64((f), (p), (w)) + +#endif /* defined(_WIN32) */ typedef struct _ni_filter_params_t { @@ -75,160 +78,6 @@ typedef struct _ni_disp_buffer volatile uint8_t *mmap_data; } disp_buffer_t; -static const ni_err_rc_txt_entry_t ni_err_rc_description[] = { - NI_RETCODE_SUCCESS, - "SUCCESS", - NI_RETCODE_FAILURE, - "FAILURE", - NI_RETCODE_INVALID_PARAM, - "INVALID_PARAM", - NI_RETCODE_ERROR_MEM_ALOC, - "ERROR_MEM_ALOC", - NI_RETCODE_ERROR_NVME_CMD_FAILED, - "ERROR_NVME_CMD_FAILED", - NI_RETCODE_ERROR_INVALID_SESSION, - "ERROR_INVALID_SESSION", - NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE, - "ERROR_RESOURCE_UNAVAILABLE", - NI_RETCODE_PARAM_INVALID_NAME, - "PARAM_INVALID_NAME", - NI_RETCODE_PARAM_INVALID_VALUE, - "PARAM_INVALID_VALUE", - NI_RETCODE_PARAM_ERROR_FRATE, - "PARAM_ERROR_FRATE", - NI_RETCODE_PARAM_ERROR_BRATE, - "PARAM_ERROR_BRATE", - NI_RETCODE_PARAM_ERROR_TRATE, - "PARAM_ERROR_TRATE", - NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE, - "PARAM_ERROR_VBV_BUFFER_SIZE", - NI_RETCODE_PARAM_ERROR_INTRA_PERIOD, - "PARAM_ERROR_INTRA_PERIOD", - NI_RETCODE_PARAM_ERROR_INTRA_QP, - "PARAM_ERROR_INTRA_QP", - NI_RETCODE_PARAM_ERROR_GOP_PRESET, - "PARAM_ERROR_GOP_PRESET", - NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE, - "PARAM_ERROR_CU_SIZE_MODE", - NI_RETCODE_PARAM_ERROR_MX_NUM_MERGE, - "PARAM_ERROR_MX_NUM_MERGE", - NI_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN, - "PARAM_ERROR_DY_MERGE_8X8_EN", - NI_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN, - "PARAM_ERROR_DY_MERGE_16X16_EN", - NI_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN, - "PARAM_ERROR_DY_MERGE_32X32_EN", - NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN, - "PARAM_ERROR_CU_LVL_RC_EN", - NI_RETCODE_PARAM_ERROR_HVS_QP_EN, - "PARAM_ERROR_HVS_QP_EN", - NI_RETCODE_PARAM_ERROR_HVS_QP_SCL, - "PARAM_ERROR_HVS_QP_SCL", - NI_RETCODE_PARAM_ERROR_MN_QP, - "PARAM_ERROR_MN_QP", - NI_RETCODE_PARAM_ERROR_MX_QP, - "PARAM_ERROR_MX_QP", - NI_RETCODE_PARAM_ERROR_MX_DELTA_QP, - "PARAM_ERROR_MX_DELTA_QP", - NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP, - "PARAM_ERROR_CONF_WIN_TOP", - NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT, - "PARAM_ERROR_CONF_WIN_BOT", - NI_RETCODE_PARAM_ERROR_CONF_WIN_L, - "PARAM_ERROR_CONF_WIN_L", - NI_RETCODE_PARAM_ERROR_CONF_WIN_R, - "PARAM_ERROR_CONF_WIN_R", - NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM, - "PARAM_ERROR_USR_RMD_ENC_PARAM", - NI_RETCODE_PARAM_ERROR_BRATE_LT_TRATE, - "PARAM_ERROR_BRATE_LT_TRATE", - NI_RETCODE_PARAM_ERROR_RCENABLE, - "PARAM_ERROR_RCENABLE", - NI_RETCODE_PARAM_ERROR_MAXNUMMERGE, - "PARAM_ERROR_MAXNUMMERGE", - NI_RETCODE_PARAM_ERROR_CUSTOM_GOP, - "PARAM_ERROR_CUSTOM_GOP", - NI_RETCODE_PARAM_ERROR_PIC_WIDTH, - "PARAM_ERROR_PIC_WIDTH", - NI_RETCODE_PARAM_ERROR_PIC_HEIGHT, - "PARAM_ERROR_PIC_HEIGHT", - NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE, - "PARAM_ERROR_DECODING_REFRESH_TYPE", - NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN, - "PARAM_ERROR_CUSIZE_MODE_8X8_EN", - NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN, - "PARAM_ERROR_CUSIZE_MODE_16X16_EN", - NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN, - "PARAM_ERROR_CUSIZE_MODE_32X32_EN", - NI_RETCODE_PARAM_ERROR_TOO_BIG, - "PARAM_ERROR_TOO_BIG", - NI_RETCODE_PARAM_ERROR_TOO_SMALL, - "PARAM_ERROR_TOO_SMALL", - NI_RETCODE_PARAM_ERROR_ZERO, - "PARAM_ERROR_ZERO", - NI_RETCODE_PARAM_ERROR_OOR, - "PARAM_ERROR_OOR", - NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG, - "PARAM_ERROR_WIDTH_TOO_BIG", - NI_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL, - "PARAM_ERROR_WIDTH_TOO_SMALL", - NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG, - "PARAM_ERROR_HEIGHT_TOO_BIG", - NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL, - "PARAM_ERROR_HEIGHT_TOO_SMALL", - NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG, - "PARAM_ERROR_AREA_TOO_BIG", - NI_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS, - "ERROR_EXCEED_MAX_NUM_SESSIONS", - NI_RETCODE_ERROR_GET_DEVICE_POOL, - "ERROR_GET_DEVICE_POOL", - NI_RETCODE_ERROR_LOCK_DOWN_DEVICE, - "ERROR_LOCK_DOWN_DEVICE", - NI_RETCODE_ERROR_UNLOCK_DEVICE, - "ERROR_UNLOCK_DEVICE", - NI_RETCODE_ERROR_OPEN_DEVICE, - "ERROR_OPEN_DEVICE", - NI_RETCODE_ERROR_INVALID_HANDLE, - "ERROR_INVALID_HANDLE", - NI_RETCODE_ERROR_INVALID_ALLOCATION_METHOD, - "ERROR_INVALID_ALLOCATION_METHOD", - NI_RETCODE_ERROR_VPU_RECOVERY, - "ERROR_VPU_RECOVERY", - - NI_RETCODE_PARAM_WARNING_DEPRECATED, - "PARAM_WARNING_DEPRECATED", - NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH, - "PARAM_ERROR_LOOK_AHEAD_DEPTH", - NI_RETCODE_PARAM_ERROR_FILLER, - "PARAM_ERROR_FILLER", - NI_RETCODE_PARAM_ERROR_PICSKIP, - "PARAM_ERROR_PICSKIP", - - NI_RETCODE_PARAM_WARN, - "PARAM_WARN", - - NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL, - "NVME_SC_WRITE_BUFFER_FULL", - NI_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE, - "NVME_SC_RESOURCE_UNAVAILABLE", - NI_RETCODE_NVME_SC_RESOURCE_IS_EMPTY, - "NVME_SC_RESOURCE_IS_EMPTY", - NI_RETCODE_NVME_SC_RESOURCE_NOT_FOUND, - "NVME_SC_RESOURCE_NOT_FOUND", - NI_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED, - "NVME_SC_REQUEST_NOT_COMPLETED", - NI_RETCODE_NVME_SC_REQUEST_IN_PROGRESS, - "NVME_SC_REQUEST_IN_PROGRESS", - NI_RETCODE_NVME_SC_INVALID_PARAMETER, - "NVME_SC_INVALID_PARAMETER", - NI_RETCODE_NVME_SC_VPU_RECOVERY, - "NVME_SC_VPU_RECOVERY", - NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT, - "NVME_SC_VPU_RSRC_INSUFFICIENT", - NI_RETCODE_NVME_SC_VPU_GENERAL_ERROR, - "NVME_SC_VPU_GENERAL_ERROR", -}; - typedef enum _ni_nalu_type { H264_NAL_UNSPECIFIED = 0, @@ -255,6 +104,9 @@ typedef enum _ni_nalu_type #define MIN_LOG2_MAX_FRAME_NUM 4 #define EXTENDED_SAR 255 #define QP_MAX_NUM (51 + 6 * 6) // The maximum supported qp +#define NI_MAX_BUFFERED_FRAME 45 +// max YUV frame size +#define MAX_YUV_FRAME_SIZE (7680 * 4320 * 3) /** * Picture parameter set @@ -278,25 +130,19 @@ typedef struct _ni_h264_pps_t int transform_8x8_mode; ///< transform_8x8_mode_flag uint8_t scaling_matrix4[6][16]; uint8_t scaling_matrix8[6][64]; - uint8_t chroma_qp_table - [2] - [QP_MAX_NUM + - 1]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table + uint8_t chroma_qp_table[2][QP_MAX_NUM + 1]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table int chroma_qp_diff; uint8_t data[4096]; size_t data_size; - uint32_t dequant4_buffer[6][QP_MAX_NUM + 1][16]; uint32_t dequant8_buffer[6][QP_MAX_NUM + 1][64]; uint32_t (*dequant4_coeff[6])[16]; uint32_t (*dequant8_coeff[6])[64]; } ni_h264_pps_t; -#define NI_MAX_BUFFERED_FRAME 45 - typedef struct _ni_test_frame_list { - ni_session_data_io_t ni_test_frame[NI_MAX_BUFFERED_FRAME]; + ni_session_data_io_t frames[NI_MAX_BUFFERED_FRAME]; int head; int tail; } ni_test_frame_list_t; @@ -310,7 +156,7 @@ typedef struct dec_send_param int pkt_size; int print_time; unsigned long *p_total_bytes_sent; - device_state_t *p_xcodeState; + device_state_t *p_xcoder_state; void *p_stream_info; } dec_send_param_t; @@ -322,9 +168,9 @@ typedef struct dec_recv_param int output_video_height; FILE *p_file; unsigned long long *p_total_bytes_received; - device_state_t *p_xcodeState; + device_state_t *p_xcoder_state; int mode; - ni_test_frame_list_t *test_frame_list; + ni_test_frame_list_t *frame_list; } dec_recv_param_t; typedef struct enc_send_param @@ -334,18 +180,20 @@ typedef struct enc_send_param int input_video_width; int input_video_height; int pfs; + void *yuv_buf; int input_arg_width[MAX_INPUT_FILES]; int input_arg_height[MAX_INPUT_FILES]; int input_bit_depth[MAX_INPUT_FILES]; int input_arg_pfs[MAX_INPUT_FILES]; + int output_total; unsigned long *p_total_bytes_sent; - device_state_t *p_xcodeState; + device_state_t *p_xcoder_state; int mode; - ni_test_frame_list_t *test_frame_list; + ni_test_frame_list_t *frame_list; uint32_t dec_codec_format; // used in transcode mode - int *p_input_exhausted; // used in upload mode - niFrameSurface1_t *p_hwframe_pool_tracker; // used in upload mode int input_total; + ni_sw_pix_fmt_t sw_pix_fmt; + ni_rate_emu_t *p_rate_emu; } enc_send_param_t; typedef struct enc_recv_param @@ -354,86 +202,169 @@ typedef struct enc_recv_param ni_session_data_io_t *p_out_packet; int output_video_width; int output_video_height; - FILE *p_file; + FILE **p_file; + int output_total; unsigned long long *p_total_bytes_received; - device_state_t *p_xcodeState; + uint32_t *p_number_of_packets; + device_state_t *p_xcoder_state; int mode; - niFrameSurface1_t *p_hwframe_pool_tracker; // used in upload mode ni_session_data_io_t *p_buffered_frame; } enc_recv_param_t; typedef struct uploader_param { ni_session_context_t *p_upl_ctx; + ni_session_context_t *p_sca_ctx; ni_session_data_io_t *p_swin_frame; + ni_session_data_io_t *p_scale_frame; int input_video_width; int input_video_height; int pfs; + void *yuv_buf; unsigned long *p_total_bytes_sent; - int *p_input_exhausted; int pool_size; - ni_test_frame_list_t *test_frame_list; + ni_test_frame_list_t *frame_list; } uploader_param_t; -volatile int send_fin_flag = 0, receive_fin_flag = 0, err_flag = 0; +volatile unsigned int g_end_of_all_threads = 0; volatile unsigned int number_of_frames = 0; volatile unsigned int number_of_frames_in_file = 0; -volatile unsigned int number_of_packets = 0; +volatile unsigned int muxed_number_of_packets = 0; +uint8_t *p_av1_seq_header = NULL; +uint32_t av1_seq_header_len = 0; +uint8_t av1_output_obu = 0; struct timeval start_time, previous_time, current_time; time_t start_timestamp = 0, privious_timestamp = 0, current_timestamp = 0; -// max YUV frame size -#define MAX_YUV_FRAME_SIZE (7680 * 4320 * 3 / 2) - static uint8_t *g_file_cache = NULL; static uint8_t *g_curr_cache_pos = NULL; // a counter for reconfigFile line entry index static int g_reconfigCount = 0; - -volatile unsigned int total_file_size = 0; -volatile unsigned int data_left_size = 0; +// HW frame (with reference count) pool tracker +static ni_hwframe_ref_t g_hwframe_pool[NI_MAX_DR_HWDESC_FRAME_INDEX]; +volatile uint64_t total_file_size = 0; +volatile uint64_t data_left_size = 0; volatile int g_repeat = 1; -static const char *ni_get_rc_txt(ni_retcode_t rc) +static ni_pix_fmt_name_t g_ni_pix_fmt_name_list[] = { + {"yuv420p", NI_PIX_FMT_YUV420P}, /* 8-bit YUV420 planar */ + {"yuv420p10le", NI_PIX_FMT_YUV420P10LE}, /* 10-bit YUV420 planar */ + {"nv12", NI_PIX_FMT_NV12}, /* 8-bit YUV420 semi-planar */ + {"p010le", NI_PIX_FMT_P010LE}, /* 10-bit YUV420 semi-planar */ + {"rgba", NI_PIX_FMT_RGBA}, /* 32-bit RGBA packed */ + {"bgra", NI_PIX_FMT_BGRA}, /* 32-bit BGRA packed */ + {"argb", NI_PIX_FMT_ARGB}, /* 32-bit ARGB packed */ + {"abgr", NI_PIX_FMT_ABGR}, /* 32-bit ABGR packed */ + {"bgr0", NI_PIX_FMT_BGR0}, /* 32-bit RGB packed */ + {"bgrp", NI_PIX_FMT_BGRP}, /* 24bit RGB packed */ + {"nv16", NI_PIX_FMT_NV16}, /* 8-bit YUV422 semi-planar */ + {"yuyv422", NI_PIX_FMT_YUYV422}, /* 8-bit YUV422 */ + {"uyvy422", NI_PIX_FMT_UYVY422}, /* 8-bit YUV422 */ + {"null", NI_PIX_FMT_NONE}, /* invalid format */ +}; + +static ni_gc620_pix_fmt_t g_ni_gc620_pix_fmt_list[] = { + {NI_PIX_FMT_NV12, GC620_NV12}, + {NI_PIX_FMT_YUV420P, GC620_I420}, + {NI_PIX_FMT_P010LE, GC620_P010_MSB}, + {NI_PIX_FMT_YUV420P10LE, GC620_I010}, + {NI_PIX_FMT_YUYV422, GC620_YUYV}, + {NI_PIX_FMT_UYVY422, GC620_UYVY}, + {NI_PIX_FMT_NV16, GC620_NV16}, + {NI_PIX_FMT_RGBA, GC620_RGBA8888}, + {NI_PIX_FMT_BGR0, GC620_BGRX8888}, + {NI_PIX_FMT_BGRA, GC620_BGRA8888}, + {NI_PIX_FMT_ABGR, GC620_ABGR8888}, + {NI_PIX_FMT_ARGB, GC620_ARGB8888}, + {NI_PIX_FMT_BGRP, GC620_RGB888_PLANAR}, +}; + +static void ni_hw_frame_ref(const niFrameSurface1_t *p_surface); +static void ni_hw_frame_unref(uint16_t hwframe_index); +static niFrameSurface1_t *hwupload_frame(ni_session_context_t *p_upl_ctx, + ni_session_context_t *p_sca_ctx, + ni_session_data_io_t *p_sw_data, + ni_session_data_io_t *p_hw_data, + ni_session_data_io_t *p_scale_data, + ni_pix_fmt_t pix_fmt, int width, + int height, int pfs, void *yuv_buf, + unsigned long *bytes_sent, int *eos); +static int encoder_receive(ni_session_context_t *enc_ctx_list, + ni_session_data_io_t *in_frame, + ni_session_data_io_t *pkt, int width, int height, + uint32_t *number_of_packets_list, + int output_total, FILE **pfs_list, + unsigned long long *total_bytes_received_list, + int print_time, device_state_t *xcoder_state); + +static inline int need_time_print(struct timeval *curr, struct timeval *prev) { - int i; - for (i = 0; - i < sizeof(ni_err_rc_description) / sizeof(ni_err_rc_txt_entry_t); i++) - { - if (rc == ni_err_rc_description[i].rc) - { - return ni_err_rc_description[i].txt; - } - } - return "rc not supported"; +#ifdef _WIN32 + return curr->tv_sec - prev->tv_sec > 3; +#else + return curr->tv_sec - prev->tv_sec > 1; +#endif +} + +static inline uint64_t get_total_file_size(int pfs) +{ + total_file_size = (uint64_t)lseek(pfs, 0, SEEK_END); + lseek(pfs, 0, SEEK_SET); + data_left_size = total_file_size; + return total_file_size; } void arg_error_exit(char *arg_name, char *param) { - fprintf(stderr, "Error: unrecognized argument for %s, \"%s\"\n", arg_name, + ni_log(NI_LOG_ERROR, "Error: unrecognized argument for %s, \"%s\"\n", arg_name, param); exit(-1); } -static inline bool test_frames_isempty(ni_test_frame_list_t *list) +static int is_ni_enc_pix_fmt(ni_pix_fmt_t pix_fmt) +{ + return pix_fmt == NI_PIX_FMT_YUV420P || pix_fmt == NI_PIX_FMT_NV12 || + pix_fmt == NI_PIX_FMT_YUV420P10LE || pix_fmt == NI_PIX_FMT_P010LE; +} + +static inline bool frame_list_is_empty(ni_test_frame_list_t *list) { return (list->head == list->tail); } -static inline bool test_frames_isfull(ni_test_frame_list_t *list) +static inline bool frame_list_is_full(ni_test_frame_list_t *list) { return (list->head == ((list->tail + 1) % NI_MAX_BUFFERED_FRAME)); } -static inline int test_frames_length(ni_test_frame_list_t *list) +static inline int frame_list_length(ni_test_frame_list_t *list) { return ((list->tail - list->head + NI_MAX_BUFFERED_FRAME) % NI_MAX_BUFFERED_FRAME); } -static inline int enq_test_frames(ni_test_frame_list_t *list) +static inline bool uploader_frame_list_full(ni_test_frame_list_t *list, + ni_pix_fmt_t pix_fmt) +{ + // There are two types of pixel formats for hw uploading. One is those + // supported by the NI encoder such as yuv420p nv12 etc. The other is those + // unsupported by the NI encoder such as rgba bgr0 etc. Such formats should + // be restricted by the hw scaler pool size in number because they have to + // be converted into the formats as former. + if (is_ni_enc_pix_fmt(pix_fmt)) + { + return frame_list_is_full(list); + } else + { + return frame_list_length(list) >= + (NI_MAX_FILTER_POOL_SIZE < NI_MAX_BUFFERED_FRAME ? + NI_MAX_FILTER_POOL_SIZE : NI_MAX_BUFFERED_FRAME); + } +} + +static inline int frame_list_enqueue(ni_test_frame_list_t *list) { - if (test_frames_isfull(list)) + if (frame_list_is_full(list)) { return -1; } @@ -441,9 +372,9 @@ static inline int enq_test_frames(ni_test_frame_list_t *list) return 0; } -static inline int deq_test_frames(ni_test_frame_list_t *list) +static inline int frame_list_drain(ni_test_frame_list_t *list) { - if (test_frames_isempty(list)) + if (frame_list_is_empty(list)) { return -1; } @@ -451,30 +382,71 @@ static inline int deq_test_frames(ni_test_frame_list_t *list) return 0; } +static ni_pix_fmt_t ni_pixel_format_search(const char *name) +{ + int i; + + for (i = 0; i < sizeof(g_ni_pix_fmt_name_list)/sizeof(ni_pix_fmt_name_t); i++) + { + if (!strcmp(name, g_ni_pix_fmt_name_list[i].name)) + { + return g_ni_pix_fmt_name_list[i].pix_fmt; + } + } + + return NI_PIX_FMT_NONE; +} + +static const char *ni_pixel_format_name(ni_pix_fmt_t pix_fmt) +{ + int i; + + for (i = 0; i < sizeof(g_ni_pix_fmt_name_list)/sizeof(ni_pix_fmt_name_t); i++) + { + if (pix_fmt == g_ni_pix_fmt_name_list[i].pix_fmt) + { + return g_ni_pix_fmt_name_list[i].name; + } + } + + return NULL; +} + +static int ni_to_gc620_pix_fmt(ni_pix_fmt_t pix_fmt) +{ + int i; + + for (i = 0; i < sizeof(g_ni_gc620_pix_fmt_list)/sizeof(ni_gc620_pix_fmt_t); i++) + { + if (g_ni_gc620_pix_fmt_list[i].pix_fmt_ni == pix_fmt) + { + return g_ni_gc620_pix_fmt_list[i].pix_fmt_gc620; + } + } + + return -1; +} + //Applies only to hwframe where recycling HW frame to FW is needed //Loop through unsent frames to set in tracking list for cleanup -static inline void drain_test_list(enc_send_param_t *p_enc_send_param, - ni_test_frame_list_t *list) +static void hwframe_list_release(ni_test_frame_list_t *list, ni_pix_fmt_t pix_fmt) { - ni_session_data_io_t *p_temp_frame = NULL; - ni_frame_t *p_ni_temp_frame = NULL; - uint16_t current_hwframe_index; - if (p_enc_send_param->p_enc_ctx->hw_action) - { - //store the unsent frames in the tracker - //to be cleared out by scan at end - while (!test_frames_isempty(list)) - { - p_temp_frame = &list->ni_test_frame[list->head]; - p_ni_temp_frame = &p_temp_frame->data.frame; - current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *)p_ni_temp_frame->p_data[3])) - ->ui16FrameIdx; - memcpy(p_enc_send_param->p_hwframe_pool_tracker + - current_hwframe_index, - (uint8_t *)p_ni_temp_frame->p_data[3], - sizeof(niFrameSurface1_t)); - deq_test_frames(list); + int i; + + // store the unsent frames in the tracker to be cleared out by scan at end + while (!frame_list_is_empty(list)) + { + ni_frame_t *p_frame = &list->frames[list->head].data.frame; + niFrameSurface1_t *p_surface = (niFrameSurface1_t *)p_frame->p_data[3]; + ni_hw_frame_ref(p_surface); + frame_list_drain(list); + } + + if (is_ni_enc_pix_fmt(pix_fmt)) + { + for (i = 0; i < NI_MAX_BUFFERED_FRAME; i++) + { + ni_frame_buffer_free(&list->frames[i].data.frame); } } } @@ -491,7 +463,7 @@ uint32_t read_next_chunk(uint8_t *p_dst, uint32_t to_read) data_left_size = total_file_size; g_repeat--; ni_log(NI_LOG_DEBUG, "input processed %d left\n", g_repeat); - to_copy = data_left_size; + to_copy = to_read; g_curr_cache_pos = g_file_cache; } else { @@ -510,14 +482,16 @@ uint32_t read_next_chunk(uint8_t *p_dst, uint32_t to_read) } // return actual bytes copied from cache, in requested size -uint32_t read_next_chunk_from_file(int pfs, uint8_t *p_dst, uint32_t to_read) +static uint32_t read_next_chunk_from_file(int pfs, uint8_t *p_dst, uint32_t to_read) { uint8_t *tmp_dst = p_dst; - ni_log(NI_LOG_DEBUG, - "read_next_chunk_from_file:p_dst %p len %u totalSize %u left %u\n", - tmp_dst, to_read, total_file_size, data_left_size); unsigned int to_copy = to_read; unsigned long tmpFileSize = to_read; + + ni_log(NI_LOG_DEBUG, "%s: p_dst %p len %u totalSize %llu left %llu\n", + __func__, tmp_dst, to_read, (unsigned long long)total_file_size, + (unsigned long long)data_left_size); + if (data_left_size == 0) { if (g_repeat > 1) @@ -543,31 +517,37 @@ uint32_t read_next_chunk_from_file(int pfs, uint8_t *p_dst, uint32_t to_read) int one_read_size = read(pfs, tmp_dst, to_copy); if (one_read_size == -1) { - fprintf(stderr, "Error: reading file, quit! left-to-read %lu\n", + ni_log(NI_LOG_ERROR, "Error: reading file, quit! left-to-read %lu\n", tmpFileSize); - fprintf(stderr, "Error: input file read error\n"); + ni_log(NI_LOG_ERROR, "Error: input file read error\n"); + return -1; + } else if (one_read_size != to_copy) + { + ni_log(NI_LOG_ERROR, + "Error: read unexpected bytes from file, actual %d != expected " + "%u\n", + one_read_size, to_copy); return -1; } data_left_size -= one_read_size; - return to_copy; + return one_read_size; } // current position of the input data buffer -static uint32_t curr_nal_start = 0; -static uint32_t curr_found_pos = 0; +static uint64_t curr_found_pos = 0; // reset input data buffer position to the start void reset_data_buf_pos(void) { - curr_nal_start = 0; curr_found_pos = 0; } // rewind input data buffer position by a number of bytes, if possible -void rewind_data_buf_pos_by(uint32_t nb_bytes) +void rewind_data_buf_pos_by(uint64_t nb_bytes) { - if (curr_found_pos > nb_bytes) + // curr_found_pos (current input parser offset) could be equal to nb_bytes (NAL size) when offset jumps back to 0 due to repeat option + if (curr_found_pos >= nb_bytes) { curr_found_pos -= nb_bytes; } else @@ -578,25 +558,27 @@ void rewind_data_buf_pos_by(uint32_t nb_bytes) // find/copy next H.264 NAL unit (including start code) and its type; // return NAL data size if found, 0 otherwise -uint32_t find_h264_next_nalu(uint8_t *p_dst, int *nal_type) +uint64_t find_h264_next_nalu(uint8_t *p_dst, int *nal_type) { - uint32_t data_size; - uint32_t i = curr_found_pos; + uint64_t data_size; + uint64_t i = curr_found_pos; if (i + 3 >= total_file_size) { ni_log(NI_LOG_DEBUG, - "%s reaching end, curr_pos %d " - "total input size %u\n", - __func__, curr_found_pos, total_file_size); + "%s reaching end, curr_pos %llu " + "total input size %llu\n", + __func__, (unsigned long long)curr_found_pos, (unsigned long long)total_file_size); if (g_repeat > 1) { g_repeat--; ni_log(NI_LOG_DEBUG, "input processed, %d left\n", g_repeat); reset_data_buf_pos(); + i = curr_found_pos; + } else { + return 0; } - return 0; } // search for start code 0x000001 or 0x00000001 @@ -620,7 +602,6 @@ uint32_t find_h264_next_nalu(uint8_t *p_dst, int *nal_type) } i += 3; - curr_nal_start = i; // get the NAL type *nal_type = (g_curr_cache_pos[i] & 0x1f); @@ -637,7 +618,7 @@ uint32_t find_h264_next_nalu(uint8_t *p_dst, int *nal_type) { data_size = total_file_size - curr_found_pos; memcpy(p_dst, &g_curr_cache_pos[curr_found_pos], data_size); - curr_found_pos = (int)total_file_size; + curr_found_pos = total_file_size; return data_size; } } @@ -1475,25 +1456,27 @@ static const uint8_t default_scaling_list_intra[] = { * find/copy next H.265 NAL unit (including start code) and its type; * return NAL data size if found, 0 otherwise */ -uint32_t find_h265_next_nalu(uint8_t *p_dst, int *nal_type) +uint64_t find_h265_next_nalu(uint8_t *p_dst, int *nal_type) { - uint32_t data_size; - uint32_t i = curr_found_pos; + uint64_t data_size; + uint64_t i = curr_found_pos; if (i + 3 >= total_file_size) { ni_log(NI_LOG_DEBUG, - "%s reaching end, curr_pos %d " - "total input size %u\n", - __func__, curr_found_pos, total_file_size); + "%s reaching end, curr_pos %llu " + "total input size %llu\n", + __func__, (unsigned long long)curr_found_pos, (unsigned long long)total_file_size); if (g_repeat > 1) { g_repeat--; ni_log(NI_LOG_DEBUG, "input processed, %d left\n", g_repeat); reset_data_buf_pos(); + i = curr_found_pos; + } else { + return 0; } - return 0; } // search for start code 0x000001 or 0x00000001 @@ -1517,7 +1500,6 @@ uint32_t find_h265_next_nalu(uint8_t *p_dst, int *nal_type) } i += 3; - curr_nal_start = i; // get the NAL type *nal_type = (g_curr_cache_pos[i] & 0x7E) >> 1; @@ -1534,7 +1516,7 @@ uint32_t find_h265_next_nalu(uint8_t *p_dst, int *nal_type) { data_size = total_file_size - curr_found_pos; memcpy(p_dst, &g_curr_cache_pos[curr_found_pos], data_size); - curr_found_pos = (int)total_file_size; + curr_found_pos = total_file_size; return data_size; } } @@ -2202,7 +2184,6 @@ static int h265_decode_vui(ni_bitstream_reader_t *br, int apply_defdispwin, if (ni_bs_reader_get_bits_left(br) < 1 && !alt) { - // XXX: Alternate syntax when sps_range_extension_flag != 0? ni_log(NI_LOG_INFO, "Overread in VUI, retrying from timing information...\n"); memcpy(vui, &backup_vui, sizeof(backup_vui)); @@ -2213,7 +2194,7 @@ static int h265_decode_vui(ni_bitstream_reader_t *br, int apply_defdispwin, return 0; } -int h265_parse_sps(ni_h265_sps_t *sps, uint8_t *buf, int size_bytes) +static int h265_parse_sps(ni_h265_sps_t *sps, uint8_t *buf, int size_bytes) { ni_h265_window_t *ow; int ret = 0; @@ -2504,13 +2485,6 @@ int h265_parse_sps(ni_h265_sps_t *sps, uint8_t *buf, int size_bytes) "implemented\n"); } } - if (0) - { - sps->output_window.left_offset += sps->vui.def_disp_win.left_offset; - sps->output_window.right_offset += sps->vui.def_disp_win.right_offset; - sps->output_window.top_offset += sps->vui.def_disp_win.top_offset; - sps->output_window.bottom_offset += sps->vui.def_disp_win.bottom_offset; - } ow = &sps->output_window; if (ow->left_offset >= INT32_MAX - ow->right_offset || @@ -2603,13 +2577,13 @@ int h265_parse_sps(ni_h265_sps_t *sps, uint8_t *buf, int size_bytes) } // probe h.265 stream info; return 0 if stream can be decoded, -1 otherwise -int probe_h265_stream_info(ni_h265_sps_t *sps) +static int probe_h265_stream_info(ni_h265_sps_t *sps) { int ret = -1; uint8_t *buf = NULL; uint8_t *p_buf; uint32_t nal_size, ep3_removed = 0, vcl_nal_count = 0; - int nal_type = -1, sei_type = -1; + int nal_type = -1; int sps_parsed = 0; if (NULL == (buf = calloc(1, NI_MAX_TX_SZ))) @@ -2683,17 +2657,26 @@ int probe_h265_stream_info(ni_h265_sps_t *sps) return ret; } -uint32_t find_vp9_next_packet(uint8_t *p_dst) +static uint64_t find_vp9_next_packet(uint8_t *p_dst, ni_vp9_header_info_t *vp9_info) { - uint32_t data_size; - uint32_t i = curr_found_pos; + uint64_t data_size; + uint64_t i = curr_found_pos ? curr_found_pos : vp9_info->header_length; if (i + 12 >= total_file_size) { ni_log(NI_LOG_DEBUG, - "%s reaching end, curr_pos %d " - "total input size %u\n", - __func__, curr_found_pos, total_file_size); - return 0; + "%s reaching end, curr_pos %llu " + "total input size %llu\n", + __func__, (unsigned long long)curr_found_pos, (unsigned long long)total_file_size); + + if (g_repeat > 1) + { + g_repeat--; + ni_log(NI_LOG_DEBUG, "input processed, %d left\n", g_repeat); + reset_data_buf_pos(); + i = vp9_info->header_length; + } else { + return 0; + } } /** packet structure: * bytes 0-3: size of frame in bytes (not including the 12-byte header) @@ -2710,7 +2693,7 @@ uint32_t find_vp9_next_packet(uint8_t *p_dst) { data_size = total_file_size - i; memcpy(p_dst, &g_curr_cache_pos[i], data_size); - curr_found_pos = (int)total_file_size; + curr_found_pos = total_file_size; return data_size; } @@ -2719,34 +2702,40 @@ uint32_t find_vp9_next_packet(uint8_t *p_dst) return data_size; } -int vp9_parse_header(ni_vp9_header_info_t *vp9_info, uint8_t *buf, - int size_bytes) +static int vp9_parse_header(ni_vp9_header_info_t *vp9_info, uint8_t *buf, + int size_bytes) { ni_bitstream_reader_t br; ni_bitstream_reader_init(&br, buf, 8 * size_bytes); ni_bs_reader_skip_bits(&br, 32); // skip signature ni_bs_reader_skip_bits(&br, 16); // skip version - vp9_info->header_length = - ni_bs_reader_get_bits(&br, 8) + (ni_bs_reader_get_bits(&br, 8) << 8); + + vp9_info->header_length = ni_bs_reader_get_bits(&br, 8); + vp9_info->header_length |= ni_bs_reader_get_bits(&br, 8) << 8; + ni_bs_reader_skip_bits(&br, 32); // skip codec fucc - vp9_info->width = - ni_bs_reader_get_bits(&br, 8) + (ni_bs_reader_get_bits(&br, 8) << 8); - vp9_info->height = - ni_bs_reader_get_bits(&br, 8) + (ni_bs_reader_get_bits(&br, 8) << 8); - vp9_info->timebase.den = ni_bs_reader_get_bits(&br, 8) + - (ni_bs_reader_get_bits(&br, 8) << 8) + - (ni_bs_reader_get_bits(&br, 8) << 16) + - (ni_bs_reader_get_bits(&br, 8) << 24); - vp9_info->timebase.num = ni_bs_reader_get_bits(&br, 8) + - (ni_bs_reader_get_bits(&br, 8) << 8) + - (ni_bs_reader_get_bits(&br, 8) << 16) + - (ni_bs_reader_get_bits(&br, 8) << 24); - - vp9_info->total_frames = ni_bs_reader_get_bits(&br, 8) + - (ni_bs_reader_get_bits(&br, 8) << 8) + - (ni_bs_reader_get_bits(&br, 8) << 16) + - (ni_bs_reader_get_bits(&br, 8) << 24); + + vp9_info->width = ni_bs_reader_get_bits(&br, 8); + vp9_info->width |= ni_bs_reader_get_bits(&br, 8) << 8; + + vp9_info->height = ni_bs_reader_get_bits(&br, 8); + vp9_info->height |= ni_bs_reader_get_bits(&br, 8) << 8; + + vp9_info->timebase.den = ni_bs_reader_get_bits(&br, 8); + vp9_info->timebase.den |= ni_bs_reader_get_bits(&br, 8) << 8; + vp9_info->timebase.den |= ni_bs_reader_get_bits(&br, 8) << 16; + vp9_info->timebase.den |= ni_bs_reader_get_bits(&br, 8) << 24; + + vp9_info->timebase.num = ni_bs_reader_get_bits(&br, 8); + vp9_info->timebase.num |= ni_bs_reader_get_bits(&br, 8) << 8; + vp9_info->timebase.num |= ni_bs_reader_get_bits(&br, 8) << 16; + vp9_info->timebase.num |= ni_bs_reader_get_bits(&br, 8) << 24; + + vp9_info->total_frames = ni_bs_reader_get_bits(&br, 8); + vp9_info->total_frames |= ni_bs_reader_get_bits(&br, 8) << 8; + vp9_info->total_frames |= ni_bs_reader_get_bits(&br, 8) << 16; + vp9_info->total_frames |= ni_bs_reader_get_bits(&br, 8) << 24; if (vp9_info->header_length != 32) { @@ -2777,7 +2766,7 @@ int vp9_parse_header(ni_vp9_header_info_t *vp9_info, uint8_t *buf, } // probe vp9 stream info; return 0 if stream can be decoded, -1 otherwise -int probe_vp9_stream_info(ni_vp9_header_info_t *vp9_info) +static int probe_vp9_stream_info(ni_vp9_header_info_t *vp9_info) { int ret = -1; uint8_t *buf = NULL; @@ -2818,8 +2807,8 @@ int probe_vp9_stream_info(ni_vp9_header_info_t *vp9_info) return ret; } -int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, - int format) +static int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, + int format) { if (!pdata || !fp) return -1; @@ -2838,8 +2827,8 @@ int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, // write Y stride if (fwrite(pdata, write_width * write_height, 1, fp) != 1) { - fprintf(stderr, "Error: writing Y stride error!\n"); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(fp)); + ni_log(NI_LOG_ERROR, "Error: writing Y stride error!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(fp)); return -1; } @@ -2857,10 +2846,10 @@ int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, { if (j < write_height && fwrite(pdata, write_width, 1, fp) != 1) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: writing U stride: height %d error!\n", height); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(fp)); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(fp)); return -1; } pdata += plane_width; @@ -2878,10 +2867,10 @@ int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, { if (j < write_height && fwrite(pdata, write_width, 1, fp) != 1) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: writing V stride: height %d error!\n", height); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(fp)); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(fp)); return -1; } pdata += plane_width; @@ -2892,8 +2881,8 @@ int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, { if (fwrite(pdata, width * height * 4, 1, fp) != 1) { - fprintf(stderr, "Error: writing rgba data error!\n"); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(fp)); + ni_log(NI_LOG_ERROR, "Error: writing rgba data error!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(fp)); return -1; } break; @@ -2905,8 +2894,8 @@ int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, { if (fwrite(pdata, width * height, 1, fp) != 1) { - fprintf(stderr, "Error: writing bgrp data error!\n"); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(fp)); + ni_log(NI_LOG_ERROR, "Error: writing bgrp data error!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(fp)); return -1; } pdata += stride_size; @@ -2920,51 +2909,203 @@ int write_dmabuf_data(uint8_t *pdata, FILE *fp, int width, int height, if (fflush(fp)) { - fprintf(stderr, "Error: writing data frame flush failed! errno %d\n", + ni_log(NI_LOG_ERROR, "Error: writing data frame flush failed! errno %d\n", errno); } return 0; } -int calc_frame_buffer_size(int width, int height, int format) +// Note we do not need to consider padding bytes from yuv/rgba file reading +static inline int frame_read_buffer_size(int w, int h, ni_pix_fmt_t pix_fmt, + ni_sw_pix_fmt_t sw_pix_fmt) { - int width_aligned = width; - int height_aligned = height; int data_len = 0; + + if (sw_pix_fmt == NI_SW_PIX_FMT_YUV444P) + { + data_len = w * h * 3; + } else if (sw_pix_fmt == NI_SW_PIX_FMT_YUV444P10LE) + { + data_len = w * h * 6; + } else + { + switch (pix_fmt) + { + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_YUV420P: + data_len = w * h * 3 / 2; + break; + case NI_PIX_FMT_P010LE: + case NI_PIX_FMT_YUV420P10LE: + data_len = w * h * 3; + break; + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_BGR0: + case NI_PIX_FMT_BGRP: + data_len = w * 4 * h; + break; + default: + break; + } + } + + return data_len; +} + +static int frame_buffer_size_calc(int width, int height, int format) +{ + int factor; + int data_len = 0; + switch (format) { case GC620_I420: { - width_aligned = ((width + 127) / 128) * 128; - height_aligned = ((height + 1) / 2) * 2; - int luma_size = width_aligned * height_aligned; - int chroma_b_size; - int chroma_r_size; - int chroma_width_aligned = (((width / 2) + 127) / 128) * 128; - int chroma_height_aligned = height_aligned / 2; - chroma_b_size = chroma_r_size = - chroma_width_aligned * chroma_height_aligned; - data_len = luma_size + chroma_b_size + chroma_r_size; + factor = 1; + int luma_width_aligned = NI_VPU_ALIGN128(width * factor); + int luma_height_aligned = ((height + 1) / 2) * 2; + int luma_size = luma_width_aligned * luma_height_aligned; + int chroma_width_aligned = NI_VPU_ALIGN128(width / 2 * factor); + int chroma_height_aligned = luma_height_aligned / 2; + int chroma_size = chroma_width_aligned * chroma_height_aligned; + data_len = luma_size + chroma_size * 2; break; } case GC620_RGBA8888: - { - data_len = width * height * 4; + factor = 4; + data_len = NI_VPU_ALIGN64(width * factor) * height; break; - } case GC620_RGB888_PLANAR: - { - data_len = NI_VPU_ALIGN32(width * height) * 3; + factor = 3; + data_len = NI_VPU_ALIGN32(width * factor) * height; break; - } - default: break; } + return data_len; } +static ni_pixel_planar_format get_pixel_planar(ni_pix_fmt_t pix_fmt) +{ + ni_pixel_planar_format ret = -1; + switch (pix_fmt) + { + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + ret = NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR; + break; + case NI_PIX_FMT_8_TILED4X4: + case NI_PIX_FMT_10_TILED4X4: + ret = NI_PIXEL_PLANAR_FORMAT_TILED4X4; + break; + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_YUV420P10LE: + case NI_PIX_FMT_ABGR: /* 32-bit ABGR packed */ + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + ret = NI_PIXEL_PLANAR_FORMAT_PLANAR; + break; + default: + break; + } + + return ret; +} + +static int read_yuv_from_file(int pfs, void *yuv_buf, int width, int height, + ni_pix_fmt_t pix_fmt, ni_sw_pix_fmt_t sw_pix_fmt, + int *eos, ni_session_run_state_t run_state) +{ + int chunk_size, frame_size; + + if (run_state == SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) + { + // The first YUV frame was consumed on sequence change. Reset the file + // pointer until the end of encoded packet is read. + get_total_file_size(pfs); + return 0; + } + + frame_size = frame_read_buffer_size(width, height, pix_fmt, sw_pix_fmt); + + chunk_size = read_next_chunk_from_file(pfs, yuv_buf, frame_size); + if (chunk_size < 0) + { + ni_log(NI_LOG_ERROR, "Error: could not read file!"); + return -1; + } else if (chunk_size == 0) + { + *eos = 1; + ni_log(NI_LOG_DEBUG, "%s: read chunk size 0, eos!\n", __func__); + return 0; + } else + { + *eos = 0; + return chunk_size; + } +} + +static int convert_yuv_444p_to_420p(ni_session_data_io_t *p_frame, + void *yuv_buf, int width, int height, + ni_sw_pix_fmt_t sw_pix_fmt, int mode, + ni_codec_format_t codec_format) +{ + int i, factor; + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS] = { NULL }; + int dst_stride[NI_MAX_NUM_DATA_POINTERS] = { 0 }; + int height_aligned[NI_MAX_NUM_DATA_POINTERS] = { 0 }; + + if (yuv_buf == NULL) + { + // EOS + return 0; + } + + switch (sw_pix_fmt) + { + case NI_SW_PIX_FMT_YUV444P: + factor = 1; + break; + case NI_SW_PIX_FMT_YUV444P10LE: + factor = 2; + break; + default: + ni_log(NI_LOG_ERROR, "Error: invalid sw pix fmt %d\n", sw_pix_fmt); + return -1; + } + + ni_get_hw_yuv420p_dim(width, height, factor, 0, dst_stride, height_aligned); + + for (i = 0; i < 2; i++) + { + ni_frame_t *frame = &p_frame[i].data.frame; + ni_encoder_frame_buffer_alloc(frame, width, height, dst_stride, + codec_format == NI_CODEC_FORMAT_H264, + NI_APP_ENC_FRAME_META_DATA_SIZE, 0); + if (frame->p_data[0] == NULL) + { + ni_log(NI_LOG_ERROR, "Error: could not allocate YUV frame buffer!\n"); + return -1; + } + } + + p_src[0] = yuv_buf; + p_src[1] = p_src[0] + width * factor * height; + p_src[2] = p_src[1] + width * factor * height; + + ni_copy_yuv_444p_to_420p(p_frame[0].data.frame.p_data, + p_frame[1].data.frame.p_data, + p_src, width, height, factor, mode); + + return 0; +} + /*!***************************************************************************** * \brief Write hwdl data to files. * @@ -3006,11 +3147,11 @@ int write_rawvideo_data(FILE *p_file, int width, int height, int format, if (j < write_height && fwrite(src, write_width, 1, p_file) != 1) { - fprintf( - stderr, + ni_log( + NI_LOG_ERROR, "Error: writing data plane %d: height %d error!\n", i, plane_height); - fprintf(stderr, "Error: ferror rc = %d\n", + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); } src += plane_width; @@ -3021,7 +3162,7 @@ int write_rawvideo_data(FILE *p_file, int width, int height, int format, uint8_t *src = p_out_frame->p_data[0]; if (fwrite(src, width * height * 4, 1, p_file) != 1) { - fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file)); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); } } else if (format == GC620_RGB888_PLANAR) { @@ -3031,14 +3172,14 @@ int write_rawvideo_data(FILE *p_file, int width, int height, int format, src = p_out_frame->p_data[i]; if (fwrite(src, width * height, 1, p_file) != 1) { - fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file)); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); } } } if (fflush(p_file)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: writing data frame flush failed! errno %d\n", errno); } @@ -3057,20 +3198,27 @@ int write_rawvideo_data(FILE *p_file, int width, int height, int format, int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, disp_buffer_t *disp, int format, FILE *fp) { + int ret = 0; + int data_len; + niFrameSurface1_t tmp_surf; + if (!disp) { - printf("Error: Invalid input params\n"); + ni_log(NI_LOG_ERROR, "Error: Invalid input params\n"); return -1; } - int ret = 0; - int data_len = calc_frame_buffer_size(p_surface->ui16width, - p_surface->ui16height, format); - data_len = (data_len + 4095) & ~4095; // must be 4096 bytes aligned + + memcpy(&tmp_surf, p_surface, sizeof(niFrameSurface1_t)); + + data_len = frame_buffer_size_calc(p_surface->ui16width, + p_surface->ui16height, format); if (!data_len) { - printf("Error: read size is 0!\n"); + ni_log(NI_LOG_ERROR, "Error: read size is 0!\n"); return -1; } + // must be 4096 bytes aligned + data_len = NI_VPU_ALIGN4096(data_len); disp->fd = -1; disp->mmap_data = MAP_FAILED; @@ -3080,7 +3228,7 @@ int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, ret = ni_scaler_p2p_frame_acquire(p_ctx, p_surface, data_len); if (ret != 0) { - printf("failed to export dma buf\n"); + ni_log(NI_LOG_ERROR, "failed to export dma buf\n"); return -1; } disp->fd = p_surface->dma_buf_fd; @@ -3090,15 +3238,15 @@ int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, mmap(0, data_len, PROT_READ | PROT_WRITE, MAP_SHARED, disp->fd, 0); if (disp->mmap_data == MAP_FAILED) { - printf("failed to mmap dmabuf: %s\n", strerror(errno)); + ni_log(NI_LOG_ERROR, "failed to mmap dmabuf: %s\n", strerror(errno)); return -1; } uint8_t *data = NULL; - ret = posix_memalign((void **)&data, sysconf(_SC_PAGESIZE), disp->len); + ret = ni_posix_memalign((void **)&data, sysconf(_SC_PAGESIZE), disp->len); if (ret) { - printf("failed to allocate memory\n"); + ni_log(NI_LOG_ERROR, "failed to allocate memory\n"); return -1; } disp->data = data; @@ -3108,7 +3256,7 @@ int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, pdata = malloc(data_len); if (!pdata) { - printf("failed to allocate data\n"); + ni_log(NI_LOG_ERROR, "failed to allocate data\n"); if (fp) fclose(fp); free(pdata); @@ -3125,7 +3273,7 @@ int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, ret = ioctl(p_ctx->netint_fd, NETINT_IOCTL_ISSUE_REQ, &uis); if (ret < 0) { - printf("failed to send req: %s\n", strerror(errno)); + ni_log(NI_LOG_ERROR, "failed to send req: %s\n", strerror(errno)); if (fp) fclose(fp); free(pdata); @@ -3140,7 +3288,7 @@ int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, ret = poll(pfds, 1, -1); if (ret < 0) { - printf("failed to poll\n"); + ni_log(NI_LOG_ERROR, "failed to poll\n"); if (fp) fclose(fp); free(pdata); @@ -3157,7 +3305,7 @@ int read_from_dmabuf(ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, write_dmabuf_data(pdata, fp, p_surface->ui16width, p_surface->ui16height, format)) { - printf("failed to write file\n"); + ni_log(NI_LOG_ERROR, "failed to write file\n"); if (fp) fclose(fp); free(pdata); @@ -3228,11 +3376,10 @@ int hwdl_frame(ni_session_context_t *p_ctx, * \return ******************************************************************************/ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, - ni_session_data_io_t *p_in_data, int sos_flag, + ni_session_data_io_t *p_in_data, int input_video_width, int input_video_height, - int pkt_size, unsigned int file_size, - unsigned long *total_bytes_sent, int print_time, - device_state_t *p_device_state, + int pkt_size, unsigned long *total_bytes_sent, + int print_time, device_state_t *p_device_state, void *stream_info) { static uint8_t tmp_buf[NI_MAX_TX_SZ] = {0}; @@ -3259,18 +3406,6 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, LRETURN; } - // TBD Demo: decoder flush at 200th packet -#if 0 - if (200 == p_dec_ctx->pkt_num) - { - if (NI_RETCODE_SUCCESS != ni_device_dec_session_flush(p_dec_ctx)) - { - ni_log(NI_LOG_ERROR, "decoder_send_data: mid-flush failed!\n"); - exit(-1); - } - } -#endif - if (0 == p_in_pkt->data_len) { memset(p_in_pkt, 0, sizeof(ni_packet_t)); @@ -3368,7 +3503,7 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, } } else if (NI_CODEC_FORMAT_VP9 == p_dec_ctx->codec_format) { - while ((packet_size = find_vp9_next_packet(tmp_buf_ptr)) > 0) + while ((packet_size = find_vp9_next_packet(tmp_buf_ptr, stream_info)) > 0) { frame_pkt_size += packet_size; ni_log(NI_LOG_DEBUG, "%s vp9 packet_size %d\n", __func__, @@ -3400,7 +3535,12 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, send_size = p_in_pkt->data_len; } - p_in_pkt->start_of_stream = sos_flag; + p_in_pkt->start_of_stream = 0; + if (!p_device_state->dec_sos_sent) + { + p_in_pkt->start_of_stream = 1; + p_device_state->dec_sos_sent = 1; + } p_in_pkt->end_of_stream = 0; p_in_pkt->video_width = input_video_width; p_in_pkt->video_height = input_video_height; @@ -3412,12 +3552,14 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, send_size = ni_packet_copy(p_in_pkt->p_data, tmp_buf, 0, p_dec_ctx->p_leftover, &p_dec_ctx->prev_size); - // todo save offset } p_in_pkt->data_len = send_size; - p_in_pkt->end_of_stream = 1; - printf("Sending p_last packet (size %u) + eos\n", p_in_pkt->data_len); + if (curr_found_pos) + { + p_in_pkt->end_of_stream = 1; + ni_log(NI_LOG_ERROR, "Sending p_last packet (size %u) + eos\n", p_in_pkt->data_len); + } } else { if (new_packet) @@ -3425,7 +3567,6 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, send_size = ni_packet_copy(p_in_pkt->p_data, tmp_buf, frame_pkt_size, p_dec_ctx->p_leftover, &p_dec_ctx->prev_size); - // todo: update offset with send_size // p_in_pkt->data_len is the actual packet size to be sent to decoder p_in_pkt->data_len += saved_prev_size; } @@ -3437,7 +3578,7 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, if (tx_size < 0) { // Error - fprintf(stderr, "Error: sending data error. rc:%d\n", tx_size); + ni_log(NI_LOG_ERROR, "Error: sending data error. rc:%d\n", tx_size); retval = NI_RETCODE_FAILURE; LRETURN; } else if (tx_size == 0) @@ -3448,7 +3589,7 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, { if (print_time) { - //printf("Sent %d < %d , re-try next time ?\n", tx_size, send_size); + //ni_log(NI_LOG_ERROR, "Sent %d < %d , re-try next time ?\n", tx_size, send_size); } } @@ -3461,7 +3602,7 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, if (print_time) { - printf("decoder_send_data: success, total sent: %lu\n", + ni_log(NI_LOG_ERROR, "decoder_send_data: success, total sent: %lu\n", *total_bytes_sent); } @@ -3471,26 +3612,9 @@ ni_retcode_t decoder_send_data(ni_session_context_t *p_dec_ctx, ni_packet_buffer_free(p_in_pkt); } -#if 0 - bytes_sent += chunk_size; - printf("[W] %d percent %d bytes sent. rc:%d result:%d\n", bytes_sent*100/file_size, chunk_size, rc, result); - sos_flag = 0; - if (NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL == rc) - { - printf("Buffer Full.\n"); - } - else if (rc != 0) - { - // Error - fprintf(stderr, "Error: sending data error. rc:%d result:%d.\n", rc, result); - err_flag = 1; - return 2; - } -#endif - retval = NI_RETCODE_SUCCESS; - END; +END: return retval; } @@ -3507,7 +3631,8 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, int output_video_width, int output_video_height, FILE *p_file, unsigned long long *total_bytes_received, int print_time, int write_to_file, - device_state_t *p_device_state) + device_state_t *p_device_state, + int * p_rx_size) { int rc = NI_RETCODE_FAILURE; int end_flag = 0; @@ -3515,10 +3640,15 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, bool b_is_hwframe = p_dec_ctx->hw_action; ni_frame_t *p_out_frame = &(p_out_data->data.frame); int width, height; - // for now read only planar data from decoder; ToDO: to read non-planar data - int is_planar = 1; + // In decoder session read function it will allocate the actual YUV + // transfer size for the very first read. And the pixel format of session + // context would be set as well. So it does not matter with the planar + // format for the first call of this function. + int is_planar = get_pixel_planar(p_dec_ctx->pixel_format) == NI_PIXEL_PLANAR_FORMAT_PLANAR; - ni_log(NI_LOG_DEBUG, "===> decoder_receive_data hwframe %d <===\n", b_is_hwframe); + ni_log(NI_LOG_DEBUG, + "===> decoder_receive_data hwframe %d pixel_format %d <===\n", + b_is_hwframe, p_dec_ctx->pixel_format); if (p_device_state->dec_eos_received) { @@ -3567,11 +3697,16 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, NI_DEVICE_TYPE_DECODER); } + // the actual pix_fmt is known and updated in ctx only after the first + // frame is decoded, so check/update it here again to be used below + is_planar = get_pixel_planar(p_dec_ctx->pixel_format) == + NI_PIXEL_PLANAR_FORMAT_PLANAR; + end_flag = p_out_frame->end_of_stream; if (rx_size < 0) { - fprintf(stderr, "Error: receiving data error. rc:%d\n", rx_size); + ni_log(NI_LOG_ERROR, "Error: receiving data error. rc:%d\n", rx_size); if (!b_is_hwframe) { ni_decoder_frame_buffer_free(&(p_out_data->data.frame)); @@ -3590,13 +3725,14 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, ni_dec_retrieve_aux_data(p_out_frame); } // rx_size == 0 means no decoded frame is available now - if (rx_size > 0 && p_file && write_to_file) { int i, j; + uint8_t *src; for (i = 0; i < 3; i++) { - uint8_t *src = p_out_frame->p_data[i]; + src = p_out_frame->p_data[i]; + int plane_height = p_dec_ctx->active_video_height; int plane_width = p_dec_ctx->active_video_width; int write_height = output_video_height; @@ -3616,6 +3752,27 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, 127) / 128) * 128; + + if (!is_planar) + { + plane_width = ((((int)(p_dec_ctx->actual_video_width) * + p_dec_ctx->bit_depth_factor + + 127) / + 128) * + 128) / + p_dec_ctx->bit_depth_factor; + // for semi-planar format, output UV at same time (data[1]) + // and skip data[2] + if (i == 1) + { + write_width *= 2; + } + if (i == 2) + { + plane_height = 0; + } + } + write_height /= 2; write_width /= 2; } @@ -3628,27 +3785,29 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, if (j < write_height && fwrite(src, write_width, 1, p_file) != 1) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: writing data plane %d: height %d error!\n", i, plane_height); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file)); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); } src += plane_width; } } + if (fflush(p_file)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: writing data frame flush failed! errno %d\n", errno); } } *total_bytes_received += rx_size; + *p_rx_size = rx_size; if (print_time) { - printf("[R] Got:%d Frames= %u fps=%f Total bytes %llu\n", rx_size, + ni_log(NI_LOG_ERROR, "[R] Got:%d Frames= %u fps=%f Total bytes %llu\n", rx_size, number_of_frames, ((float)number_of_frames / (float)(current_time.tv_sec - start_time.tv_sec)), @@ -3657,7 +3816,7 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, if (end_flag) { - printf("Decoder Receiving done.\n"); + ni_log(NI_LOG_INFO, "Decoder Receiving done.\n"); p_device_state->dec_eos_received = 1; rc = 1; } else if (0 == rx_size) @@ -3667,7 +3826,8 @@ int decoder_receive_data(ni_session_context_t *p_dec_ctx, ni_log(NI_LOG_DEBUG, "decoder_receive_data: success\n"); - END; +END: + ni_log(NI_LOG_DEBUG, "decoder_receive_data: rc %d rx_size %d\n", rc, rx_size); return rc; } @@ -3697,40 +3857,33 @@ void prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *frame) } *((int32_t *)aux_data->data) = api_param->reconf_hash[g_reconfigCount][1]; - ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig BR by frame %d\n", + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig BR %d by frame aux data\n", __func__, p_enc_ctx->frame_num, api_param->reconf_hash[g_reconfigCount][1]); g_reconfigCount++; } break; - /* case XCODER_TEST_RECONF_INTRAPRD: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) { - p_enc_ctx->enc_change_params->enable_option |= - NI_SET_CHANGE_PARAM_INTRA_PARAM; - p_enc_ctx->enc_change_params->intraQP = + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_INTRAPRD, sizeof(int32_t)); + if (!aux_data) + { + return; + } + int32_t intraprd = *((int32_t *)aux_data->data) = api_param->reconf_hash[g_reconfigCount][1]; - p_enc_ctx->enc_change_params->intraPeriod = - api_param->reconf_hash[g_reconfigCount][2]; - p_enc_ctx->enc_change_params->repeatHeaders = - api_param->reconf_hash[g_reconfigCount][3]; - ni_log(NI_LOG_DEBUG, - "%s(): frame #%lu reconf intraQP %d intraPeriod %d " - "repeatHeaders %d\n", - __func__, p_enc_ctx->frame_num, - p_enc_ctx->enc_change_params->intraQP, - p_enc_ctx->enc_change_params->intraPeriod, - p_enc_ctx->enc_change_params->repeatHeaders); - - // frame reconf_len needs to be set here - frame->reconf_len = sizeof(ni_encoder_change_params_t); + ni_log(NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "intraPeriod %d\n", + p_enc_ctx->frame_num, + intraprd); g_reconfigCount++; } break; - */ case XCODER_TEST_RECONF_VUI_HRD: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) @@ -3790,28 +3943,29 @@ void prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *frame) g_reconfigCount++; } break; - /* case XCODER_TEST_RECONF_RC_MIN_MAX_QP: + case XCODER_TEST_RECONF_RC_MIN_MAX_QP_REDUNDANT: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) { - p_enc_ctx->enc_change_params->enable_option |= - NI_SET_CHANGE_PARAM_RC_MIN_MAX_QP; - p_enc_ctx->enc_change_params->minQpI = - api_param->reconf_hash[g_reconfigCount][1]; - p_enc_ctx->enc_change_params->maxQpI = - api_param->reconf_hash[g_reconfigCount][2]; - p_enc_ctx->enc_change_params->minQpPB = - api_param->reconf_hash[g_reconfigCount][3]; - p_enc_ctx->enc_change_params->maxQpPB = - api_param->reconf_hash[g_reconfigCount][4]; + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_MAX_MIN_QP, sizeof(ni_rc_min_max_qp)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf max&min QP aux_data\n", + __func__); + return; + } + ni_rc_min_max_qp *qp_info = (ni_rc_min_max_qp *)aux_data->data; + qp_info->minQpI = api_param->reconf_hash[g_reconfigCount][1]; + qp_info->maxQpI = api_param->reconf_hash[g_reconfigCount][2]; + qp_info->maxDeltaQp = api_param->reconf_hash[g_reconfigCount][3]; + qp_info->minQpPB = api_param->reconf_hash[g_reconfigCount][4]; + qp_info->maxQpPB = api_param->reconf_hash[g_reconfigCount][5]; - // frame reconf_len needs to be set here - frame->reconf_len = sizeof(ni_encoder_change_params_t); g_reconfigCount++; } break; - */ case XCODER_TEST_RECONF_LTR_INTERVAL: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) @@ -3877,13 +4031,180 @@ void prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *frame) (int32_t)api_param->reconf_hash[g_reconfigCount][2]; ni_log(NI_LOG_DEBUG, - "%s(): frame #%lu reconfig framerate by frame (%d/%d)\n", + "%s(): frame #%lu reconfig framerate (%d/%d) by frame aux data\n", __func__, p_enc_ctx->frame_num, framerate->framerate_num, framerate->framerate_denom); g_reconfigCount++; } break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, sizeof(int32_t)); + if (!aux_data) + { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf maxFrameSize aux_data\n", + __func__); + return; + } + *((int32_t *)aux_data->data) = + api_param->reconf_hash[g_reconfigCount][1]; + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig maxFrameSize %d by frame aux data\n", + __func__, p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1]); + + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_CRF: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_CRF, sizeof(int32_t)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf crf aux_data\n", + __func__); + return; + } + *((int32_t *)aux_data->data) = + api_param->reconf_hash[g_reconfigCount][1]; + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig crf %d by frame aux data\n", + __func__, p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1]); + + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_CRF_FLOAT: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_CRF_FLOAT, sizeof(float)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf crf aux_data\n", + __func__); + return; + } + float crf = (float)(api_param->reconf_hash[g_reconfigCount][1] + + (float)api_param->reconf_hash[g_reconfigCount][2] / 100.0); + *((float *)aux_data->data) = crf; + ni_log(NI_LOG_DEBUG, + "%s(): frame #%lu reconfig float type crf %f by frame " + "aux data\n", __func__, p_enc_ctx->frame_num, crf); + g_reconfigCount++; + } + break; + + case XCODER_TEST_RECONF_VBV: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_VBV_MAX_RATE, sizeof(int32_t)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf vbfMaxRate aux_data\n", + __func__); + return; + } + *((int32_t *)aux_data->data) = + api_param->reconf_hash[g_reconfigCount][1]; + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE, sizeof(int32_t)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf vbvBufferSize aux_data\n", + __func__); + return; + } + *((int32_t *)aux_data->data) = + api_param->reconf_hash[g_reconfigCount][2]; + ni_log(NI_LOG_DEBUG, + "%s(): frame #%lu reconfig vbfMaxRate %d vbvBufferSize " + "%d by frame aux data\n", + __func__, p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1], + api_param->reconf_hash[g_reconfigCount][2]); + + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) { + int maxFrameSizeRatio = api_param->reconf_hash[g_reconfigCount][1]; + if (maxFrameSizeRatio < 1) { + ni_log(NI_LOG_ERROR, "maxFrameSizeRatio %d cannot < 1\n", + maxFrameSizeRatio); + return; + } + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, sizeof(int32_t)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf maxFrameSizeRatio aux_data\n", + __func__); + return; + } + + int32_t bitrate, framerate_num, framerate_denom; + uint32_t min_maxFrameSize, maxFrameSize; + bitrate = (p_enc_ctx->target_bitrate > 0) ? p_enc_ctx->target_bitrate : api_param->bitrate; + + if ((p_enc_ctx->framerate.framerate_num > 0) && (p_enc_ctx->framerate.framerate_denom > 0)) + { + framerate_num = p_enc_ctx->framerate.framerate_num; + framerate_denom = p_enc_ctx->framerate.framerate_denom; + } + else + { + framerate_num = (int32_t) api_param->fps_number; + framerate_denom = (int32_t) api_param->fps_denominator; + } + + min_maxFrameSize = ((uint32_t)bitrate / framerate_num * framerate_denom) / 8; + maxFrameSize = min_maxFrameSize * maxFrameSizeRatio > NI_MAX_FRAME_SIZE ? + NI_MAX_FRAME_SIZE : min_maxFrameSize * maxFrameSizeRatio; + *((int32_t *)aux_data->data) = maxFrameSize; + ni_log(NI_LOG_DEBUG, + "xcoder_send_frame: frame #%lu reconf " + "maxFrameSizeRatio %d maxFrameSize %d\n", + p_enc_ctx->frame_num, maxFrameSizeRatio, maxFrameSize); + + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_SLICE_ARG: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) { + aux_data = ni_frame_new_aux_data( + frame, NI_FRAME_AUX_DATA_SLICE_ARG, sizeof(int16_t)); + if (!aux_data) { + ni_log(NI_LOG_ERROR, + "Error %s(): no mem for reconf sliceArg aux_data\n", + __func__); + return; + } + *((int16_t *)aux_data->data) = + api_param->reconf_hash[g_reconfigCount][1]; + ni_log2(p_enc_ctx, NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu reconf " + "sliceArg %d\n", + p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1]); + + g_reconfigCount++; + } + break; + case XCODER_TEST_FORCE_IDR_FRAME: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) @@ -3906,6 +4227,20 @@ void prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *frame) g_reconfigCount++; } break; + case XCODER_TEST_RECONF_INTRAPRD_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) { + int32_t intraprd = + api_param->reconf_hash[g_reconfigCount][1]; + ni_reconfig_intraprd(p_enc_ctx, intraprd); + ni_log(NI_LOG_TRACE, + "xcoder_send_frame: frame #%lu API reconfig intraPeriod %d\n", + p_enc_ctx->frame_num, + intraprd); + + g_reconfigCount++; + } + break; case XCODER_TEST_RECONF_VUI_HRD_API: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) @@ -3958,6 +4293,25 @@ void prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *frame) g_reconfigCount++; } break; + case XCODER_TEST_RECONF_RC_MIN_MAX_QP_API: + case XCODER_TEST_RECONF_RC_MIN_MAX_QP_API_REDUNDANT: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + ni_rc_min_max_qp qp_info; + qp_info.minQpI = (int32_t)api_param->reconf_hash[g_reconfigCount][1]; + qp_info.maxQpI = (int32_t)api_param->reconf_hash[g_reconfigCount][2]; + qp_info.maxDeltaQp = (int32_t)api_param->reconf_hash[g_reconfigCount][3]; + qp_info.minQpPB = (int32_t)api_param->reconf_hash[g_reconfigCount][4]; + qp_info.maxQpPB = (int32_t)api_param->reconf_hash[g_reconfigCount][5]; + ni_reconfig_min_max_qp(p_enc_ctx, &qp_info); + ni_log(NI_LOG_DEBUG, + "%s(): frame %llu minQpI %d maxQpI %d maxDeltaQp %d minQpPB %d maxQpPB %d\n", + __func__, p_enc_ctx->frame_num, + qp_info.minQpI, qp_info.maxQpI, qp_info.maxDeltaQp, qp_info.minQpPB, qp_info.maxQpPB); + g_reconfigCount++; + } + break; case XCODER_TEST_RECONF_LTR_INTERVAL_API: if (p_enc_ctx->frame_num == api_param->reconf_hash[g_reconfigCount][0]) @@ -4001,92 +4355,141 @@ void prep_reconf_demo_data(ni_session_context_t *p_enc_ctx, ni_frame_t *frame) g_reconfigCount++; } break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + ni_reconfig_max_frame_size(p_enc_ctx, + api_param->reconf_hash[g_reconfigCount][1]); + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig maxFrameSize %d\n", + __func__, p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1]); + g_reconfigCount++; + } + break; + case XCODER_TEST_CRF_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + ni_reconfig_crf(p_enc_ctx, + api_param->reconf_hash[g_reconfigCount][1]); + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig crf %d\n", + __func__, p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1]); + g_reconfigCount++; + } + break; + case XCODER_TEST_CRF_FLOAT_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + float crf = (float)(api_param->reconf_hash[g_reconfigCount][1] + + (float)api_param->reconf_hash[g_reconfigCount][2] / 100.0); + ni_reconfig_crf2(p_enc_ctx, crf); + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig crf %f\n", + __func__, p_enc_ctx->frame_num, crf); + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_VBV_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + ni_reconfig_vbv_value( + p_enc_ctx, api_param->reconf_hash[g_reconfigCount][1], + api_param->reconf_hash[g_reconfigCount][2]); + ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig vbvMaxRate %d vbvBufferSize %d\n", + __func__, p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1], + api_param->reconf_hash[g_reconfigCount][2]); + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) + { + ni_reconfig_max_frame_size_ratio( + p_enc_ctx, api_param->reconf_hash[g_reconfigCount][1]); + ni_log(NI_LOG_DEBUG, + "xcoder_send_frame: frame #%lu reconf maxFrameSizeRatio %d\n", + p_enc_ctx->frame_num, api_param->reconf_hash[g_reconfigCount][1]); + + g_reconfigCount++; + } + break; + case XCODER_TEST_RECONF_SLICE_ARG_API: + if (p_enc_ctx->frame_num == + api_param->reconf_hash[g_reconfigCount][0]) { + ni_reconfig_slice_arg( + p_enc_ctx, api_param->reconf_hash[g_reconfigCount][1]); + ni_log(NI_LOG_DEBUG, + "xcoder_send_frame: frame #%lu API reconfig sliceArg %d\n", + p_enc_ctx->frame_num, + api_param->reconf_hash[g_reconfigCount][1]); + + g_reconfigCount++; + } + break; case XCODER_TEST_RECONF_OFF: default:; } } /*!***************************************************************************** - * \brief Read from input file, send to uploader, retrieve HW descriptor + * \brief Read from input file, upload to encoder, retrieve HW descriptor * * \param * * \return ******************************************************************************/ -int upload_send_data_get_desc( - ni_session_context_t *p_upl_ctx, - ni_session_data_io_t *p_swin_data, //intermediate for swf - ni_session_data_io_t *p_in_data, int input_video_width, - int input_video_height, int pfs, unsigned int file_size, - unsigned long *bytes_sent, int *input_exhausted) +int upload_send_data_get_desc(ni_session_context_t *p_upl_ctx, + ni_session_data_io_t *p_swin_data, //intermediate for swf + ni_session_data_io_t *p_in_data, + int input_video_width, int input_video_height, + void *yuv_buf, unsigned long *bytes_sent) { - static uint8_t tmp_buf[MAX_YUV_FRAME_SIZE]; - //volatile static int started = 0; - //volatile static int need_to_resend = 0; - int frame_size = input_video_width * input_video_height * 3 * - p_upl_ctx->bit_depth_factor / 2; - uint32_t chunk_size; - int retval; - ni_frame_t *p_in_frame = &(p_in_data->data.frame); //hwframe - ni_frame_t *p_swin_frame = &(p_swin_data->data.frame); //swframe - - niFrameSurface1_t *dst_surf; + int retval, is_semiplanar; + ni_frame_t *p_in_frame = &p_in_data->data.frame; //hwframe + ni_frame_t *p_swin_frame = &p_swin_data->data.frame; //swframe + niFrameSurface1_t *dst_surf = NULL; ni_log(NI_LOG_DEBUG, "===> upload_send_data <===\n"); - chunk_size = read_next_chunk_from_file(pfs, tmp_buf, frame_size); - if (chunk_size == -1) - { - fprintf(stderr, "Error: could not read file!"); - return -1; - } - p_in_frame->start_of_stream = 0; - - p_in_frame->end_of_stream = 0; + p_in_frame->end_of_stream = yuv_buf == NULL; p_in_frame->force_key_frame = 0; - if (chunk_size == 0) - { - p_in_frame->end_of_stream = 1; - ni_log(NI_LOG_DEBUG, "upload_send_data: read chunk size 0, eos!\n"); - *input_exhausted = 1; - } p_in_frame->video_width = p_swin_frame->video_width = input_video_width; p_in_frame->video_height = p_swin_frame->video_height = input_video_height; - // only metadata header for now - p_in_frame->extra_data_len = p_swin_frame->extra_data_len = - NI_APP_ENC_FRAME_META_DATA_SIZE; + p_in_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; + p_swin_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0}; - //bool alignment_2pass_wa = 0; // default 2pass disabled; ToDo - int is_nv12 = 0; // default NOT NV12 frame; ToDo - ni_get_hw_yuv420p_dim(input_video_width, input_video_height, - p_upl_ctx->bit_depth_factor, is_nv12, dst_stride, - dst_height_aligned); - - ni_frame_buffer_alloc_pixfmt( - p_swin_frame, /*todo semi planar format*/ - (p_upl_ctx->bit_depth_factor == 1 ? NI_PIX_FMT_YUV420P : - NI_PIX_FMT_YUV420P10LE), - input_video_width, input_video_height, dst_stride, - p_upl_ctx->codec_format == NI_CODEC_FORMAT_H264, - (int)(p_in_frame->extra_data_len)); + ni_get_min_frame_dim( + input_video_width, input_video_height, + p_upl_ctx->pixel_format, dst_stride, + dst_height_aligned); + is_semiplanar = ( + get_pixel_planar(p_upl_ctx->pixel_format) == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR); + ni_encoder_sw_frame_buffer_alloc( + !is_semiplanar, p_swin_frame, input_video_width, + dst_height_aligned[0], dst_stride, 0, + (int)p_swin_frame->extra_data_len, false); if (!p_swin_frame->p_data[0]) { - fprintf(stderr, "Error: could not allocate YUV frame buffer!"); + ni_log(NI_LOG_ERROR, "Error: could not allocate YUV frame buffer!"); return -1; } - // alloc dest avframe buff //can also be ni_frame_buffer_alloc() ni_frame_buffer_alloc_hwenc(p_in_frame, input_video_width, input_video_height, (int)p_in_frame->extra_data_len); if (!p_in_frame->p_data[3]) { - fprintf(stderr, "Error: could not allocate hw frame buffer!"); + ni_log(NI_LOG_ERROR, "Error: could not allocate hw frame buffer!"); return -1; } @@ -4098,349 +4501,338 @@ int upload_send_data_get_desc( input_video_height, dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2]); - uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS]; - int src_stride[NI_MAX_NUM_DATA_POINTERS]; - int src_height[NI_MAX_NUM_DATA_POINTERS]; - - src_stride[0] = input_video_width * p_upl_ctx->bit_depth_factor; - src_stride[1] = src_stride[2] = src_stride[0] / 2; + if (p_in_frame->end_of_stream) + { + goto hwupload; + } + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS] = {NULL}; + int src_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; + int src_height[NI_MAX_NUM_DATA_POINTERS] = {0}; src_height[0] = input_video_height; - src_height[1] = src_height[0] / 2; - src_height[2] = src_height[1]; // ToDo: (is_nv12 ? 0 : src_height[1]); - - p_src[0] = tmp_buf; - p_src[1] = tmp_buf + src_stride[0] * src_height[0]; - p_src[2] = p_src[1] + src_stride[1] * src_height[1]; + src_height[1] = input_video_height / 2; + src_height[2] = (is_semiplanar) ? 0 : (input_video_height / 2); + uint32_t conf_win_right = 0; + + switch (p_upl_ctx->pixel_format) + { + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_BGR0: + src_stride[0] = input_video_width * p_upl_ctx->bit_depth_factor; + src_height[0] = input_video_height; + src_height[1] = 0; + src_height[2] = 0; + p_src[0] = yuv_buf; + break; + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_YUV420P10LE: + src_stride[0] = input_video_width * p_upl_ctx->bit_depth_factor; + src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2; + src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2; + + p_src[0] = yuv_buf; + p_src[1] = p_src[0] + src_stride[0] * src_height[0]; + p_src[2] = p_src[1] + src_stride[1] * src_height[1]; + if (input_video_width < NI_MIN_WIDTH) + { + conf_win_right += (NI_MIN_WIDTH - input_video_width) / 2 * 2; + } else + { + conf_win_right += (NI_VPU_CEIL(input_video_width, 2) - input_video_width) / 2 * 2; + } + break; + default: + ni_log(NI_LOG_ERROR, "%s: Error Invalid pixel format %s\n", __func__, + ni_pixel_format_name(p_upl_ctx->pixel_format)); + return -1; + } - ni_copy_hw_yuv420p((uint8_t **)(p_swin_frame->p_data), p_src, - input_video_width, input_video_height, - p_upl_ctx->bit_depth_factor, is_nv12, 0, dst_stride, - dst_height_aligned, src_stride, src_height); + ni_copy_frame_data( + (uint8_t **)(p_swin_frame->p_data), + p_src, input_video_width, + input_video_height, p_upl_ctx->bit_depth_factor, + p_upl_ctx->pixel_format, conf_win_right, dst_stride, + dst_height_aligned, src_stride, src_height); +hwupload: retval = ni_device_session_hwup(p_upl_ctx, p_swin_data, dst_surf); if (retval < 0) { - fprintf(stderr, "Error: failed ni_device_session_hwup():%d, frameNum %u\n", + ni_log(NI_LOG_ERROR, "Error: ni_device_session_hwup():%d, frameNum %u\n", retval, number_of_frames); - //file was read so reset read pointer and try again - data_left_size += chunk_size; - lseek(pfs, chunk_size * number_of_frames, SEEK_SET); return -1; } else { *bytes_sent += p_swin_frame->data_len[0] + p_swin_frame->data_len[1] + p_swin_frame->data_len[2] + p_swin_frame->data_len[3]; ni_log(NI_LOG_DEBUG, "upload_send_data: total sent data size=%lu\n", - *bytes_sent); + *bytes_sent); - /* TODO Should be within libxcoderAPI*/ dst_surf->ui16width = input_video_width; dst_surf->ui16height = input_video_height; - dst_surf->ui32nodeAddress = 0; // always 0 offset for upload - dst_surf->encoding_type = (is_nv12) ? + dst_surf->encoding_type = is_semiplanar ? NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR : NI_PIXEL_PLANAR_FORMAT_PLANAR; - /* */ + number_of_frames++; ni_log(NI_LOG_DEBUG, "upload_send_data: FID = %d success, number:%u\n", - dst_surf->ui16FrameIdx, number_of_frames); + dst_surf->ui16FrameIdx, number_of_frames); } return 0; } /*!***************************************************************************** - * \brief Send encoder input data, read from input file + * \brief Read from input file, send to uploader for hw scaling, + * retrieve HW descriptor * - * \param + * \param * * \return ******************************************************************************/ -int encoder_send_data(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_in_data, int sos_flag, - int input_video_width, int input_video_height, int pfs, - unsigned int file_size, unsigned long *bytes_sent, - device_state_t *p_device_state, int bit_depth, int is_last_input) +int upload_send_data_get_desc2(ni_session_context_t *p_upl_ctx, + ni_session_data_io_t *p_swin_data, //intermediate for swf + ni_session_data_io_t *p_in_data, + int input_video_width, int input_video_height, + void *yuv_buf, unsigned long *bytes_sent) { - static uint8_t tmp_buf[MAX_YUV_FRAME_SIZE]; - volatile static int started = 0; - volatile static int need_to_resend = 0; - int frame_size = input_video_width * input_video_height * 3 * - p_enc_ctx->bit_depth_factor / 2; - uint32_t chunk_size; - int oneSent; - ni_frame_t *p_in_frame = &(p_in_data->data.frame); - // employ a ni_frame_t as a data holder for encode info that is to be sent - // to encoder; the encode info comes from either decoded frame (e.g. close - // caption, HDR/HDR+), or encode configuration specified by xcoder-params - ni_frame_t dec_frame = {0}; - ni_xcoder_params_t *p_param = - (ni_xcoder_params_t *)p_enc_ctx->p_session_config; + int retval, is_semiplanar; + ni_frame_t *p_in_frame = &p_in_data->data.frame; //hwframe + ni_frame_t *p_swin_frame = &p_swin_data->data.frame; //swframe + niFrameSurface1_t *dst_surf = NULL; - ni_log(NI_LOG_DEBUG, "===> encoder_send_data <===\n"); + ni_log(NI_LOG_DEBUG, "===> upload_send_data <===\n"); - if (p_device_state->enc_seq_change == 1) - { - ni_log(NI_LOG_DEBUG, "encoder_send_data: Sequence Change - waiting for previous session to end\n"); - return NI_TEST_RETCODE_SUCCESS; - } + p_in_frame->start_of_stream = 0; + p_in_frame->end_of_stream = yuv_buf == NULL; + p_in_frame->force_key_frame = 0; + p_in_frame->video_width = p_swin_frame->video_width = input_video_width; + p_in_frame->video_height = p_swin_frame->video_height = input_video_height; + // only metadata header for now + p_in_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; + p_swin_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; - if (p_device_state->enc_eos_sent == 1) - { - ni_log(NI_LOG_DEBUG, "encoder_send_data: ALL data (incl. eos) sent " - "already!\n"); - return NI_TEST_RETCODE_SUCCESS; + int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; + int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0}; + is_semiplanar = ( + get_pixel_planar(p_upl_ctx->pixel_format) == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR); + dst_height_aligned[0] = NI_VPU_CEIL(input_video_height, 2); + dst_height_aligned[2] = dst_height_aligned[1] = dst_height_aligned[0] / 2; + switch (p_upl_ctx->pixel_format) + { + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_BGR0: + dst_stride[0] = NI_VPU_CEIL(input_video_width, 16) * p_upl_ctx->bit_depth_factor; + dst_height_aligned[2] = dst_height_aligned[1] = 0; + break; + case NI_PIX_FMT_NV12: + dst_stride[0] = NI_VPU_CEIL(input_video_width, 128); + dst_stride[1] = dst_stride[0]; + dst_height_aligned[2] = 0; + break; + case NI_PIX_FMT_P010LE: + dst_stride[0] = NI_VPU_CEIL(input_video_width * 2, 128); + dst_stride[1] = dst_stride[0]; + dst_height_aligned[2] = 0; + break; + case NI_PIX_FMT_YUV420P: + dst_stride[0] = NI_VPU_CEIL(input_video_width, 128); + dst_stride[1] = NI_VPU_CEIL((input_video_width / 2), 128); + dst_stride[2] = dst_stride[1]; + break; + case NI_PIX_FMT_YUV420P10LE: + dst_stride[0] = NI_VPU_CEIL(input_video_width * 2, 128); + dst_stride[1] = NI_VPU_CEIL(input_video_width, 128); + dst_stride[2] = dst_stride[1]; + break; + default: + ni_log(NI_LOG_ERROR, "%s: Error Invalid pixel format %s\n", __func__, + ni_pixel_format_name(p_upl_ctx->pixel_format)); + return -1; } - if (need_to_resend) + ni_frame_buffer_alloc_pixfmt(p_swin_frame, p_upl_ctx->pixel_format, + input_video_width, input_video_height, + dst_stride, + p_upl_ctx->codec_format == NI_CODEC_FORMAT_H264, + (int)p_swin_frame->extra_data_len); + if (!p_swin_frame->p_data[0]) { - goto send_frame; + ni_log(NI_LOG_ERROR, "Error: could not allocate YUV frame buffer!"); + return -1; } - p_in_frame->start_of_stream = 0; - if (!started || p_enc_ctx->session_run_state == SESSION_RUN_STATE_SEQ_CHANGE_OPENING) + // alloc dest avframe buff + //can also be ni_frame_buffer_alloc() + ni_frame_buffer_alloc_hwenc(p_in_frame, input_video_width, + input_video_height, + (int)p_in_frame->extra_data_len); + if (!p_in_frame->p_data[3]) { - started = 1; - p_in_frame->start_of_stream = 1; + ni_log(NI_LOG_ERROR, "Error: could not allocate hw frame buffer!"); + return -1; } - p_in_frame->end_of_stream = 0; - p_in_frame->force_key_frame = 0; - p_in_frame->video_width = input_video_width; - p_in_frame->video_height = input_video_height; - - // reset encoder change data buffer - memset(p_enc_ctx->enc_change_params, 0, sizeof(ni_encoder_change_params_t)); + dst_surf = (niFrameSurface1_t *)p_in_frame->p_data[3]; - // extra data starts with metadata header, and reset various aux data size - p_in_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; - p_in_frame->roi_len = 0; - p_in_frame->reconf_len = 0; - p_in_frame->sei_total_len = 0; - - /* // currently xcoder demo app does not support semi-planar - following is for future reference - int is_planar = 1; // hard coded to planar in demo - p_in_frame->pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P : NI_PIX_FMT_NV12); - if (10 == bit_depth) - { - p_in_frame->pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P10LE : NI_PIX_FMT_P010LE); - } - */ - p_in_frame->pixel_format = NI_PIX_FMT_YUV420P; - if (10 == bit_depth) + ni_log(NI_LOG_DEBUG, "p_dst alloc linesize = %d/%d/%d src height=%d " + "dst height aligned = %d/%d/%d\n", + dst_stride[0], dst_stride[1], dst_stride[2], + input_video_height, dst_height_aligned[0], + dst_height_aligned[1], dst_height_aligned[2]); + + if (p_in_frame->end_of_stream) { - p_in_frame->pixel_format = NI_PIX_FMT_YUV420P10LE; + goto hwupload; } - if (!p_in_frame->start_of_stream && - (p_in_frame->video_width != p_enc_ctx->actual_video_width || - p_in_frame->video_height != p_enc_ctx->active_video_height || - p_in_frame->pixel_format != p_enc_ctx->pixel_format)) + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS] = {NULL}; + int src_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; + int src_height[NI_MAX_NUM_DATA_POINTERS] = {0}; + + switch (p_upl_ctx->pixel_format) { - ni_log(NI_LOG_INFO, - "encoder_send_data: resolution change %dx%d " - "-> %dx%d or pixel format change %d -> %d\n", - p_enc_ctx->actual_video_width, p_enc_ctx->active_video_height, - p_in_frame->video_width, p_in_frame->video_height, - p_enc_ctx->pixel_format, p_in_frame->pixel_format); - - // change run state - p_enc_ctx->session_run_state = - SESSION_RUN_STATE_SEQ_CHANGE_DRAINING; + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_BGR0: + src_stride[0] = input_video_width * p_upl_ctx->bit_depth_factor; + src_height[0] = input_video_height; + p_src[0] = yuv_buf; + break; + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_YUV420P10LE: + src_stride[0] = input_video_width * p_upl_ctx->bit_depth_factor; + src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2; + src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2; + + src_height[0] = input_video_height; + src_height[1] = src_height[0] / 2; + src_height[2] = is_semiplanar ? 0 : src_height[1]; + + p_src[0] = yuv_buf; + p_src[1] = p_src[0] + src_stride[0] * src_height[0]; + p_src[2] = p_src[1] + src_stride[1] * src_height[1]; + break; + default: + ni_log(NI_LOG_ERROR, "%s: Error Invalid pixel format %s\n", __func__, + ni_pixel_format_name(p_upl_ctx->pixel_format)); + return -1; + } - ni_log(NI_LOG_DEBUG, - "encoder_send_data: session_run_state change to %d \n", - p_enc_ctx->session_run_state); + ni_copy_frame_data( + (uint8_t **)(p_swin_frame->p_data), + p_src, input_video_width, + input_video_height, p_upl_ctx->bit_depth_factor, + p_upl_ctx->pixel_format, 0, dst_stride, + dst_height_aligned, src_stride, src_height); - // queue frame not needed because frame info stored in p_in_frame - // (customer application may queue frame here) - - // send EOS - p_in_frame->end_of_stream = 1; - goto send_frame; - } +hwupload: + retval = ni_device_session_hwup(p_upl_ctx, p_swin_data, dst_surf); + if (retval < 0) + { + ni_log(NI_LOG_ERROR, "Error: ni_device_session_hwup():%d, frameNum %u\n", + retval, number_of_frames); + return -1; + } else + { + *bytes_sent += p_swin_frame->data_len[0] + p_swin_frame->data_len[1] + + p_swin_frame->data_len[2] + p_swin_frame->data_len[3]; + ni_log(NI_LOG_DEBUG, "upload_send_data: total sent data size=%lu\n", + *bytes_sent); - // collect encode reconfig and demo info and save them in the data holder - // struct, to be used in the aux data prep and copy later - prep_reconf_demo_data(p_enc_ctx, &dec_frame); + dst_surf->ui16width = input_video_width; + dst_surf->ui16height = input_video_height; + dst_surf->encoding_type = is_semiplanar ? + NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR : + NI_PIXEL_PLANAR_FORMAT_PLANAR; - int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; - int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0}; - bool alignment_2pass_wa = 0; // default 2pass disabled; ToDo - int is_nv12 = 0; // default NOT NV12 frame; ToDo - ni_get_hw_yuv420p_dim(input_video_width, input_video_height, - p_enc_ctx->bit_depth_factor, is_nv12, dst_stride, - dst_height_aligned); + number_of_frames++; - // ROI demo mode takes higher priority over aux data - // Note: when ROI demo modes enabled, supply ROI map for the specified range - // frames, and 0 map for others - if (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable) - { - if (p_enc_ctx->frame_num > 90 && p_enc_ctx->frame_num < 300) - { - p_in_frame->roi_len = p_enc_ctx->roi_len; - } else - { - p_in_frame->roi_len = 0; - } - // when ROI enabled, always have a data buffer for ROI - // Note: this is handled separately from ROI through side/aux data - p_in_frame->extra_data_len += p_enc_ctx->roi_len; + ni_log(NI_LOG_DEBUG, "upload_send_data: FID = %d success, number:%u\n", + dst_surf->ui16FrameIdx, number_of_frames); } - // frame type is unknown in encode only case, so supply a dummy one - int should_send_sei_with_frame = ni_should_send_sei_with_frame( - p_enc_ctx, PIC_TYPE_P, - (ni_xcoder_params_t *)p_enc_ctx->p_session_config); - - // encode only case does not have the following SEI support for now; - // data buffer for various SEI: HDR mastering display color volume, HDR - // content light level, close caption, User data unregistered, HDR10+ etc. - uint8_t mdcv_data[NI_MAX_SEI_DATA]; - uint8_t cll_data[NI_MAX_SEI_DATA]; - uint8_t cc_data[NI_MAX_SEI_DATA]; - uint8_t udu_data[NI_MAX_SEI_DATA]; - uint8_t hdrp_data[NI_MAX_SEI_DATA]; + return 0; +} - // but still have to prep for auxiliary data (including those generated by - // reconf demo encode info) - ni_enc_prep_aux_data(p_enc_ctx, p_in_frame, &dec_frame, - p_enc_ctx->codec_format, should_send_sei_with_frame, - mdcv_data, cll_data, cc_data, udu_data, hdrp_data); +/*!***************************************************************************** + * \brief Send encoder input data, read from input file + * + * Note: For optimal performance, yuv_buf should be 4k aligned + * + * \param + * + * \return + ******************************************************************************/ +int encoder_send_data(ni_session_context_t *p_enc_ctx, + ni_session_data_io_t *p_in_data, void *yuv_buf, + int input_video_width, int input_video_height, + unsigned long *bytes_sent, device_state_t *p_device_state, + int is_last_input, ni_rate_emu_t *p_rate_emu) +{ + int oneSent; + ni_frame_t *p_in_frame = &p_in_data->data.frame; - p_in_frame->extra_data_len += p_in_frame->sei_total_len; + ni_log(NI_LOG_DEBUG, "===> encoder_send_data <===\n"); - // data layout requirement: leave space for reconfig data if at least one of - // reconfig, SEI or ROI is present - // Note: ROI is present when enabled, so use encode config flag instead of - // frame's roi_len as it can be 0 indicating a 0'd ROI map setting ! - if (p_in_frame->reconf_len || p_in_frame->sei_total_len || - (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable)) + if (p_enc_ctx->session_run_state == SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) { - p_in_frame->extra_data_len += sizeof(ni_encoder_change_params_t); + ni_log(NI_LOG_DEBUG, "encoder_send_data: Sequence Change - waiting " + "for previous session to end\n"); + return NI_TEST_RETCODE_SUCCESS; } - ni_encoder_frame_buffer_alloc( - p_in_frame, input_video_width, dst_height_aligned[0], dst_stride, - p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264, - (int)(p_in_frame->extra_data_len), alignment_2pass_wa); - if (!p_in_frame->p_data[0]) + if (p_device_state->enc_eos_sent == 1) { - fprintf(stderr, "Error: could not allocate YUV frame buffer!"); - return NI_TEST_RETCODE_FAILURE; + ni_log(NI_LOG_DEBUG, "encoder_send_data: ALL data (incl. eos) sent " + "already!\n"); + return NI_TEST_RETCODE_SUCCESS; } - ni_log(NI_LOG_DEBUG, - "p_dst alloc linesize = %d/%d/%d src height=%d " - "dst height aligned = %d/%d/%d force_key_frame=%d, " - "extra_data_len=%u" - " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_" - "color_vol %u hdr10+ %u hrd %d) reconf_size=%u roi_size=%u " - "force_pic_qp=%u udu_sei_size=%u " - "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n", - dst_stride[0], dst_stride[1], dst_stride[2], input_video_height, - dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2], - p_in_frame->force_key_frame, p_in_frame->extra_data_len, - p_in_frame->sei_total_len, - p_in_frame->sei_hdr_content_light_level_info_len, - p_in_frame->sei_hdr_mastering_display_color_vol_len, - p_in_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */ - p_in_frame->reconf_len, p_in_frame->roi_len, p_in_frame->force_pic_qp, - p_in_frame->sei_user_data_unreg_len, - p_in_frame->use_cur_src_as_long_term_pic, - p_in_frame->use_long_term_ref); - - uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS]; - int src_stride[NI_MAX_NUM_DATA_POINTERS]; - int src_height[NI_MAX_NUM_DATA_POINTERS]; - - src_stride[0] = input_video_width * p_enc_ctx->bit_depth_factor; - src_stride[1] = src_stride[2] = src_stride[0] / 2; - - src_height[0] = input_video_height; - src_height[1] = src_height[0] / 2; - src_height[2] = src_height[1]; // ToDo: (is_nv12 ? 0 : src_height[1]); - - p_src[0] = tmp_buf; - p_src[1] = tmp_buf + src_stride[0] * src_height[0]; - p_src[2] = p_src[1] + src_stride[1] * src_height[1]; - - uint8_t plane_idx; - bool need_copy = 0; - for (plane_idx = 0; plane_idx < NI_MAX_NUM_DATA_POINTERS - 1; plane_idx++) - { - if ((src_stride[plane_idx] != dst_stride[plane_idx]) || - (dst_height_aligned[plane_idx] != src_height[plane_idx])) - { - ni_log(NI_LOG_TRACE, - "encoder_send_data: plane_idx %d src_stride %d dst_stride " - "%d dst_height_aligned %d src_height %d need_copy 1\n", - plane_idx, src_stride[plane_idx], dst_stride[plane_idx], - dst_height_aligned[plane_idx], src_height[plane_idx]); - need_copy = 1; - break; - } - } - if (((ni_xcoder_params_t *)p_enc_ctx->p_session_config) - ->cfg_enc_params.conf_win_right) + if (p_device_state->enc_resend) { - ni_log(NI_LOG_TRACE, - "encoder_send_data: conf_win_right %d need_copy 1\n", - ((ni_xcoder_params_t *)p_enc_ctx->p_session_config) - ->cfg_enc_params.conf_win_right); - need_copy = 1; + goto send_frame; } - ni_log(NI_LOG_TRACE, "encoder_send_data: need_copy %d\n", need_copy); - - if (!need_copy) - { - // zero copy - chunk_size = read_next_chunk_from_file( - pfs, (uint8_t *)p_in_frame->p_data[0], frame_size); - //ni_log(NI_LOG_TRACE, - // "encoder_send_data: p_data %p frame_size %d chunk_size %d\n", - // (uint8_t *)p_in_frame->p_data[0], frame_size, chunk_size); - if (chunk_size == -1) - { - fprintf(stderr, "Error: could not read file!"); - return NI_TEST_RETCODE_FAILURE; - } - } else + p_in_frame->start_of_stream = 0; + if (!p_device_state->enc_sos_sent || + p_enc_ctx->session_run_state == SESSION_RUN_STATE_SEQ_CHANGE_OPENING) { - chunk_size = read_next_chunk_from_file(pfs, tmp_buf, frame_size); - //ni_log(NI_LOG_TRACE, - // "encoder_send_data: tmp_buf %p frame_size %d chunk_size %d\n", - // tmp_buf, frame_size, chunk_size); - if (chunk_size == -1) - { - fprintf(stderr, "Error: could not read file!"); - return NI_TEST_RETCODE_FAILURE; - } - - // YUV part of the encoder input data layout - ni_copy_hw_yuv420p( - (uint8_t **)(p_in_frame->p_data), p_src, input_video_width, - input_video_height, p_enc_ctx->bit_depth_factor, is_nv12, - ((ni_xcoder_params_t *)p_enc_ctx->p_session_config) - ->cfg_enc_params.conf_win_right, - dst_stride, dst_height_aligned, src_stride, src_height); + p_device_state->enc_sos_sent = 1; + p_in_frame->start_of_stream = 1; } + p_in_frame->end_of_stream = 0; + p_in_frame->force_key_frame = 0; + + p_in_frame->video_width = input_video_width; + p_in_frame->video_height = input_video_height; + + // reset encoder change data buffer + memset(p_enc_ctx->enc_change_params, 0, sizeof(ni_encoder_change_params_t)); - // auxiliary data part of the encoder input data layout - ni_enc_copy_aux_data(p_enc_ctx, p_in_frame, &dec_frame, - p_enc_ctx->codec_format, mdcv_data, cll_data, cc_data, - udu_data, hdrp_data, 0 /*swframe*/, is_nv12); + // reset various aux data size + p_in_frame->roi_len = 0; + p_in_frame->reconf_len = 0; + p_in_frame->sei_total_len = 0; - // clean up data storage - ni_frame_buffer_free(&dec_frame); + // collect encode reconfig and demo info and save them as aux data in + // the input frame struct. + prep_reconf_demo_data(p_enc_ctx, p_in_frame); - if (chunk_size == 0) + if (yuv_buf == NULL) { if (is_last_input) { @@ -4455,20 +4847,38 @@ int encoder_send_data(ni_session_context_t *p_enc_ctx, } send_frame: - oneSent = - ni_device_session_write(p_enc_ctx, p_in_data, NI_DEVICE_TYPE_ENCODER); + // simulate FFmpeg -re option, which controls process input rate to simualte real time environment + if (p_rate_emu->rate_emu_framerate) + { + uint64_t abs_time_ns; + abs_time_ns = ni_gettime_ns(); + if ((abs_time_ns - p_rate_emu->rate_emu_start) < (uint64_t)(1000000000LL / p_rate_emu->rate_emu_framerate * p_rate_emu->rate_emu_input_frames)) + { + if (!p_device_state->enc_resend) + p_device_state->enc_resend = 2; + if (p_device_state->enc_resend == 2) + return NI_TEST_RETCODE_SUCCESS; + } + else + { + p_rate_emu->rate_emu_input_frames++; + } + } + + oneSent = ni_enc_write_from_yuv_buffer(p_enc_ctx, p_in_frame, yuv_buf); if (oneSent < 0) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: failed ni_device_session_write() for encoder\n"); - need_to_resend = 1; + p_device_state->enc_resend = 1; return NI_TEST_RETCODE_FAILURE; } else if (oneSent == 0 && !p_enc_ctx->ready_to_close) { - need_to_resend = 1; + p_device_state->enc_resend = 1; + return NI_TEST_RETCODE_EAGAIN; } else { - need_to_resend = 0; + p_device_state->enc_resend = 0; number_of_frames++; *bytes_sent += p_in_frame->data_len[0] + p_in_frame->data_len[1] + @@ -4482,7 +4892,8 @@ int encoder_send_data(ni_session_context_t *p_enc_ctx, { if (p_enc_ctx->session_run_state == SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) { - p_device_state->enc_seq_change = 1; + // The sequence change YUV frame will be read again next time. + number_of_frames--; } else { @@ -4493,13 +4904,13 @@ int encoder_send_data(ni_session_context_t *p_enc_ctx, if (p_enc_ctx->session_run_state == SESSION_RUN_STATE_SEQ_CHANGE_OPENING) { p_enc_ctx->session_run_state = SESSION_RUN_STATE_NORMAL; - ni_log(NI_LOG_DEBUG, - "encoder_send_data: session_run_state change to %d \n", - p_enc_ctx->session_run_state); + "encoder_send_data: session_run_state change to %d\n", + p_enc_ctx->session_run_state); } } + ni_frame_wipe_aux_data(p_in_frame); return NI_TEST_RETCODE_SUCCESS; } @@ -4514,15 +4925,11 @@ int encoder_send_data(ni_session_context_t *p_enc_ctx, * @return ******************************************************************************/ int encoder_send_data2(ni_session_context_t *p_enc_ctx, - uint32_t dec_codec_format, ni_session_data_io_t *p_dec_out_data, - ni_session_data_io_t *p_enc_in_data, int sos_flag, - int input_video_width, int input_video_height, int pfs, - unsigned int file_size, unsigned long *bytes_sent, - device_state_t *p_device_state) + ni_session_data_io_t *p_enc_in_data, + int input_video_width, int input_video_height, + unsigned long *bytes_sent, device_state_t *p_device_state) { - volatile static int started = 0; - volatile static int need_to_resend_2 = 0; int oneSent; // pointer to data struct to be sent ni_session_data_io_t *p_to_send = NULL; @@ -4530,7 +4937,7 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, ni_frame_t *p_in_frame = NULL; ni_xcoder_params_t *api_params = (ni_xcoder_params_t *)p_enc_ctx->p_session_config; - int is_nv12 = 0; // default NOT NV12 frame; ToDo + int is_semiplanar = get_pixel_planar(p_enc_ctx->pixel_format) == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR; int is_hwframe = p_enc_ctx->hw_action != NI_CODEC_HW_NONE; ni_log(NI_LOG_DEBUG, "===> encoder_send_data2 <===\n"); @@ -4542,7 +4949,8 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, return 1; } - if (need_to_resend_2) + // frame resend + if (p_device_state->enc_resend) { p_to_send = p_enc_in_data; p_in_frame = &(p_to_send->data.frame); @@ -4607,7 +5015,6 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, p_in_frame->roi_len = 0; p_in_frame->reconf_len = 0; p_in_frame->sei_total_len = 0; - p_in_frame->force_pic_qp = 0; // collect encode reconfig and demo info and save them in the decode out @@ -4616,10 +5023,27 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0}; int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0}; - bool alignment_2pass_wa = 0; // default 2pass disabled; ToDo + bool alignment_2pass_wa = ( + (api_params->cfg_enc_params.lookAheadDepth || + api_params->cfg_enc_params.crfFloat >= 0) && + (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H265 || + p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1)); ni_get_hw_yuv420p_dim(input_video_width, input_video_height, - p_enc_ctx->bit_depth_factor, is_nv12, dst_stride, - dst_height_aligned); + p_enc_ctx->bit_depth_factor, is_semiplanar, + dst_stride, dst_height_aligned); + + if (alignment_2pass_wa && !is_hwframe) { + if (is_semiplanar) { + // for 2-pass encode output mismatch WA, need to extend (and + // pad) CbCr plane height, because 1st pass assume input 32 + // align + dst_height_aligned[1] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2; + } else { + // for 2-pass encode output mismatch WA, need to extend (and + // pad) Cr plane height, because 1st pass assume input 32 align + dst_height_aligned[2] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2; + } + } // ROI demo mode takes higher priority over aux data // Note: when ROI demo modes enabled, supply ROI map for the specified @@ -4674,14 +5098,13 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, if (!is_hwframe) { - //ToDo add NV12 frame support - ni_encoder_frame_buffer_alloc( + ni_encoder_sw_frame_buffer_alloc(api_params->cfg_enc_params.planar, p_in_frame, input_video_width, input_video_height, dst_stride, p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264, (int)(p_in_frame->extra_data_len), alignment_2pass_wa); if (!p_in_frame->p_data[0]) { - fprintf(stderr, "Error: cannot allocate YUV frame buffer!"); + ni_log(NI_LOG_ERROR, "Error: cannot allocate YUV frame buffer!"); return -1; } } else @@ -4691,7 +5114,7 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, (int)(p_in_frame->extra_data_len)); if (!p_in_frame->p_data[3]) { - fprintf(stderr, "Error: cannot allocate YUV frame buffer!"); + ni_log(NI_LOG_ERROR, "Error: cannot allocate YUV frame buffer!"); return -1; } } @@ -4729,6 +5152,11 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, src_stride[1] = (int)(p_dec_out_data->data.frame.data_len[1]) / src_height[1]; src_stride[2] = src_stride[1]; + if (is_semiplanar) + { + src_height[2] = 0; + src_stride[2] = 0; + } src_stride[3] = 0; p_src[0] = p_dec_out_data->data.frame.p_data[0]; @@ -4740,7 +5168,7 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, { // YUV part of the encoder input data layout ni_copy_hw_yuv420p( (uint8_t **)(p_in_frame->p_data), p_src, input_video_width, - input_video_height, p_enc_ctx->bit_depth_factor, is_nv12, + input_video_height, p_enc_ctx->bit_depth_factor, is_semiplanar, ((ni_xcoder_params_t *)p_enc_ctx->p_session_config) ->cfg_enc_params.conf_win_right, dst_stride, dst_height_aligned, src_stride, src_height); @@ -4752,16 +5180,17 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, ni_enc_copy_aux_data(p_enc_ctx, p_in_frame, &(p_dec_out_data->data.frame), p_enc_ctx->codec_format, mdcv_data, cll_data, - cc_data, udu_data, hdrp_data, is_hwframe, is_nv12); + cc_data, udu_data, hdrp_data, is_hwframe, + is_semiplanar); } p_in_frame->video_width = input_video_width; p_in_frame->video_height = input_video_height; p_in_frame->start_of_stream = 0; - if (!started) + if (!p_device_state->enc_sos_sent) { - started = 1; + p_device_state->enc_sos_sent = 1; p_in_frame->start_of_stream = 1; } // p_in_frame->end_of_stream = 0; @@ -4782,33 +5211,28 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, if (oneSent < 0) { - fprintf(stderr, "Error: encoder_send_data2\n"); - need_to_resend_2 = 1; + ni_log(NI_LOG_ERROR, "Error: encoder_send_data2\n"); + p_device_state->enc_resend = 1; return -1; } else if (oneSent == 0) { if (p_device_state->enc_eos_sent == 0 && p_enc_ctx->ready_to_close) { - need_to_resend_2 = 0; + p_device_state->enc_resend = 0; p_device_state->enc_eos_sent = 1; } else { - need_to_resend_2 = 1; - return 2; + p_device_state->enc_resend = 1; + return NI_TEST_RETCODE_EAGAIN; } } else { - need_to_resend_2 = 0; + p_device_state->enc_resend = 0; if (p_enc_ctx->ready_to_close) { p_device_state->enc_eos_sent = 1; } -#if 0 - *bytes_sent += p_in_frame->data_len[0] + p_in_frame->data_len[1] + p_in_frame->data_len[2] - + p_in_frame->data_len[3]; - ni_log(NI_LOG_DEBUG, "encoder_send_data2: total sent data size=%u\n", *bytes_sent); -#endif ni_log(NI_LOG_DEBUG, "encoder_send_data2: success\n"); } @@ -4824,14 +5248,10 @@ int encoder_send_data2(ni_session_context_t *p_enc_ctx, * \return ******************************************************************************/ int encoder_send_data3(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_in_data, int sos_flag, + ni_session_data_io_t *p_in_data, int input_video_width, int input_video_height, - device_state_t *p_device_state, int input_exhausted, - int *need_to_resend) + device_state_t *p_device_state, int eos) { - volatile static int started = 0; - //*need_to_resend = 0; //bring this outside and have upload check it too - int oneSent; ni_frame_t *p_in_frame = &(p_in_data->data.frame); @@ -4844,26 +5264,25 @@ int encoder_send_data3(ni_session_context_t *p_enc_ctx, return 0; } - if (*need_to_resend) + if (p_device_state->enc_resend) { goto send_frame; } p_in_frame->start_of_stream = 0; - if (!started) + if (!p_device_state->enc_sos_sent) { - started = 1; + p_device_state->enc_sos_sent = 1; p_in_frame->start_of_stream = 1; } - p_in_frame->end_of_stream = 0; + p_in_frame->end_of_stream = eos; p_in_frame->force_key_frame = 0; - if (input_exhausted) + p_in_frame->video_width = input_video_width; + p_in_frame->video_height = input_video_height; + if (eos) { - p_in_frame->end_of_stream = 1; ni_log(NI_LOG_DEBUG, "encoder_send_data3: read chunk size 0, eos!\n"); } - p_in_frame->video_width = input_video_width; - p_in_frame->video_height = input_video_height; // only metadata header for now p_in_frame->extra_data_len = NI_APP_ENC_FRAME_META_DATA_SIZE; @@ -4873,17 +5292,18 @@ int encoder_send_data3(ni_session_context_t *p_enc_ctx, ni_device_session_write(p_enc_ctx, p_in_data, NI_DEVICE_TYPE_ENCODER); if (oneSent < 0) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: failed ni_device_session_write() for encoder\n"); - *need_to_resend = 1; + p_device_state->enc_resend = 1; return -1; } else if (oneSent == 0 && !p_enc_ctx->ready_to_close) { - *need_to_resend = 1; + p_device_state->enc_resend = 1; ni_log(NI_LOG_DEBUG, "NEEDED TO RESEND"); + return NI_TEST_RETCODE_EAGAIN; } else { - *need_to_resend = 0; + p_device_state->enc_resend = 0; ni_log(NI_LOG_DEBUG, "encoder_send_data3: total sent data size=%u\n", p_in_frame->data_len[3]); @@ -4899,31 +5319,6 @@ int encoder_send_data3(ni_session_context_t *p_enc_ctx, return 0; } -/*!***************************************************************************** -* \brief Simple scan to Recycle remaining memory bins left around -* -* \param p_pool_tracker - start address of hwdesc pool -* -* \return -******************************************************************************/ -int scan_and_clean_hwdescriptors(niFrameSurface1_t *p_pool_tracker) -{ - int i; - int recycled = 0; - for (i = 0; i < NI_MAX_DR_HWDESC_FRAME_INDEX; i++) - { - if (p_pool_tracker[i].ui16FrameIdx) - { - ni_hwframe_buffer_recycle(&p_pool_tracker[i], - p_pool_tracker[i].device_handle); - //zero for tracking purposes - p_pool_tracker[i].ui16FrameIdx = 0; - recycled++; - } - } - return recycled; -} - /*!***************************************************************************** * \brief Reopen or reconfig encoder upon sequence change * @@ -4944,31 +5339,54 @@ int encoder_reinit_session(ni_session_context_t *p_enc_ctx, ni_frame_t *p_buffered_frame = &(p_in_data->data.frame); ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config; int new_width, new_height; - int new_bit_depth, new_bit_depth_factor; - + ni_pix_fmt_t new_pix_fmt; + bool isnv12frame; + bool isrgba; + int src_stride[NI_MAX_NUM_DATA_POINTERS]; + new_width = p_buffered_frame->video_width; new_height = p_buffered_frame->video_height; - - switch (p_buffered_frame->pixel_format) + new_pix_fmt = p_buffered_frame->pixel_format; + + // check if resolution is zero copy compatible and set linesize according to new resolution + isnv12frame = (new_pix_fmt == NI_PIX_FMT_NV12 || new_pix_fmt == NI_PIX_FMT_P010LE); + + isrgba = (new_pix_fmt == NI_PIX_FMT_ABGR || new_pix_fmt == NI_PIX_FMT_ARGB + || new_pix_fmt == NI_PIX_FMT_RGBA || new_pix_fmt == NI_PIX_FMT_BGRA); + + // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code + src_stride[0] = new_width * p_enc_ctx->bit_depth_factor; + if (isrgba) { - case NI_PIX_FMT_YUV420P: - case NI_PIX_FMT_NV12: - new_bit_depth = 8; - new_bit_depth_factor = 1; - break; - case NI_PIX_FMT_YUV420P10LE: - case NI_PIX_FMT_P010LE: - new_bit_depth = 10; - new_bit_depth_factor = 2; - break; - default: - new_bit_depth = 8; - new_bit_depth_factor = 1; - break; - } + src_stride[1] = 0; + src_stride[2] = 0; + } + else + { + src_stride[1] = isnv12frame ? src_stride[0] : src_stride[0] / 2; + src_stride[2] = isnv12frame ? 0 : src_stride[0] / 2; + } + + if (ni_encoder_frame_zerocopy_check(p_enc_ctx, + p_api_param, new_width, new_height, + (const int *)src_stride, true) == NI_RETCODE_SUCCESS) + { + new_stride = p_api_param->luma_linesize; // new sequence is zero copy compatible + } + else + { + new_stride = NI_ALIGN(new_width * p_enc_ctx->bit_depth_factor, 128); + } + + if (p_enc_ctx->ori_luma_linesize && p_enc_ctx->ori_chroma_linesize) + { + ori_stride = p_enc_ctx->ori_luma_linesize; // previous sequence was zero copy compatible + } + else + { + ori_stride = NI_ALIGN(p_enc_ctx->ori_width * p_enc_ctx->bit_depth_factor, 128); + } - new_stride = NI_ALIGN(new_width, 128); - ori_stride = NI_ALIGN(p_enc_ctx->ori_width, 128); if (p_api_param->cfg_enc_params.lookAheadDepth) { ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit 2-pass " "lookaheadDepth %d\n", @@ -4984,7 +5402,7 @@ int encoder_reinit_session(ni_session_context_t *p_enc_ctx, bIsSmallPicture = true; } } - + if (p_api_param->cfg_enc_params.multicoreJointMode) { ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit multicore " "joint mode\n"); @@ -4994,65 +5412,240 @@ int encoder_reinit_session(ni_session_context_t *p_enc_ctx, } } + if (p_api_param->cfg_enc_params.crop_width || p_api_param->cfg_enc_params.crop_height) { + ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit needs to close and re-open " + "due to crop width x height\n"); + bIsSmallPicture = true; + } + ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit resolution: %dx%d->%dx%d " "pix fmt: %d->%d bIsSmallPicture %d codec %d\n", ori_stride, p_enc_ctx->ori_height, new_stride, new_height, - p_enc_ctx->ori_pix_fmt, p_buffered_frame->pixel_format, - bIsSmallPicture, + p_enc_ctx->ori_pix_fmt, new_pix_fmt, bIsSmallPicture, p_enc_ctx->codec_format); - + // fast sequence change without close / open only if new resolution < original resolution - if ((ori_stride*p_enc_ctx->ori_height < new_stride*new_height) || - (p_enc_ctx->ori_pix_fmt != p_buffered_frame->pixel_format) || + if (ori_stride*p_enc_ctx->ori_height < new_stride*new_height || + p_enc_ctx->ori_pix_fmt != new_pix_fmt || bIsSmallPicture || - (p_enc_ctx->codec_format == NI_CODEC_FORMAT_JPEG)) { + p_enc_ctx->codec_format == NI_CODEC_FORMAT_JPEG) + { ni_log(NI_LOG_INFO, "XCoder encode sequence change by close / re-open session\n"); encoder_close_session(p_enc_ctx, p_in_data, p_out_data); - ret = encoder_init_session(p_enc_ctx, p_in_data, p_out_data, new_width, new_height, new_bit_depth); + ret = encoder_init_session(p_enc_ctx, p_in_data, p_out_data, new_width, + new_height, new_pix_fmt); + // clear crop parameters upon sequence change because cropping values may not be compatible to new resolution + p_api_param->cfg_enc_params.crop_width = p_api_param->cfg_enc_params.crop_height = 0; + p_api_param->cfg_enc_params.hor_offset = p_api_param->cfg_enc_params.ver_offset = 0; } - else { + else + { if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1) { // AV1 8x8 alignment HW limitation is now worked around by FW cropping input resolution if (new_width % NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT) - ni_log(NI_LOG_ERROR, + ni_log(NI_LOG_ERROR, "resolution change: AV1 Picture Width not aligned to %d - picture will be cropped\n", NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT); if (new_height % NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT) - ni_log(NI_LOG_ERROR, + ni_log(NI_LOG_ERROR, "resolution change: AV1 Picture Height not aligned to %d - picture will be cropped\n", NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT); } ni_log(NI_LOG_INFO, "XCoder encode sequence change by re-config session (fast path)\n"); - ret = encoder_sequence_change(p_enc_ctx, p_in_data, p_out_data, new_width, new_height, new_bit_depth_factor); - } - - // set run state - p_enc_ctx->session_run_state = SESSION_RUN_STATE_SEQ_CHANGE_OPENING; // this state is referenced when sending first frame after sequence change - - ni_log(NI_LOG_DEBUG, - "encoder_reinit_session: session_run_state change to %d \n", - p_enc_ctx->session_run_state); - - return ret; + ret = encoder_sequence_change(p_enc_ctx, p_in_data, p_out_data, new_width, new_height, new_pix_fmt); + } + + // this state is referenced when sending first frame after sequence change + p_enc_ctx->session_run_state = SESSION_RUN_STATE_SEQ_CHANGE_OPENING; + + ni_log(NI_LOG_DEBUG, "%s: session_run_state change to %d \n", __func__, + p_enc_ctx->session_run_state); + + return ret; +} + +static void write_av1_ivf_header(uint32_t width, uint32_t height, + uint32_t frame_num, uint32_t frame_denom, + FILE *p_file) +{ + static int global_ivf_header = 1; + + // write the global ivf start header + if (global_ivf_header && p_file != NULL && !av1_output_obu) + { + uint8_t start_header[32] = { + 0x44, 0x4b, 0x49, 0x46, /* signature: 'DKIF' */ + 0x00, 0x00, /* version: 0 */ + 0x20, 0x00, /* length of header in bytes: 32 */ + 0x41, 0x56, 0x30, 0x31, /* codec FourCC: AV01 */ + 0x00, 0x07, /* width in pixels(little endian), default 1280 */ + 0xd0, 0x02, /* height in pixels(little endian), default 720 */ + 0x1e, 0x00, 0x00, 0x00, /* time base numerator, default 30 */ + 0x01, 0x00, 0x00, 0x00, /* time base denominator, default 1 */ + 0x00, 0x00, 0x00, 0x00, /* number of frames in file */ + 0x00, 0x00, 0x00, 0x00 /* reserved */ + }; + + if (width && height) + { + start_header[12] = width & 0xff; + start_header[13] = ((width >> 8) & 0xff); + start_header[14] = height & 0xff; + start_header[15] = ((height >> 8) & 0xff); + } + + if (frame_num && frame_denom) + { + start_header[16] = frame_num & 0xff; + start_header[17] = ((frame_num >> 8) & 0xff); + start_header[18] = ((frame_num >> 16) & 0xff); + start_header[19] = ((frame_num >> 24) & 0xff); + start_header[20] = frame_denom & 0xff; + start_header[21] = ((frame_denom >> 8) & 0xff); + start_header[22] = ((frame_denom >> 16) & 0xff); + start_header[23] = ((frame_denom >> 24) & 0xff); + } + + if (fwrite(start_header, sizeof(start_header), 1, p_file) != 1) + { + ni_log(NI_LOG_ERROR, "Error: writing ivf start header fail!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + } + + global_ivf_header = 0; + } +} + +static void write_av1_ivf_packet(ni_packet_t *p_out_pkt, uint32_t meta_size, + FILE *p_file) +{ + int i; + + if (!p_file) + { + return; + } + + // write ivf frame header + if (!av1_output_obu) + { + uint32_t pts = muxed_number_of_packets; + uint32_t pkt_size = p_out_pkt->data_len - meta_size; + + if (av1_seq_header_len > 0) + { + pkt_size += av1_seq_header_len - meta_size; + } + for (i = 0; i < p_out_pkt->av1_buffer_index; i++) + { + pkt_size += p_out_pkt->av1_data_len[i] - meta_size; + } + + // ivf frame header + // bytes 0-3: size of frame in bytes(not including the 12-byte header + // byte 4-11: 64-bit pts (here pts=num_of_packets(32-bit), thus here only saves 32-bit + uint8_t ivf_frame_header[12] = {((pkt_size & 0xff)), + ((pkt_size >> 8) & 0xff), + ((pkt_size >> 16) & 0xff), + ((pkt_size >> 24) & 0xff), + ((pts & 0xff)), + ((pts >> 8) & 0xff), + ((pts >> 16) & 0xff), + ((pts >> 24) & 0xff), + 0x00, 0x00, 0x00, 0x00}; + if (fwrite(ivf_frame_header, 12, 1, p_file) != 1) + { + ni_log(NI_LOG_ERROR, "Error: writing ivf frame header fail!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + } + } + + // write the leftover sequence header if there is any + if (av1_seq_header_len > 0) + { + if (fwrite(p_av1_seq_header + meta_size, + av1_seq_header_len - meta_size, 1, p_file) != 1) + { + ni_log(NI_LOG_ERROR, "Error: writing av1 sequence header fail!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + } + ni_aligned_free(p_av1_seq_header); + av1_seq_header_len = 0; + } + + // write the leftover av1 packets + for (i = 0; i < p_out_pkt->av1_buffer_index; i++) + { + if (fwrite((uint8_t *)p_out_pkt->av1_p_data[i] + meta_size, + p_out_pkt->av1_data_len[i] - meta_size, 1, p_file) != 1) + { + ni_log(NI_LOG_ERROR, "Error: writing av1 packets fail!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + } + } + + // write the current packet + if (fwrite((uint8_t *)p_out_pkt->p_data + meta_size, + p_out_pkt->data_len - meta_size, 1, p_file) != 1) + { + ni_log(NI_LOG_ERROR, "Error: writing av1 packets fail!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + } + + muxed_number_of_packets++; +} + +static int write_av1_ivf_trailer(ni_packet_t *p_out_pkt, uint32_t meta_size, + FILE *p_file) +{ + if (p_file) + { + // write the leftover packets + if (p_out_pkt->av1_buffer_index > 0) + { + write_av1_ivf_packet(p_out_pkt, meta_size, p_file); + } + + // update frame_count in ivf start header + if (muxed_number_of_packets && !av1_output_obu) + { + uint8_t frame_cnt[4] = { + (muxed_number_of_packets & 0xff), + ((muxed_number_of_packets >> 8) & 0xff), + ((muxed_number_of_packets >> 16) & 0xff), + ((muxed_number_of_packets >> 24) & 0xff)}; + fseek(p_file, 24, SEEK_SET); + if (fwrite(frame_cnt, 4, 1, p_file) != 1) + { + ni_log(NI_LOG_ERROR, "Error: failed to update frame_cnt in ivf " + "header!\n"); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + return -1; + } + } + } + + return 0; } /*!***************************************************************************** * \brief Receive output data from encoder * - * \param + * \param p_in_data is passed in to specify new frame resolution upon sequence + * change * * \return 0 - success got packet * 1 - received eos * 2 - got nothing, need retry * -1 - failure ******************************************************************************/ -int encoder_receive_data(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_out_data, - int output_video_width, int output_video_height, - FILE *p_file, unsigned long long *total_bytes_received, - int print_time, - ni_session_data_io_t *p_in_data) //p_in_data is passed in to specify new frame resolution upon sequence change +int encoder_receive_data( + ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_out_data, + int output_video_width, int output_video_height, FILE *p_file, + unsigned long long *total_bytes_received, int print_time, + volatile unsigned int *nb_pkts_received, + ni_session_data_io_t * p_in_data) { int packet_size = NI_MAX_TX_SZ; int rc = 0; @@ -5060,24 +5653,25 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, int rx_size = 0; ni_packet_t *p_out_pkt = &(p_out_data->data.packet); int meta_size = p_enc_ctx->meta_size; + ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config; ni_log(NI_LOG_DEBUG, "===> encoder_receive_data <===\n"); - - if (NI_INVALID_SESSION_ID == p_enc_ctx->session_id || - NI_INVALID_DEVICE_HANDLE == p_enc_ctx->blk_io_handle) + if (NI_INVALID_SESSION_ID == p_enc_ctx->session_id) { - ni_log(NI_LOG_DEBUG, "encode session not opened yet, return\n"); - return NI_TEST_RETCODE_SUCCESS; + // keep-alive-thread timeout will set session_id to invalid, should exit + ni_log(NI_LOG_ERROR, + "encode session id invalid, the session should be closed\n"); + return NI_TEST_RETCODE_FAILURE; } +receive_data: rc = ni_packet_buffer_alloc(p_out_pkt, packet_size); if (rc != NI_RETCODE_SUCCESS) { - fprintf(stderr, "Error: malloc packet failed, ret = %d!\n", rc); + ni_log(NI_LOG_ERROR, "Error: malloc packet failed, ret = %d!\n", rc); return NI_TEST_RETCODE_FAILURE; } -receive_data: rc = ni_device_session_read(p_enc_ctx, p_out_data, NI_DEVICE_TYPE_ENCODER); end_flag = p_out_pkt->end_of_stream; @@ -5087,13 +5681,78 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, if (rx_size > meta_size) { - if (p_file && - (fwrite((uint8_t *)p_out_pkt->p_data + meta_size, - p_out_pkt->data_len - meta_size, 1, p_file) != 1)) + if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1) + { + if (p_enc_ctx->pkt_num == 0) + { + write_av1_ivf_header(output_video_width, output_video_height, + p_api_param->fps_number, + p_api_param->fps_denominator, p_file); + // store the sequence header for next packet writing + p_av1_seq_header = (uint8_t *)p_out_pkt->p_data; + av1_seq_header_len = p_out_pkt->data_len; + p_out_pkt->p_buffer = NULL; + p_out_pkt->p_data = NULL; + p_out_pkt->buffer_size = 0; + p_out_pkt->data_len = 0; + } else + { + // store the av1 unshown frames for next packet writing + if (!p_out_pkt->av1_show_frame) + { + p_out_pkt->av1_p_buffer[p_out_pkt->av1_buffer_index] = + p_out_pkt->p_buffer; + p_out_pkt->av1_p_data[p_out_pkt->av1_buffer_index] = + p_out_pkt->p_data; + p_out_pkt->av1_buffer_size[p_out_pkt->av1_buffer_index] = + p_out_pkt->buffer_size; + p_out_pkt->av1_data_len[p_out_pkt->av1_buffer_index] = + p_out_pkt->data_len; + p_out_pkt->av1_buffer_index++; + p_out_pkt->p_buffer = NULL; + p_out_pkt->p_data = NULL; + p_out_pkt->buffer_size = 0; + p_out_pkt->data_len = 0; + if (p_out_pkt->av1_buffer_index >= MAX_AV1_ENCODER_GOP_NUM) + { + ni_log(NI_LOG_ERROR, "Error: recv AV1 not shown frame " + "number %d >= %d\n", p_out_pkt->av1_buffer_index, + MAX_AV1_ENCODER_GOP_NUM); + return NI_TEST_RETCODE_FAILURE; + } + } else + { + ni_log(NI_LOG_DEBUG, "AV1 output packet " + "pts %lld dts %lld\n", p_out_pkt->pts, p_out_pkt->dts); + write_av1_ivf_packet(p_out_pkt, p_enc_ctx->meta_size, p_file); + ni_packet_buffer_free_av1(p_out_pkt); + } + + // recycle hw frame before next read + if (p_enc_ctx->hw_action) + { + // encoder only returns valid recycle index + // when there's something to recycle. + // This range is suitable for all memory bins + if (p_out_pkt->recycle_index > 0 && + p_out_pkt->recycle_index < + NI_GET_MAX_HWDESC_FRAME_INDEX(p_enc_ctx->ddr_config)) + { + ni_hw_frame_unref(p_out_pkt->recycle_index); + p_out_pkt->recycle_index = 0; //clear to not double count + } + } + } + } else { - fprintf(stderr, "Error: writing data %u bytes error!\n", - p_out_pkt->data_len - meta_size); - fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file)); + if (p_file && + (fwrite((uint8_t *)p_out_pkt->p_data + meta_size, + p_out_pkt->data_len - meta_size, 1, p_file) != 1)) + { + ni_log(NI_LOG_ERROR, "Error: writing data %u bytes error!\n", + p_out_pkt->data_len - meta_size); + ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file)); + } } *total_bytes_received += rx_size - meta_size; @@ -5104,19 +5763,18 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, ni_log(NI_LOG_DEBUG, "got encoded stream header, keep reading ..\n"); goto receive_data; } - number_of_packets++; + (*nb_pkts_received)++; - ni_log(NI_LOG_DEBUG, "Got: Packets= %u\n", number_of_packets); + ni_log(NI_LOG_DEBUG, "Got: Packets= %u\n", *nb_pkts_received); } else if (rx_size != 0) { - fprintf(stderr, "Error: received %d bytes, <= metadata size %d!\n", + ni_log(NI_LOG_ERROR, "Error: received %d bytes, <= metadata size %d!\n", rx_size, meta_size); return NI_TEST_RETCODE_FAILURE; - } else if (!end_flag && - ((ni_xcoder_params_t *)(p_enc_ctx->p_session_config)) - ->low_delay_mode) + } else if (!end_flag && p_api_param->low_delay_mode) { ni_log(NI_LOG_DEBUG, "low delay mode and NO pkt, keep reading ..\n"); + ni_usleep(200); goto receive_data; } else { @@ -5141,31 +5799,39 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, return NI_TEST_RETCODE_FAILURE; } } + + if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1) + { + rc = write_av1_ivf_trailer(p_out_pkt, p_enc_ctx->meta_size, p_file); + ni_packet_buffer_free_av1(p_out_pkt); + if (rc < 0) + { + return NI_TEST_RETCODE_FAILURE; + } + } } } if (print_time) { - int timeDiff = (int)(current_time.tv_sec - start_time.tv_sec); - if (timeDiff == 0) + uint32_t time_diff = (uint32_t)(current_time.tv_sec - start_time.tv_sec); + if (time_diff == 0) { - timeDiff = 1; + time_diff = 1; } - printf("[R] Got:%d Packets= %u fps=%f Total bytes %llu\n", rx_size, - number_of_packets, - ((float)number_of_packets) / ((float)timeDiff), + ni_log(NI_LOG_ERROR, "[R] Got:%d Packets= %u fps=%f Total bytes %llu\n", rx_size, + *nb_pkts_received, (float)p_enc_ctx->frame_num / (float)time_diff, *total_bytes_received); } if (end_flag) { - printf("Encoder Receiving done.\n"); + ni_log(NI_LOG_INFO, "Encoder Receiving done.\n"); return NI_TEST_RETCODE_END_OF_STREAM; } else if (0 == rx_size) { return NI_TEST_RETCODE_EAGAIN; } - ni_log(NI_LOG_DEBUG, "encoder_receive_data: success\n"); return NI_TEST_RETCODE_SUCCESS; @@ -5189,6 +5855,7 @@ void set_demo_roi_map(ni_session_context_t *p_enc_ctx) // mode non-1: reverse of mode 1 int importanceLevelCentre = p_param->roi_demo_mode == 1 ? 40 : 10; int importanceLevelRest = p_param->roi_demo_mode == 1 ? 10 : 40; + int32_t width, height; if (!p_enc_ctx->roi_map) { @@ -5206,11 +5873,21 @@ void set_demo_roi_map(ni_session_context_t *p_enc_ctx) max_cu_size = 16; roiMapBlockUnitSize = 16; } + + width = p_param->source_width; + height = p_param->source_height; + // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation + if (NI_CODEC_FORMAT_AV1 == p_enc_ctx->codec_format) + { + width = (width / 8) * 8; + height = (height / 8) * 8; + } + mbWidth = - ((p_param->source_width + max_cu_size - 1) & (~(max_cu_size - 1))) / + ((width + max_cu_size - 1) & (~(max_cu_size - 1))) / roiMapBlockUnitSize; mbHeight = - ((p_param->source_height + max_cu_size - 1) & (~(max_cu_size - 1))) / + ((height + max_cu_size - 1) & (~(max_cu_size - 1))) / roiMapBlockUnitSize; numMbs = mbWidth * mbHeight; @@ -5255,14 +5932,32 @@ void set_demo_roi_map(ni_session_context_t *p_enc_ctx) * * \return 0 if successful, < 0 otherwise ******************************************************************************/ -int encoder_open_session( - ni_session_context_t *p_enc_ctx, int dst_codec_format, int iXcoderGUID, - ni_xcoder_params_t *p_enc_params, int src_bit_depth, int width, int height, - ni_hrd_params_t *hrd_params, ni_color_primaries_t color_primaries, - ni_color_transfer_characteristic_t color_trc, ni_color_space_t color_space, - int video_full_range_flag, int sar_num, int sar_den, int is_planar) +int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format, + int iXcoderGUID, ni_xcoder_params_t *p_enc_params, + int width, int height, + ni_color_primaries_t color_primaries, + ni_color_transfer_characteristic_t color_trc, + ni_color_space_t color_space, int video_full_range_flag, + int sar_num, int sar_den, ni_pix_fmt_t pix_fmt, + ni_rate_emu_t *p_rate_emu, + bool check_zerocopy) { int ret = 0; + bool isrgba = false; + + // p_rate_emu is NULL for sequence change - do not reset rate emu start time upon sequence change + if (p_rate_emu) + { + p_rate_emu->rate_emu_start = ni_gettime_ns(); + p_rate_emu->rate_emu_input_frames = 0; + } + + if (video_full_range_flag < 0) + { + ni_log(NI_LOG_ERROR, "ERROR %s: The video full range flag is %d should " + "be indicated excplicitly as 0 or 1!\n", __func__); + return -1; + } p_enc_ctx->p_session_config = p_enc_params; p_enc_ctx->session_id = NI_INVALID_SESSION_ID; @@ -5275,56 +5970,83 @@ int encoder_open_session( p_enc_ctx->hw_id = iXcoderGUID; // default: little endian - p_enc_ctx->src_bit_depth = src_bit_depth; p_enc_ctx->src_endian = NI_FRAME_LITTLE_ENDIAN; - p_enc_ctx->bit_depth_factor = 1; - p_enc_ctx->pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P : NI_PIX_FMT_NV12); - if (10 == p_enc_ctx->src_bit_depth) + + switch (pix_fmt) { - p_enc_ctx->bit_depth_factor = 2; - p_enc_ctx->pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P10LE : NI_PIX_FMT_P010LE); + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_NV12: + p_enc_ctx->src_bit_depth = 8; + p_enc_ctx->bit_depth_factor = 1; + break; + case NI_PIX_FMT_YUV420P10LE: + case NI_PIX_FMT_P010LE: + p_enc_ctx->src_bit_depth = 10; + p_enc_ctx->bit_depth_factor = 2; + break; + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + p_enc_ctx->src_bit_depth = 8; + p_enc_ctx->bit_depth_factor = 4; + isrgba = true; + break; + default: + p_enc_ctx->src_bit_depth = 8; + p_enc_ctx->bit_depth_factor = 1; + pix_fmt = NI_PIX_FMT_YUV420P; + break; + //ni_log(NI_LOG_ERROR, "%s: Invalid pixel format %s\n", __func__, + // ni_pixel_format_name(pix_fmt)); + //return NI_RETCODE_INVALID_PARAM; } // original resolution this stream started with, this is used by encoder sequence change p_enc_ctx->ori_width = width; p_enc_ctx->ori_height = height; p_enc_ctx->ori_bit_depth_factor = p_enc_ctx->bit_depth_factor; - p_enc_ctx->ori_pix_fmt = p_enc_ctx->pixel_format; + p_enc_ctx->ori_pix_fmt = pix_fmt; + p_enc_ctx->pixel_format = pix_fmt; int linesize_aligned = width; - if (linesize_aligned < NI_MIN_WIDTH) - { - p_enc_params->cfg_enc_params.conf_win_right += - (NI_MIN_WIDTH - width) / 2 * 2; - linesize_aligned = NI_MIN_WIDTH; - } else + if (!isrgba) { - linesize_aligned = ((width + 1) / 2) * 2; - p_enc_params->cfg_enc_params.conf_win_right += - (linesize_aligned - width) / 2 * 2; + if (linesize_aligned < NI_MIN_WIDTH) + { + p_enc_params->cfg_enc_params.conf_win_right += + (NI_MIN_WIDTH - width) / 2 * 2; + linesize_aligned = NI_MIN_WIDTH; + } else + { + linesize_aligned = ((width + 1) / 2) * 2; + p_enc_params->cfg_enc_params.conf_win_right += + (linesize_aligned - width) / 2 * 2; + } } p_enc_params->source_width = linesize_aligned; int height_aligned = height; - if (height_aligned < NI_MIN_HEIGHT) - { - p_enc_params->cfg_enc_params.conf_win_bottom += - (NI_MIN_HEIGHT - height) / 2 * 2; - height_aligned = NI_MIN_HEIGHT; - } else + if (!isrgba) { - height_aligned = ((height + 1) / 2) * 2; - p_enc_params->cfg_enc_params.conf_win_bottom += - (height_aligned - height) / 2 * 2; + if (height_aligned < NI_MIN_HEIGHT) + { + p_enc_params->cfg_enc_params.conf_win_bottom += + (NI_MIN_HEIGHT - height) / 2 * 2; + height_aligned = NI_MIN_HEIGHT; + } else + { + height_aligned = ((height + 1) / 2) * 2; + p_enc_params->cfg_enc_params.conf_win_bottom += + (height_aligned - height) / 2 * 2; + } } p_enc_params->source_height = height_aligned; // VUI setting including color setting is done by specifying them in the // encoder config p_enc_params->cfg_enc_params.colorDescPresent = 0; - // ToDo: when to enable + if ((color_primaries != NI_COL_PRI_UNSPECIFIED) || (color_space != NI_COL_SPC_UNSPECIFIED) || (color_trc != NI_COL_TRC_UNSPECIFIED)) @@ -5338,18 +6060,41 @@ int encoder_open_session( p_enc_params->cfg_enc_params.aspectRatioWidth = sar_num; p_enc_params->cfg_enc_params.aspectRatioHeight = sar_den; - // default planar encoder input data; ToDo: HW frames - p_enc_params->cfg_enc_params.planar = is_planar; + // default planar encoder input data + p_enc_params->cfg_enc_params.planar = get_pixel_planar(pix_fmt); p_enc_params->video_full_range_flag = video_full_range_flag; + if (check_zerocopy) + { + + // config linesize for zero copy (if input resolution is zero copy compatible) + int src_stride[NI_MAX_NUM_DATA_POINTERS]; + + // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code + src_stride[0] = width * p_enc_ctx->bit_depth_factor; + + if (isrgba) + src_stride[1] = src_stride[2] = 0; + else + { + bool isnv12frame = (p_enc_params->cfg_enc_params.planar == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) ? true : false; + src_stride[1] = isnv12frame ? src_stride[0] : src_stride[0] / 2; + src_stride[2] = isnv12frame ? 0 : src_stride[0] / 2; + } + + ni_encoder_frame_zerocopy_check(p_enc_ctx, + p_enc_params, width, height, + (const int *)src_stride, true); + } + ret = ni_device_session_open(p_enc_ctx, NI_DEVICE_TYPE_ENCODER); - if (ret < 0) + if (ret != NI_RETCODE_SUCCESS) { - fprintf(stderr, "Error: encoder_open_session failure!\n"); + ni_log(NI_LOG_ERROR, "Error: %s failure!\n", __func__); } else { - printf("Encoder device %d session open successful.\n", iXcoderGUID); + ni_log(NI_LOG_INFO, "Encoder device %d session open successful.\n", iXcoderGUID); } // set up ROI QP map for ROI demo modes if enabled @@ -5402,11 +6147,10 @@ int encoder_close_session(ni_session_context_t *p_enc_ctx, * \return 0 if successful, < 0 otherwise ******************************************************************************/ int encoder_init_session(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_in_data, - ni_session_data_io_t *p_out_data, - int arg_width, - int arg_height, - int bit_depth) + ni_session_data_io_t *p_in_data, + ni_session_data_io_t *p_out_data, + int arg_width, int arg_height, + ni_pix_fmt_t pix_fmt) { int ret = 0; ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config; @@ -5414,12 +6158,15 @@ int encoder_init_session(ni_session_context_t *p_enc_ctx, ni_log(NI_LOG_DEBUG, "XCoder encode sequence change (re-open): session_run_state %d\n", p_enc_ctx->session_run_state); // for encode from YUV, use all the parameters specified by user - ret = encoder_open_session( - p_enc_ctx, p_enc_ctx->codec_format, p_enc_ctx->hw_id, p_api_param, bit_depth, - arg_width, arg_height, NULL, p_api_param->color_primaries, - p_api_param->color_transfer_characteristic, p_api_param->color_space, - p_api_param->video_full_range_flag, p_api_param->sar_num, p_api_param->sar_denom, - 1); + ret = encoder_open_session(p_enc_ctx, p_enc_ctx->codec_format, + p_enc_ctx->hw_id, p_api_param, arg_width, + arg_height, p_api_param->color_primaries, + p_api_param->color_transfer_characteristic, + p_api_param->color_space, + p_api_param->video_full_range_flag, + p_api_param->sar_num, p_api_param->sar_denom, + pix_fmt, + NULL, true); if (NI_RETCODE_SUCCESS != ret) { ni_log(NI_LOG_ERROR, "Failed to Re-open Encoder Session upon Sequence Change (status = %d)\n", ret); @@ -5434,16 +6181,33 @@ int encoder_init_session(ni_session_context_t *p_enc_ctx, int encoder_sequence_change(ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_in_data, ni_session_data_io_t *p_out_data, - int width, - int height, - int bit_depth_factor) + int width, int height, ni_pix_fmt_t pix_fmt) { ni_retcode_t ret = 0; + int bit_depth; + int bit_depth_factor; ni_log(NI_LOG_DEBUG, "XCoder encode sequence change (reconfig): session_run_state %d\n", p_enc_ctx->session_run_state); - ret = ni_device_session_sequence_change(p_enc_ctx, width, height, bit_depth_factor, NI_DEVICE_TYPE_ENCODER); + switch (pix_fmt) + { + case NI_PIX_FMT_YUV420P: + case NI_PIX_FMT_NV12: + bit_depth = 8; + bit_depth_factor = 1; + break; + case NI_PIX_FMT_YUV420P10LE: + case NI_PIX_FMT_P010LE: + bit_depth = 10; + bit_depth_factor = 2; + break; + default: + bit_depth = 8; + bit_depth_factor = 1; + break; + } + ret = ni_device_session_sequence_change(p_enc_ctx, width, height, bit_depth_factor, NI_DEVICE_TYPE_ENCODER); if (NI_RETCODE_SUCCESS != ret) { ni_log(NI_LOG_ERROR, "Failed to send Sequence Change to Encoder Session (status = %d)\n", ret); @@ -5452,7 +6216,7 @@ int encoder_sequence_change(ni_session_context_t *p_enc_ctx, // update session context p_enc_ctx->bit_depth_factor = bit_depth_factor; - p_enc_ctx->src_bit_depth = (bit_depth_factor == 1) ? 8 : 10; + p_enc_ctx->src_bit_depth = bit_depth; // xcoder demo only support little endian (for 10-bit pixel format) p_enc_ctx->src_endian = NI_FRAME_LITTLE_ENDIAN; p_enc_ctx->ready_to_close = 0; @@ -5495,13 +6259,13 @@ int decoder_open_session(ni_session_context_t *p_dec_ctx, int iXcoderGUID, ret = ni_device_session_open(p_dec_ctx, NI_DEVICE_TYPE_DECODER); - if (ret < 0) + if (ret != NI_RETCODE_SUCCESS) { - fprintf(stderr, "Error: ni_decoder_session_open() failure!\n"); + ni_log(NI_LOG_ERROR, "Error: ni_decoder_session_open() failure!\n"); return -1; } else { - printf("Decoder device %d session open successful.\n", iXcoderGUID); + ni_log(NI_LOG_INFO, "Decoder device %d session open successful.\n", iXcoderGUID); return 0; } } @@ -5514,8 +6278,8 @@ int decoder_open_session(ni_session_context_t *p_dec_ctx, int iXcoderGUID, * \return 0 if successful, < 0 otherwise ******************************************************************************/ int uploader_open_session(ni_session_context_t *p_upl_ctx, int iXcoderGUID, - int src_bit_depth, int width, int height, - int is_planar, int pool_size) + int width, int height, ni_pix_fmt_t pix_fmt, + int is_p2p, int pool_size) { int ret = 0; p_upl_ctx->session_id = NI_INVALID_SESSION_ID; @@ -5526,299 +6290,182 @@ int uploader_open_session(ni_session_context_t *p_upl_ctx, int iXcoderGUID, p_upl_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE; p_upl_ctx->hw_id = iXcoderGUID; - // default: little endian - p_upl_ctx->src_bit_depth = src_bit_depth; - p_upl_ctx->src_endian = NI_FRAME_LITTLE_ENDIAN; - p_upl_ctx->bit_depth_factor = 1; - p_upl_ctx->pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P : NI_PIX_FMT_NV12); - if (10 == p_upl_ctx->src_bit_depth) - { - p_upl_ctx->bit_depth_factor = 2; - p_upl_ctx->src_bit_depth = 10; - p_upl_ctx->pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P10LE : NI_PIX_FMT_P010LE); - } else if (32 == p_upl_ctx->src_bit_depth) - { - //rgba, not currently supported in this tool - fprintf(stderr, "Error: uploader rgba is toDO!\n"); - return -1; + // Set the input frame format of the upload session + ret = ni_uploader_set_frame_format(p_upl_ctx, width, height, pix_fmt, is_p2p); + if(ret != NI_RETCODE_SUCCESS) + { + ni_log(NI_LOG_ERROR, "Error: %s failure. Failed to set uploader format!\n", __func__); + return ret; } - p_upl_ctx->active_video_width = width; - p_upl_ctx->active_video_height = height; ret = ni_device_session_open(p_upl_ctx, NI_DEVICE_TYPE_UPLOAD); - if (ret < 0) + if (ret != NI_RETCODE_SUCCESS) { - fprintf(stderr, "Error: uploader_open_session failure!\n"); + ni_log(NI_LOG_ERROR, "Error: %s failure!\n", __func__); return ret; } else { - printf("Uploader device %d session open successful.\n", iXcoderGUID); + ni_log(NI_LOG_INFO, "Uploader device %d session open successful.\n", iXcoderGUID); } + ret = ni_device_session_init_framepool(p_upl_ctx, pool_size, 0); if (ret < 0) { - fprintf(stderr, "Error: uploader_config_session failure!\n"); - } else - { - printf("Uploader device %d configured successful.\n", iXcoderGUID); - } - return ret; -} - -void print_usage(void) -{ - printf("Video decoder/encoder/transcoder application directly using Netint " - "Libxcoder release v%s\n" - "Usage: xcoder [options]\n" - "\n" - "options:\n" - "-h | --help Show help.\n" - "-v | --version Print version info.\n" - "-t | --multi-thread Enable multi-threaded sending and receiving" - " in all modes.\n" - "-l | --loglevel Set loglevel of libxcoder API.\n" - " [none, fatal, error, info, debug, trace]\n" - " (Default: info)\n" - "-c | --card Set card index to use.\n" - " See `ni_rsrc_mon` for cards on system.\n" - " (Default: 0)\n" - "-i | --input Input file path.\n" - "-r | --repeat (Positive integer) to Repeat input X \n" - " times for performance test.(Default: 1)\n" - "-s | --size Resolution of input file in format " - "WIDTHxHEIGHT.\n" - " (eg. '1920x1080')\n" - "-m | --mode Input to output codec processing mode in " - "format:\n" - " InType2OutType. [a2y, h2y, y2a, u2a, y2h, " - "u2h, a2a, " - "a2h, h2a, h2h, y2x, u2x, v2y]\n" - " Type notation: y=YUV420P a=AVC, h=HEVC, " - "v=VP9, x=AV1, " - "u=hwupload yuv\n" - "-b | --bitdepth Input and output bit depth. [8, 10]\n" - " (Default: 8)\n" - "-x | --xcoder-params Encoding params. See \"Encoding " - "Parameters\" chapter in\n" - " " - "QuadraIntegration&ProgrammingGuide*.pdf for help.\n" - " (Default: \"\")\n" - "-d | --decoder-params Decoding params. See \"Decoding " - "Parameters\" chapter in\n" - " " - "QuadraIntegration&ProgrammingGuide*.pdf for help.\n" - " (Default: \"\")\n" - "-o | --output Output file path.\n" - "-f | --vf Scaling params. Example: " - "ni_width=1280:ni_height=720:format=0:p2p=1.\n", - NI_XCODER_REVISION); -} - -// retrieve key and value from 'key=value' pair, return 0 if successful -// otherwise non-0 -static int get_key_value(char *p_str, char *key, char *value) -{ - if (!p_str || !key || !value) - { - return 1; - } - - char *p = strchr(p_str, '='); - if (!p) - { - return 1; + ni_log(NI_LOG_ERROR, "Error: %s failure!\n", __func__); } else { - *p = '\0'; - key[0] = '\0'; - value[0] = '\0'; - strcpy(key, p_str); - strcpy(value, p + 1); - return 0; - } -} - -// retrieve config parameter valus from --xcoder-params, -// return 0 if successful, -1 otherwise -static int retrieve_xcoder_params(char xcoderParams[], - ni_xcoder_params_t *params, - ni_session_context_t *ctx) -{ - char key[64], value[64]; - char *p = xcoderParams; - char *curr = xcoderParams, *colon_pos; - int ret = 0; - - while (*curr) - { - colon_pos = strchr(curr, ':'); - - if (colon_pos) - { - *colon_pos = '\0'; - } - - if (strlen(curr) > sizeof(key) + sizeof(value) - 1 || - get_key_value(curr, key, value)) - { - fprintf(stderr, - "Error: xcoder-params p_config key/value not " - "retrieved: %s\n", - curr); - ret = -1; - break; - } - ret = ni_encoder_params_set_value(params, key, value); - switch (ret) - { - case NI_RETCODE_PARAM_INVALID_NAME: - fprintf(stderr, "Error: unknown option: %s.\n", key); - break; - case NI_RETCODE_PARAM_INVALID_VALUE: - fprintf(stderr, "Error: invalid value for %s: %s.\n", key, - value); - break; - default: - break; - } - - if (NI_RETCODE_SUCCESS != ret) - { - fprintf(stderr, "Error: config parsing failed %d: %s\n", ret, - ni_get_rc_txt(ret)); - break; - } - - if (colon_pos) - { - curr = colon_pos + 1; - } else - { - curr += strlen(curr); - } + ni_log(NI_LOG_INFO, "Uploader device %d configured successful.\n", iXcoderGUID); } - ctx->keep_alive_timeout = params->cfg_enc_params.keep_alive_timeout; return ret; } -// retrieve config parameter valus from --decoder-params, -// return 0 if successful, -1 otherwise -static int retrieve_decoder_params(char xcoderParams[], - ni_xcoder_params_t *params, - ni_session_context_t *ctx) +void print_usage(void) { - char key[64], value[64]; - char *p = xcoderParams; - char *curr = xcoderParams, *colon_pos; - int ret = 0; - - while (*curr) - { - colon_pos = strchr(curr, ':'); - - if (colon_pos) - { - *colon_pos = '\0'; - } - - if (strlen(curr) > sizeof(key) + sizeof(value) - 1 || - get_key_value(curr, key, value)) - { - fprintf(stderr, - "Error: decoder-params p_config key/value not " - "retrieved: %s\n", - curr); - ret = -1; - break; - } - ret = ni_decoder_params_set_value(params, key, value); - switch (ret) - { - case NI_RETCODE_PARAM_INVALID_NAME: - fprintf(stderr, "Error: unknown option: %s.\n", key); - break; - case NI_RETCODE_PARAM_INVALID_VALUE: - fprintf(stderr, "Error: invalid value for %s: %s.\n", key, - value); - break; - default: - break; - } - - if (NI_RETCODE_SUCCESS != ret) - { - fprintf(stderr, "Error: config parsing failed %d: %s\n", ret, - ni_get_rc_txt(ret)); - break; - } - - if (colon_pos) - { - curr = colon_pos + 1; - } else - { - curr += strlen(curr); - } - } - ctx->keep_alive_timeout = params->dec_input_params.keep_alive_timeout; - ctx->decoder_low_delay = params->dec_input_params.decoder_low_delay; - - return ret; + printf( + "Video decoder/encoder/transcoder application directly using Netint " + "Libxcoder release v%s\n" + "Usage: xcoder [options]\n" + "\n" + "options:\n" + "-h | --help Show help.\n" + "-v | --version Print version info.\n" + "-t | --multi-thread Enable multi-threaded sending and " + "receiving" + " in all modes.\n" + "-l | --loglevel Set loglevel of libxcoder API.\n" + " [none, fatal, error, info, debug, " + "trace]\n" + " (Default: info)\n" + "-c | --card Set card index to use.\n" + " See `ni_rsrc_mon` for cards on " + "system.\n" + " (Default: 0)\n" + "-i | --input Input file path.\n" + "-r | --repeat (Positive integer) to Repeat input X \n" + " times for performance test.(Default: " + "1)\n" + "-e | --readframerate Read input at specified frame rate.\n" + " Currently only available for ENCODE " + "modes (y2a, y2h, y2x, y2o)\n" + "-p | --pix_fmt Indicate the pixel format of the " + "input.\n" + " (Default: yuv420p)\n" + " Read raw video and do encode: [yuv420p, yuv420p10le, nv12, p010le, " + "rgba, gbra, argb, abgr, bgr0, yuv444p]\n" + " Upload and do encode: [yuv420p, yuv420p10le, nv12, p010le, " + "rgba, gbra, argb, abgr, bgr0]\n" + "-s | --size Resolution of input file in format " + "WIDTHxHEIGHT.\n" + " (eg. '1920x1080')\n" + "-m | --mode Input to output codec processing mode " + "in " + "format:\n" + " InType2OutType. [a2y, h2y, y2a, u2a, " + "y2h, " + "u2h, a2a, " + "a2h, h2a, h2h, y2x, y2o, u2x, v2y, v2a, v2h, v2x, h2x, a2x, a2r]\n" + " Type notation: y=YUV420P a=AVC, " + "h=HEVC, " + "v=VP9, x=AV1 IVF, o=AV1 OBU, " + "u=hwupload yuv, " + "r=scaler p2p demo\n" + "-b | --bitdepth Input and output bit depth. [8, 10]\n" + " (Default: 8)\n" + "-u | --user_data_sei_passthru Enable user data unregistered SEI " + "passthrough.\n" + "-x | --xcoder-params Encoding params. See \"Encoding " + "Parameters\" chapter in\n" + " " + "QuadraIntegration&ProgrammingGuide*.pdf for help.\n" + " " + "Can be specified multiple (max MAX_OUTPUT_FILES) times \n" + " " + "for HWUpload + Encoding for non-AV1 codec in single \n" + " " + "thread mode. Must match the number of -o specified.\n" + " (Default: \"\")\n" + "-g | --xcoder-gop Custom GOP for encoding. See \"Custom " + " Gop Structure\" chapter in\n" + " " + "QuadraIntegration&ProgrammingGuide*.pdf for help.\n" + " (Default: \"\")\n" + " " + "gopPresetIdx must be set to 0 to be in effect.\n" + "-d | --decoder-params Decoding params. See \"Decoding " + "Parameters\" chapter in\n" + " " + "QuadraIntegration&ProgrammingGuide*.pdf for help.\n" + " (Default: \"\")\n" + "-o | --output Output file path.\n" + " " + "Can be specified multiple (max MAX_OUTPUT_FILES) times \n" + " " + "for HWUpload + Encoding for non-AV1 codec in single \n" + " " + "thread mode. Must match the number of -x specified.\n" + "-f | --vf Scaling params. Example: " + "ni_width=1280:ni_height=720:format=0:p2p=1.\n", + NI_XCODER_REVISION); } void *decoder_send_thread(void *args) { dec_send_param_t *p_dec_send_param = args; ni_session_context_t *p_dec_ctx = p_dec_send_param->p_dec_ctx; - int sos_flag = 1; - int retval; + int retval = 0; - printf("decoder_send_thread start\n"); - for (;;) + ni_log(NI_LOG_INFO, "decoder_send_thread start: decoder_low_delay %d\n", + p_dec_ctx->decoder_low_delay); + while (!g_end_of_all_threads) { retval = decoder_send_data( - p_dec_ctx, p_dec_send_param->p_in_pkt, sos_flag, + p_dec_ctx, p_dec_send_param->p_in_pkt, p_dec_send_param->input_video_width, p_dec_send_param->input_video_height, p_dec_send_param->pkt_size, - total_file_size, p_dec_send_param->p_total_bytes_sent, - p_dec_send_param->print_time, p_dec_send_param->p_xcodeState, + p_dec_send_param->p_total_bytes_sent, + p_dec_send_param->print_time, p_dec_send_param->p_xcoder_state, p_dec_send_param->p_stream_info); - sos_flag = 0; if (retval < 0) // Error { - fprintf(stderr, "Error: decoder_send_thread break!\n"); + ni_log(NI_LOG_ERROR, "Error: decoder_send_thread break!\n"); break; - } else if (p_dec_send_param->p_xcodeState->dec_eos_sent) //eos + } else if (p_dec_send_param->p_xcoder_state->dec_eos_sent) //eos { - printf("decoder_send_thread reach eos\n"); + ni_log(NI_LOG_INFO, "decoder_send_thread reach eos\n"); break; } } + // Broadcast all codec threads to quit on exception such as NVMe IO. + if (retval < 0) + { + g_end_of_all_threads = 1; + } + ni_log(NI_LOG_TRACE, "decoder_send_thread exit\n"); - return NULL; + return (void *)(long)retval; } void *decoder_receive_thread(void *args) { dec_recv_param_t *p_dec_recv_param = args; - ni_test_frame_list_t *frame_list = p_dec_recv_param->test_frame_list; + ni_test_frame_list_t *frame_list = p_dec_recv_param->frame_list; ni_session_data_io_t *p_out_frame = NULL; ni_frame_t *p_ni_frame = NULL; - int retval; + int retval = 0; int print_time; struct timeval previous_time_l = previous_time; + int rx_size = 0; + + ni_log(NI_LOG_INFO, "decoder_receive_thread start\n"); - printf("decoder_receive_thread start\n"); for (;;) { if (p_dec_recv_param->mode == XCODER_APP_DECODE) { (void)ni_gettimeofday(¤t_time, NULL); - print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1); + print_time = need_time_print(¤t_time, &previous_time); p_ni_frame = &p_dec_recv_param->p_out_frame->data.frame; retval = decoder_receive_data( p_dec_recv_param->p_dec_ctx, p_dec_recv_param->p_out_frame, @@ -5826,20 +6473,32 @@ void *decoder_receive_thread(void *args) p_dec_recv_param->output_video_height, p_dec_recv_param->p_file, p_dec_recv_param->p_total_bytes_received, print_time, 1, // save to file - p_dec_recv_param->p_xcodeState); - ni_decoder_frame_buffer_free(p_ni_frame); + p_dec_recv_param->p_xcoder_state, + &rx_size); + + if (p_dec_recv_param->p_dec_ctx->hw_action == NI_CODEC_HW_ENABLE) + { + niFrameSurface1_t *p_hwframe = (niFrameSurface1_t *)p_dec_recv_param->p_out_frame->data.frame.p_data[3]; + ni_log(NI_LOG_DEBUG, "decoder_receive_thread HW decode-only. recycle HW frame idx %u\n", p_hwframe->ui16FrameIdx); + ni_hwframe_buffer_recycle2(p_hwframe); + ni_frame_buffer_free(p_ni_frame); + } else + { + ni_decoder_frame_buffer_free(p_ni_frame); + } if (retval < 0) // Error { - fprintf( - stderr, + ni_log( + NI_LOG_ERROR, "Error: decoder_receive_thread break in decode mode!\n"); break; } else if (p_ni_frame->end_of_stream) //eos { - printf("decoder_receive_thread reach eos\n"); + ni_log(NI_LOG_INFO, "decoder_receive_thread reach eos\n"); + retval = 0; break; - } else if (retval == 2) + } else if (retval == NI_TEST_RETCODE_EAGAIN) { ni_usleep(100); } @@ -5849,12 +6508,18 @@ void *decoder_receive_thread(void *args) } } else { - while (test_frames_isfull(frame_list)) + while (frame_list_is_full(frame_list) && !g_end_of_all_threads) { ni_usleep(100); } - print_time = ((current_time.tv_sec - previous_time_l.tv_sec) > 1); - p_out_frame = &frame_list->ni_test_frame[frame_list->tail]; + + if (g_end_of_all_threads) + { + break; + } + + print_time = need_time_print(¤t_time, &previous_time_l); + p_out_frame = &frame_list->frames[frame_list->tail]; p_ni_frame = &p_out_frame->data.frame; retval = decoder_receive_data( p_dec_recv_param->p_dec_ctx, p_out_frame, @@ -5862,7 +6527,8 @@ void *decoder_receive_thread(void *args) p_dec_recv_param->output_video_height, p_dec_recv_param->p_file, p_dec_recv_param->p_total_bytes_received, print_time, 0, // do not save to file - p_dec_recv_param->p_xcodeState); + p_dec_recv_param->p_xcoder_state, + &rx_size); if (retval < 0) // Error { if (!p_dec_recv_param->p_dec_ctx->hw_action) @@ -5872,16 +6538,17 @@ void *decoder_receive_thread(void *args) { ni_frame_buffer_free(p_ni_frame); } - fprintf( - stderr, + ni_log( + NI_LOG_ERROR, "Error: decoder_receive_thread break in transcode mode!\n"); break; - } else if (p_ni_frame->end_of_stream) //eos + } else if (p_ni_frame->end_of_stream) { - enq_test_frames(frame_list); - printf("decoder_receive_thread reach eos\n"); + frame_list_enqueue(frame_list); + ni_log(NI_LOG_INFO, "decoder_receive_thread reach eos\n"); + retval = 0; break; - } else if (retval == 2) // eagain + } else if (retval == NI_TEST_RETCODE_EAGAIN) { if (!p_dec_recv_param->p_dec_ctx->hw_action) { @@ -5902,7 +6569,7 @@ void *decoder_receive_thread(void *args) ni_log(NI_LOG_DEBUG, "decoder recv:%d, tail:%d\n", current_hwframe_index, frame_list->tail); } - enq_test_frames(frame_list); + frame_list_enqueue(frame_list); } if (print_time) { @@ -5912,307 +6579,359 @@ void *decoder_receive_thread(void *args) } } + // Broadcast all codec threads to quit on exception such as NVMe IO. + if (retval < 0) + { + g_end_of_all_threads = 1; + } + ni_log(NI_LOG_TRACE, "decoder_receive_thread exit\n"); - return NULL; + return (void *)(long)retval; } void *encoder_send_thread(void *args) { enc_send_param_t *p_enc_send_param = args; - ni_session_context_t *p_enc_ctx = p_enc_send_param->p_enc_ctx; - ni_test_frame_list_t *frame_list = p_enc_send_param->test_frame_list; + ni_session_context_t *p_enc_ctx_list = p_enc_send_param->p_enc_ctx; + ni_test_frame_list_t *frame_list = p_enc_send_param->frame_list; ni_session_data_io_t *p_dec_frame = NULL; ni_session_data_io_t *p_upl_frame = NULL; + ni_session_data_io_t sw_pix_frame[2]; ni_frame_t *p_ni_frame = NULL; - int need_to_resend = 0; - int input_exhausted = 0; - int sos_flag = 1; - int retval; + niFrameSurface1_t *p_surface; + int i, ret = 0; int input_index = 0; - int input_total = p_enc_send_param->input_total; - int is_last_input; + int chunk_size; + int eos = 0; + + ni_log(NI_LOG_INFO, "%s start\n", __func__); + + memset(sw_pix_frame, 0, 2 * sizeof(ni_session_data_io_t)); - printf("encoder_send_thread start\n"); for (;;) { if (p_enc_send_param->mode == XCODER_APP_ENCODE) { - is_last_input = (input_index == (input_total-1)) ? 1 : 0; - - retval = encoder_send_data( - p_enc_ctx, - p_enc_send_param->p_in_frame, - sos_flag, - p_enc_send_param->input_arg_width[input_index], - p_enc_send_param->input_arg_height[input_index], - p_enc_send_param->input_arg_pfs[input_index], - total_file_size, - p_enc_send_param->p_total_bytes_sent, - p_enc_send_param->p_xcodeState, - p_enc_send_param->input_bit_depth[input_index], - is_last_input); - sos_flag = 0; - if (retval < 0) // Error + chunk_size = read_yuv_from_file( + p_enc_send_param->input_arg_pfs[input_index], + p_enc_send_param->yuv_buf, + p_enc_send_param->input_arg_width[input_index], + p_enc_send_param->input_arg_height[input_index], + p_enc_ctx_list[0].pixel_format, + p_enc_send_param->sw_pix_fmt, &eos, + p_enc_ctx_list[0].session_run_state); + if (chunk_size < 0) { - fprintf(stderr, - "Error: encoder_send_thread break in encode mode!\n"); break; - } else if (retval == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change) + } + + // YUV444P conversion + if (p_enc_send_param->sw_pix_fmt != NI_SW_PIX_FMT_NONE) + { + ret = convert_yuv_444p_to_420p(&sw_pix_frame[0], + eos ? NULL : p_enc_send_param->yuv_buf, + p_enc_send_param->input_arg_width[input_index], + p_enc_send_param->input_arg_height[input_index], + p_enc_send_param->sw_pix_fmt, 0, + p_enc_send_param->dec_codec_format); + if (ret < 0) + { + break; + } + } + + for (i = 0; i < p_enc_send_param->output_total; i++) + { + if (p_enc_send_param->sw_pix_fmt != NI_SW_PIX_FMT_NONE) + { + ret = encoder_send_data3(&p_enc_ctx_list[i], + &sw_pix_frame[i], + p_enc_send_param->input_arg_width[input_index], + p_enc_send_param->input_arg_height[input_index], + &p_enc_send_param->p_xcoder_state[i], eos); + } else + { + ret = encoder_send_data(&p_enc_ctx_list[i], + p_enc_send_param->p_in_frame, + eos ? NULL : p_enc_send_param->yuv_buf, + p_enc_send_param->input_arg_width[input_index], + p_enc_send_param->input_arg_height[input_index], + p_enc_send_param->p_total_bytes_sent, + &p_enc_send_param->p_xcoder_state[i], + input_index == p_enc_send_param->input_total - 1, + &p_enc_send_param->p_rate_emu[i]); + } + + if (ret < 0) // Error + { + ni_log(NI_LOG_ERROR,"Error: %s break in encode mode\n",__func__); + LRETURN; + } + } + + // All frames has been sent successfully. Just check the one of the + // statuses. + if (ret == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change) { input_index++; - lseek(p_enc_send_param->input_arg_pfs[input_index], 0, SEEK_END); - total_file_size = lseek(p_enc_send_param->input_arg_pfs[input_index], 0, SEEK_CUR); - lseek(p_enc_send_param->input_arg_pfs[input_index], 0, SEEK_SET); - data_left_size = total_file_size; - } else if (p_enc_send_param->p_xcodeState->enc_seq_change) // sequene change + get_total_file_size(p_enc_send_param->input_arg_pfs[input_index]); + } else if (p_enc_ctx_list[0].session_run_state == + SESSION_RUN_STATE_SEQ_CHANGE_DRAINING) // sequene change { ni_usleep(100); - } else if (p_enc_send_param->p_xcodeState->enc_eos_sent) //eos + } else if (p_enc_send_param->p_xcoder_state[0].enc_eos_sent) //eos { - ni_log(NI_LOG_DEBUG, - "encoder_send_thread reach eos in encode mode!\n"); + ni_log(NI_LOG_DEBUG, "%s reach eos in encode mode\n", __func__); break; } } else if (p_enc_send_param->mode == XCODER_APP_TRANSCODE) { - while (test_frames_isempty(frame_list)) + while (frame_list_is_empty(frame_list) && !g_end_of_all_threads) { ni_usleep(100); } - p_dec_frame = &frame_list->ni_test_frame[frame_list->head]; + + if (g_end_of_all_threads) + { + LRETURN; + } + + p_dec_frame = &frame_list->frames[frame_list->head]; p_ni_frame = &p_dec_frame->data.frame; - retval = encoder_send_data2( - p_enc_ctx, p_enc_send_param->dec_codec_format, p_dec_frame, - p_enc_send_param->p_in_frame, sos_flag, - p_enc_send_param->input_video_width, - p_enc_send_param->input_video_height, p_enc_send_param->pfs, - total_file_size, p_enc_send_param->p_total_bytes_sent, - p_enc_send_param->p_xcodeState); - sos_flag = 0; - if (retval == 0) - { - if (p_enc_send_param->p_enc_ctx->hw_action) + + for (i = 0; i < p_enc_send_param->output_total; i++) + { + ret = encoder_send_data2(&p_enc_ctx_list[i], p_dec_frame, + p_enc_send_param->p_in_frame, + p_enc_send_param->input_video_width, + p_enc_send_param->input_video_height, + p_enc_send_param->p_total_bytes_sent, + p_enc_send_param->p_xcoder_state); + if (ret < 0) //Error { - // skip copy the frame when eos received. - if (!p_enc_send_param->p_xcodeState->enc_eos_sent) + if (p_enc_ctx_list[i].hw_action) { - //track in array with unique index, free when enc read finds - //this must be implemented in application space for complete - //tracking of hwframes - //If encoder write had no buffer avail space the next time we - //update the tracker will be redundant - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *) - p_ni_frame->p_data[3])) - ->ui16FrameIdx; - ni_log(NI_LOG_DEBUG, - "send frame index:%d, head:%d, eos:%d\n", - current_hwframe_index, frame_list->head, - p_enc_send_param->p_xcodeState->enc_eos_sent); - memcpy(p_enc_send_param->p_hwframe_pool_tracker + - current_hwframe_index, - (uint8_t *)p_ni_frame->p_data[3], - sizeof(niFrameSurface1_t)); + //pre close cleanup will clear it out + p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3]; + ni_hw_frame_ref(p_surface); + } else + { + ni_decoder_frame_buffer_free(p_ni_frame); } - ni_frame_wipe_aux_data(p_ni_frame); //reusebuff - } else - { - ni_decoder_frame_buffer_free(p_ni_frame); + frame_list_drain(frame_list); + ni_log(NI_LOG_ERROR, "Error: %s break in transcode mode!\n", + __func__); + LRETURN; } - deq_test_frames(frame_list); - } else if (retval < 0) //Error + } + + // All frames has been sent successfully. Just check the one of the + // statuses. + if (p_enc_ctx_list[0].hw_action) { - if (p_enc_send_param->p_enc_ctx->hw_action) - { - //pre close cleanup will clear it out - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *) - p_ni_frame->p_data[3])) - ->ui16FrameIdx; - memcpy(p_enc_send_param->p_hwframe_pool_tracker + - current_hwframe_index, - (uint8_t *)p_ni_frame->p_data[3], - sizeof(niFrameSurface1_t)); - } else + // skip copy the frame when eos received. + if (!p_enc_send_param->p_xcoder_state[0].enc_eos_sent) { - ni_decoder_frame_buffer_free(p_ni_frame); + //track in array with unique index, free when enc read + //finds this must be implemented in application space + //for complete tracking of hwframes. If encoder write + //had no buffer avail space the next time we update the + //tracker will be redundant. + p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3]; + ni_hw_frame_ref(p_surface); } - fprintf( - stderr, - "Error: encoder_send_thread break in transcode mode!\n"); - break; + ni_frame_wipe_aux_data(p_ni_frame); //reusebuff + } else + { + ni_decoder_frame_buffer_free(p_ni_frame); } - if (p_enc_send_param->p_xcodeState->enc_eos_sent) // eos + frame_list_drain(frame_list); + + if (p_enc_send_param->p_xcoder_state[0].enc_eos_sent) // eos { - printf("encoder_send_thread reach eos in transcode mode!\n"); + ni_log(NI_LOG_INFO, "%s reach eos in transcode mode\n", __func__); break; } } else { - while (test_frames_isempty(frame_list)) + while (frame_list_is_empty(frame_list) && !g_end_of_all_threads) { ni_usleep(100); } - p_upl_frame = &frame_list->ni_test_frame[frame_list->head]; - if (*p_enc_send_param->p_input_exhausted && - p_upl_frame->data.frame.end_of_stream) + + if (g_end_of_all_threads) { - input_exhausted = 1; + LRETURN; } - retval = encoder_send_data3(p_enc_send_param->p_enc_ctx, - p_upl_frame, sos_flag, - p_enc_send_param->input_video_width, - p_enc_send_param->input_video_height, - p_enc_send_param->p_xcodeState, - input_exhausted, &need_to_resend); - sos_flag = 0; - if (retval == 2) //Error + p_upl_frame = &frame_list->frames[frame_list->head]; + eos = p_upl_frame->data.frame.end_of_stream; + + for (i = 0; i < p_enc_send_param->output_total; i++) { - fprintf( - stderr, - "Error: encoder_send_thread break in transcode mode!\n"); - break; + ret = encoder_send_data3(&p_enc_ctx_list[i], p_upl_frame, + p_enc_send_param->input_video_width, + p_enc_send_param->input_video_height, + &p_enc_send_param->p_xcoder_state[i], + eos); + if (ret < 0) //Error + { + ni_log(NI_LOG_ERROR, "Error: %s break in upload mode\n", + __func__); + LRETURN; + } } - if (need_to_resend == 0) + // All frames has been sent successfully. Just check the one of the + // statuses. + if (!p_enc_send_param->p_xcoder_state[0].enc_resend) { - //successful read means there is recycle to check - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *)p_upl_frame->data.frame - .p_data[3])) - ->ui16FrameIdx; + p_ni_frame = &p_upl_frame->data.frame; + p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3]; + ni_hw_frame_ref(p_surface); ni_log(NI_LOG_DEBUG, "send frame index:%d, head:%d\n", - current_hwframe_index, frame_list->head); - memcpy((p_enc_send_param->p_hwframe_pool_tracker + - current_hwframe_index), - (uint8_t *)p_upl_frame->data.frame.p_data[3], - sizeof(niFrameSurface1_t)); - deq_test_frames(frame_list); + p_surface->ui16FrameIdx, frame_list->head); + frame_list_drain(frame_list); } - if (p_enc_send_param->p_xcodeState->enc_eos_sent) // eos + if (p_enc_send_param->p_xcoder_state[0].enc_eos_sent) { - printf("encoder_send_thread reach eos in upload mode!\n"); + ni_log(NI_LOG_INFO, "%s reach eos in upload mode\n", __func__); break; } } } - ni_log(NI_LOG_TRACE, "encoder_send_thread exit\n"); - return NULL; +END: + // Broadcast all codec threads to quit on exception such as NVMe IO. + if (ret < 0) + { + g_end_of_all_threads = 1; + } + + ni_log(NI_LOG_TRACE, "%s exit\n", __func__); + return (void *)(long)ret; } void *encoder_receive_thread(void *args) { enc_recv_param_t *p_enc_recv_param = args; - ni_packet_t *p_ni_packet = &p_enc_recv_param->p_out_packet->data.packet; - niFrameSurface1_t *p_hwframe = NULL; - int retval; + int i, ret = 0; int print_time; + int end_of_all_streams = 0; - printf("encoder_receive_thread start\n"); - for (;;) + ni_log(NI_LOG_INFO, "encoder_receive_thread start\n"); + + while (!end_of_all_streams && ret >= 0 && !g_end_of_all_threads) { (void)ni_gettimeofday(¤t_time, NULL); - print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1); - retval = encoder_receive_data( - p_enc_recv_param->p_enc_ctx, p_enc_recv_param->p_out_packet, - p_enc_recv_param->output_video_width, - p_enc_recv_param->output_video_height, p_enc_recv_param->p_file, - p_enc_recv_param->p_total_bytes_received, print_time, - p_enc_recv_param->p_buffered_frame); - if (retval < 0) // Error - { - fprintf(stderr, "Error: encoder_receive_thread break!\n"); - break; - } else if (p_ni_packet->end_of_stream) // eos - { - printf("encoder_receive_thread reach eos\n"); - break; - } else if (retval == NI_TEST_RETCODE_EAGAIN) - { - ni_usleep(100); - } else if (retval == NI_TEST_RETCODE_SEQ_CHANGE_DONE) - { - p_enc_recv_param->p_xcodeState->enc_seq_change = 0; - } else if (p_enc_recv_param->p_enc_ctx->hw_action) - { - //encoder only returns valid recycle index - //when there's something to recycle. - //This range is suitable for all memory bins - if (p_ni_packet->recycle_index > 0 && - p_ni_packet->recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX( - p_enc_recv_param->p_enc_ctx->ddr_config)) + print_time = need_time_print(¤t_time, &previous_time); + + ret = encoder_receive(p_enc_recv_param->p_enc_ctx, + p_enc_recv_param->p_buffered_frame, + p_enc_recv_param->p_out_packet, + p_enc_recv_param->output_video_width, + p_enc_recv_param->output_video_height, + p_enc_recv_param->p_number_of_packets, + p_enc_recv_param->output_total, + p_enc_recv_param->p_file, + p_enc_recv_param->p_total_bytes_received, + print_time, p_enc_recv_param->p_xcoder_state); + for (i = 0; ret >= 0 && i < p_enc_recv_param->output_total; i++) + { + if (!p_enc_recv_param->p_xcoder_state[i].enc_eos_received) + { + ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i); + end_of_all_streams = 0; + break; + } else { - p_hwframe = p_enc_recv_param->p_hwframe_pool_tracker + - p_ni_packet->recycle_index; - - ni_log(NI_LOG_DEBUG, "recycle index:%d, %d\n", - p_hwframe->ui16FrameIdx, - p_hwframe->device_handle); - if (p_hwframe->ui16FrameIdx) - { - ni_hwframe_buffer_recycle(p_hwframe, - p_hwframe->device_handle); - p_hwframe->ui16FrameIdx = 0; - } + ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i); + end_of_all_streams = 1; } } + if (print_time) { previous_time = current_time; } } + // Broadcast all codec threads to quit on exception such as NVMe IO. + if (ret < 0) + { + g_end_of_all_threads = 1; + } + ni_log(NI_LOG_TRACE, "encoder_receive_thread exit\n"); - return NULL; + return (void *)(long)ret; } void *uploader_thread(void *args) { uploader_param_t *p_upl_param = args; - ni_test_frame_list_t *frame_list = p_upl_param->test_frame_list; - ni_session_data_io_t *p_out_frame = NULL; - int retval; + ni_session_context_t *p_upl_ctx = p_upl_param->p_upl_ctx; + ni_test_frame_list_t *frame_list = p_upl_param->frame_list; + ni_session_data_io_t *p_out_frame; + niFrameSurface1_t *p_hwframe = NULL; + int eos = 0; + p_upl_ctx->async_mode = 1; // async mode (multi-threaded mode) - printf("uploader_thread start\n"); + ni_log(NI_LOG_INFO, "uploader_thread start\n"); for (;;) { - while (test_frames_isfull(frame_list)) + while (uploader_frame_list_full(frame_list, p_upl_ctx->pixel_format) && + !g_end_of_all_threads) { ni_usleep(100); } - p_out_frame = &frame_list->ni_test_frame[frame_list->tail]; - retval = upload_send_data_get_desc( - p_upl_param->p_upl_ctx, p_upl_param->p_swin_frame, p_out_frame, - p_upl_param->input_video_width, p_upl_param->input_video_height, - p_upl_param->pfs, total_file_size, p_upl_param->p_total_bytes_sent, - p_upl_param->p_input_exhausted); - if (retval < 0) + if (g_end_of_all_threads) + { + break; + } + + int tail = frame_list->tail; + p_out_frame = &frame_list->frames[tail]; + p_hwframe = hwupload_frame(p_upl_ctx, p_upl_param->p_sca_ctx, + p_upl_param->p_swin_frame, p_out_frame, + p_upl_param->p_scale_frame, + p_upl_ctx->pixel_format, + p_upl_param->input_video_width, + p_upl_param->input_video_height, + p_upl_param->pfs, p_upl_param->yuv_buf, + p_upl_param->p_total_bytes_sent, &eos); + if (!p_hwframe) { - if (p_upl_param->p_upl_ctx->status == - NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL) - { //No space to write to, wait for downstream to free some + if (p_upl_ctx->status == NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL) + { ni_usleep(100); continue; + } else + { + ni_log(NI_LOG_ERROR, "Error: uploader_thread break!\n"); + // Broadcast all codec threads to quit on exception such as + // NVMe IO. + g_end_of_all_threads = 1; + break; } - fprintf(stderr, "Error: uploader_thread break!\n"); - break; - } else if (*p_upl_param->p_input_exhausted) // eos + } else if (p_out_frame->data.frame.end_of_stream) // eos { - enq_test_frames(frame_list); - printf("uploader_thread reach eos\n"); + frame_list_enqueue(frame_list); + ni_log(NI_LOG_INFO, "uploader_thread reach eos\n"); break; } - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *) - p_out_frame->data.frame.p_data[3])) - ->ui16FrameIdx; - ni_log(NI_LOG_DEBUG, "uploader:%d, tail:%d\n", current_hwframe_index, - frame_list->tail); - enq_test_frames(frame_list); + + ni_log(NI_LOG_DEBUG, "uploader:%d, tail:%d\n", p_hwframe->ui16FrameIdx, + tail); + + if (!is_ni_enc_pix_fmt(p_upl_ctx->pixel_format)) + { + ni_frame_buffer_free(&frame_list->frames[tail].data.frame); + memcpy(&frame_list->frames[tail], + p_upl_param->p_scale_frame, sizeof(ni_session_data_io_t)); + } + frame_list_enqueue(frame_list); } ni_log(NI_LOG_TRACE, "uploader_thread exit\n"); @@ -6224,13 +6943,13 @@ static int ni_scaler_params_set_value(ni_filter_params_t *params, { if (!params) { - printf("Error: Null pointer parameters passed\n"); + ni_log(NI_LOG_ERROR, "Error: Null pointer parameters passed\n"); return -1; } if (!name) { - printf("Error: Null name pointer parameters passed\n"); + ni_log(NI_LOG_ERROR, "Error: Null name pointer parameters passed\n"); return -1; } @@ -6258,14 +6977,15 @@ static int ni_scaler_params_set_value(ni_filter_params_t *params, params->format = GC620_RGB888_PLANAR; } else { - printf("Error: invallid scaler parameters\n"); + ni_log(NI_LOG_ERROR, "Error: invallid scaler parameters\n"); return -1; } } else { - printf("Error: invallid scaler parameters\n"); + ni_log(NI_LOG_ERROR, "Error: invallid scaler parameters\n"); return -1; } + return 0; } @@ -6286,9 +7006,9 @@ static int retrieve_filter_params(char xcoderParams[], } if (strlen(curr) > sizeof(key) + sizeof(value) - 1 || - get_key_value(curr, key, value)) + ni_param_get_key_value(curr, key, value)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: scaler-params key/value not " "retrieved: %s\n", curr); @@ -6298,7 +7018,7 @@ static int retrieve_filter_params(char xcoderParams[], ret = ni_scaler_params_set_value(params, key, value); if (ret != 0) { - printf("Error: failed to parse the input scaler parameters\n"); + ni_log(NI_LOG_ERROR, "Error: failed to parse the input scaler parameters\n"); ret = -1; break; } @@ -6406,8 +7126,8 @@ void init_scaler_params(ni_scaler_input_params_t *p_scaler_params, * * \return 0 if successful, < 0 otherwise ******************************************************************************/ -int scaler_session_open(ni_session_context_t *p_scaler_ctx, int iXcoderGUID, - ni_scaler_opcode_t op) +static int scaler_session_open(ni_session_context_t *p_scaler_ctx, + int iXcoderGUID, ni_scaler_opcode_t op) { int ret = 0; @@ -6422,17 +7142,17 @@ int scaler_session_open(ni_session_context_t *p_scaler_ctx, int iXcoderGUID, ret = ni_device_session_open(p_scaler_ctx, NI_DEVICE_TYPE_SCALER); - if (ret < 0) + if (ret != NI_RETCODE_SUCCESS) { - fprintf(stderr, "Error: ni_scaler_session_open() failure!\n"); + ni_log(NI_LOG_ERROR, "Error: ni_scaler_session_open() failure!\n"); return -1; } else { #ifdef _WIN32 - printf("Scaler session open: device_handle %p, session_id %u.\n", + ni_log(NI_LOG_INFO, "Scaler session open: device_handle %p, session_id %u.\n", p_scaler_ctx->device_handle, p_scaler_ctx->session_id); #else - printf("Scaler session open: device_handle %d, session_id %u.\n", + ni_log(NI_LOG_INFO, "Scaler session open: device_handle %d, session_id %u.\n", p_scaler_ctx->device_handle, p_scaler_ctx->session_id); #endif return 0; @@ -6446,66 +7166,73 @@ int scaler_session_open(ni_session_context_t *p_scaler_ctx, int iXcoderGUID, * * \return 0 if successful, < 0 otherwise ******************************************************************************/ -int launch_scaler_operation(ni_session_context_t *p_ctx, - ni_frame_t *p_frame_in_up, - ni_frame_t *p_frame_in_bg, - ni_session_data_io_t *p_data_out, - ni_scaler_input_params_t scaler_params) +static int launch_scaler_operation(ni_session_context_t *p_ctx, int iXcoderGUID, + ni_frame_t *p_frame_in_up, + ni_frame_t *p_frame_in_bg, + ni_session_data_io_t *p_data_out, + ni_scaler_input_params_t scaler_params) { int ret = 0; + niFrameSurface1_t *frame_surface_up; + niFrameSurface1_t *frame_surface_bg; + niFrameSurface1_t *frame_surface_output; + if (p_ctx->session_id == NI_INVALID_SESSION_ID) { // Open scaler session - if (0 != scaler_session_open(p_ctx, 0, scaler_params.op)) + if (0 != scaler_session_open(p_ctx, iXcoderGUID, scaler_params.op)) { - fprintf(stderr, "Error: scaler open session error\n"); + ni_log(NI_LOG_ERROR, "Error: scaler open session error\n"); return -1; } // init scaler hwframe pool if (0 != ni_scaler_frame_pool_alloc(p_ctx, scaler_params)) { - fprintf(stderr, "Error: init filter hwframe pool\n"); + ni_log(NI_LOG_ERROR, "Error: init filter hwframe pool\n"); return -1; } } // allocate a ni_frame_t structure on the host PC - if (0 != - ni_frame_buffer_alloc_hwenc(&(p_data_out->data.frame), - scaler_params.output_width, - scaler_params.output_height, 0)) + ret = ni_frame_buffer_alloc_hwenc(&p_data_out->data.frame, + scaler_params.output_width, + scaler_params.output_height, 0); + if (ret != 0) { return -1; } - niFrameSurface1_t *frame_surface_up; - frame_surface_up = (niFrameSurface1_t *)(( - p_frame_in_up->p_data[3])); // out_frame retrieved from decoder - // allocate scaler input frame - if (0 != - ni_scaler_input_frame_alloc(p_ctx, scaler_params, frame_surface_up)) + // out_frame retrieved from decoder + frame_surface_up = (niFrameSurface1_t *)(p_frame_in_up->p_data[3]); + frame_surface_bg = (niFrameSurface1_t *)(p_frame_in_bg->p_data[3]); + + // Allocate scaler input frame + ret = ni_scaler_input_frame_alloc(p_ctx, scaler_params, frame_surface_up); + if (ret != 0) { return -1; } - niFrameSurface1_t *frame_surface_bg; - frame_surface_bg = (niFrameSurface1_t *)((p_frame_in_bg->p_data[3])); // Allocate scaler destination frame. - if (0 != ni_scaler_dest_frame_alloc(p_ctx, scaler_params, frame_surface_bg)) + ret = ni_scaler_dest_frame_alloc(p_ctx, scaler_params, frame_surface_bg); + if (ret != 0) { return -1; } // Retrieve hardware frame info from 2D engine and put it in the ni_frame_t structure. - ret = - ni_device_session_read_hwdesc(p_ctx, p_data_out, NI_DEVICE_TYPE_SCALER); + ret = ni_device_session_read_hwdesc(p_ctx, p_data_out, NI_DEVICE_TYPE_SCALER); + frame_surface_output = (niFrameSurface1_t *)(p_data_out->data.frame.p_data[3]); + ni_log(NI_LOG_DEBUG, "%s: output FID %u \n", __func__, + frame_surface_output->ui16FrameIdx); if (ret < 0) { ni_frame_buffer_free(p_frame_in_up); ni_frame_buffer_free(p_frame_in_bg); - ni_frame_buffer_free(&(p_data_out->data.frame)); + ni_frame_buffer_free(&p_data_out->data.frame); } + return ret; } @@ -6519,9 +7246,10 @@ int launch_scaler_operation(ni_session_context_t *p_ctx, int drawbox_filter(ni_session_context_t *p_crop_ctx, ni_session_context_t *p_pad_ctx, ni_session_context_t *p_overlay_ctx, - ni_session_context_t *p_fmt_ctx, ni_frame_t *p_frame_in, - ni_session_data_io_t *p_data_out, box_params_t *p_box_params, - int output_format) + ni_session_context_t *p_fmt_ctx, + ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, + box_params_t *p_box_params, + int iXcoderGUID, int input_format, int output_format) { // assume drawing box at the same position (can be set by box_params) // set default box params @@ -6554,7 +7282,7 @@ int drawbox_filter(ni_session_context_t *p_crop_ctx, p_surface_in = (niFrameSurface1_t *)(p_frame_in->p_data[3]); ni_scaler_input_params_t crop_params = {0}; - crop_params.input_format = GC620_I420; + crop_params.input_format = input_format; crop_params.input_width = p_surface_in->ui16width; crop_params.input_height = p_surface_in->ui16height; crop_params.output_format = GC620_I420; @@ -6563,18 +7291,19 @@ int drawbox_filter(ni_session_context_t *p_crop_ctx, init_scaler_params(&crop_params, NI_SCALER_OPCODE_CROP, box_width, box_height, box_x, box_y, 0, 0); ni_session_data_io_t crop_data = {0}; - ret = launch_scaler_operation(p_crop_ctx, p_frame_in, p_frame_in, - &crop_data, crop_params); + ret = launch_scaler_operation(p_crop_ctx, iXcoderGUID, p_frame_in, + p_frame_in, &crop_data, crop_params); if (ret != 0) { - printf("Failed to lauch scaler operation %d\n", crop_params.op); + ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", crop_params.op); return -1; } niFrameSurface1_t *crop_frame_surface = (niFrameSurface1_t *)(crop_data.data.frame.p_data[3]); + ni_hw_frame_ref(crop_frame_surface); ni_scaler_input_params_t pad_params = {0}; - pad_params.input_format = GC620_I420; + pad_params.input_format = input_format; pad_params.input_width = crop_params.output_width; pad_params.input_height = crop_params.output_height; pad_params.output_format = GC620_I420; @@ -6583,23 +7312,22 @@ int drawbox_filter(ni_session_context_t *p_crop_ctx, init_scaler_params(&pad_params, NI_SCALER_OPCODE_PAD, 0, 0, 0, 0, line_width, line_width); ni_session_data_io_t pad_data = {0}; - ret = - launch_scaler_operation(p_pad_ctx, &(crop_data.data.frame), - &(crop_data.data.frame), &pad_data, pad_params); + ret = launch_scaler_operation(p_pad_ctx, iXcoderGUID, &crop_data.data.frame, + &crop_data.data.frame, &pad_data, pad_params); // recycle HwFrameIdx first, then free the frame - ni_hwframe_buffer_recycle(crop_frame_surface, - crop_frame_surface->device_handle); + ni_hw_frame_unref(crop_frame_surface->ui16FrameIdx); ni_frame_buffer_free(&(crop_data.data.frame)); if (ret != 0) { - printf("Failed to lauch scaler operation %d\n", pad_params.op); + ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", pad_params.op); return -1; } niFrameSurface1_t *pad_frame_surface = (niFrameSurface1_t *)(pad_data.data.frame.p_data[3]); + ni_hw_frame_ref(pad_frame_surface); ni_scaler_input_params_t overlay_params = {0}; - overlay_params.input_format = GC620_I420; + overlay_params.input_format = input_format; overlay_params.input_width = pad_params.output_width; overlay_params.input_height = pad_params.output_height; overlay_params.output_format = GC620_I420; @@ -6611,18 +7339,19 @@ int drawbox_filter(ni_session_context_t *p_crop_ctx, overlay_x, overlay_y, 0, 0); ni_session_data_io_t ovly_data = {0}; if (output_format == GC620_I420) - ret = launch_scaler_operation(p_overlay_ctx, &(pad_data.data.frame), - p_frame_in, p_data_out, overlay_params); + ret = launch_scaler_operation(p_overlay_ctx, iXcoderGUID, + &pad_data.data.frame, p_frame_in, + p_data_out, overlay_params); else - ret = launch_scaler_operation(p_overlay_ctx, &(pad_data.data.frame), - p_frame_in, &ovly_data, overlay_params); + ret = launch_scaler_operation(p_overlay_ctx, iXcoderGUID, + &pad_data.data.frame, p_frame_in, + &ovly_data, overlay_params); // recycle HwFrameIdx first, then free the frame - ni_hwframe_buffer_recycle(pad_frame_surface, - pad_frame_surface->device_handle); + ni_hw_frame_unref(pad_frame_surface->ui16FrameIdx); ni_frame_buffer_free(&(pad_data.data.frame)); if (ret != 0) { - printf("Failed to lauch scaler operation %d\n", overlay_params.op); + ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", overlay_params.op); return -1; } @@ -6630,17 +7359,18 @@ int drawbox_filter(ni_session_context_t *p_crop_ctx, { niFrameSurface1_t *ovly_frame_surface = (niFrameSurface1_t *)(ovly_data.data.frame.p_data[3]); + ni_hw_frame_ref(ovly_frame_surface); ovly_frame_surface->ui16width = overlay_params.output_width; ovly_frame_surface->ui16height = overlay_params.output_height; ret = scale_filter(p_fmt_ctx, &(ovly_data.data.frame), p_data_out, - overlay_params.output_width, - overlay_params.output_height, output_format); - ni_hwframe_buffer_recycle(ovly_frame_surface, - ovly_frame_surface->device_handle); - ni_frame_buffer_free(&(ovly_data.data.frame)); + iXcoderGUID, overlay_params.output_width, + overlay_params.output_height, GC620_I420, + output_format); + ni_hw_frame_unref(ovly_frame_surface->ui16FrameIdx); + ni_frame_buffer_free(&ovly_data.data.frame); if (ret != 0) { - printf("Failed to lauch scaler operation 0\n"); + ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation 0\n"); return -1; } } @@ -6656,29 +7386,31 @@ int drawbox_filter(ni_session_context_t *p_crop_ctx, * \return 0 if successful, < 0 otherwise ******************************************************************************/ int scale_filter(ni_session_context_t *p_ctx, ni_frame_t *p_frame_in, - ni_session_data_io_t *p_data_out, int scale_width, - int scale_height, int out_format) + ni_session_data_io_t *p_data_out, int iXcoderGUID, + int scale_width, int scale_height, int in_format, int out_format) { + int ret; niFrameSurface1_t *p_surface_in; - p_surface_in = (niFrameSurface1_t *)(p_frame_in->p_data[3]); - ni_scaler_input_params_t scale_params; + + p_surface_in = (niFrameSurface1_t *)p_frame_in->p_data[3]; scale_params.output_format = out_format; // rgba or bgrp or yuv420p; scale_params.output_width = scale_width; scale_params.output_height = scale_height; - scale_params.input_format = - GC620_I420; // now assume the decoded frame format is GC620_I420; - scale_params.input_width = p_surface_in->ui16width; - scale_params.input_height = p_surface_in->ui16height; + scale_params.input_format = in_format; + scale_params.input_width = p_surface_in ? p_surface_in->ui16width : 0; + scale_params.input_height = p_surface_in ? p_surface_in->ui16height : 0; init_scaler_params(&scale_params, NI_SCALER_OPCODE_SCALE, 0, 0, 0, 0, 0, 0); - int ret = launch_scaler_operation(p_ctx, p_frame_in, p_frame_in, p_data_out, - scale_params); + + ret = launch_scaler_operation(p_ctx, iXcoderGUID, p_frame_in, p_frame_in, + p_data_out, scale_params); if (ret != 0) { - printf("Failed to lauch scaler operation %d\n", scale_params.op); + ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", scale_params.op); return -1; } - return 0; + + return ret; } /*!***************************************************************************** @@ -6693,22 +7425,25 @@ int scaler_output_write(ni_session_context_t *p_ctx, int out_height, int out_format, FILE *fp, disp_buffer_t *disp) { + int ret; + niFrameSurface1_t *p_surface; + if (!fp) return 0; - niFrameSurface1_t *p_frame_surface = - (niFrameSurface1_t *)(p_data_out->data.frame.p_data[3]); - p_frame_surface->ui16width = out_width; - p_frame_surface->ui16height = out_height; - p_frame_surface->bit_depth = 1; - p_frame_surface->encoding_type = NI_PIXEL_PLANAR_FORMAT_PLANAR; - int ret; + + p_surface = (niFrameSurface1_t *)p_data_out->data.frame.p_data[3]; + p_surface->ui16width = out_width; + p_surface->ui16height = out_height; + p_surface->bit_depth = 1; + p_surface->encoding_type = NI_PIXEL_PLANAR_FORMAT_PLANAR; if (p_ctx->isP2P) { #ifndef _WIN32 - ret = read_from_dmabuf(p_ctx, p_frame_surface, disp, out_format, fp); + ret = read_from_dmabuf(p_ctx, p_surface, disp, out_format, fp); if (ret != 0) { + ni_hw_frame_unref(p_surface->ui16FrameIdx); ni_frame_buffer_free(&(p_data_out->data.frame)); return -1; } @@ -6717,90 +7452,525 @@ int scaler_output_write(ni_session_context_t *p_ctx, { // use hwdownload to download hw frame, recycle hwframe buffer ni_session_data_io_t hwdl_session_data = {0}; - ret = hwdl_frame(p_ctx, &hwdl_session_data, &(p_data_out->data.frame), + ret = hwdl_frame(p_ctx, &hwdl_session_data, &p_data_out->data.frame, out_format); if (ret <= 0) { + ni_hw_frame_unref(p_surface->ui16FrameIdx); ni_frame_buffer_free(&(p_data_out->data.frame)); return -1; } // write hwdl frame to output_file write_rawvideo_data(fp, out_width, out_height, out_format, - &(hwdl_session_data.data.frame)); - ni_frame_buffer_free(&(hwdl_session_data.data.frame)); + &hwdl_session_data.data.frame); + ni_frame_buffer_free(&hwdl_session_data.data.frame); } + + ni_hw_frame_unref(p_surface->ui16FrameIdx); + return 0; } -/*!***************************************************************************** - * \brief main - * - * \param - * - * \return - ******************************************************************************/ +// final scan clean up of ref counted HW frame pool, return number of recycled +// HW frames. +static int scan_and_clean_hwdescriptors(void) +{ + int i; + int recycled = 0; + + for (i = 0; i < NI_MAX_DR_HWDESC_FRAME_INDEX; i++) + { + if (g_hwframe_pool[i].ref_cnt && + g_hwframe_pool[i].surface.ui16FrameIdx) + { + ni_log(NI_LOG_DEBUG, "clean/recycle frame idx %u ref_cnt %d\n,", + g_hwframe_pool[i].surface.ui16FrameIdx, + g_hwframe_pool[i].ref_cnt); + ni_hwframe_buffer_recycle2(&g_hwframe_pool[i].surface); + g_hwframe_pool[i].ref_cnt = 0; + recycled++; + } + } + + return recycled; +} + +// reference HW frame +static void ni_hw_frame_ref(const niFrameSurface1_t *p_surface) +{ + uint16_t hwframe_index; + + if (!p_surface) + { + return; + } + + hwframe_index = p_surface->ui16FrameIdx; + g_hwframe_pool[hwframe_index].ref_cnt++; + if (1 == g_hwframe_pool[hwframe_index].ref_cnt) + { + memcpy(&g_hwframe_pool[hwframe_index].surface, p_surface, + sizeof(niFrameSurface1_t)); + } + ni_log(NI_LOG_TRACE, "%s frame idx %u ref_cnt %d ..\n", __func__, + hwframe_index, g_hwframe_pool[hwframe_index].ref_cnt); +} + +// unref HW frame +static void ni_hw_frame_unref(uint16_t hwframe_index) +{ + if (g_hwframe_pool[hwframe_index].ref_cnt > 0) + { + g_hwframe_pool[hwframe_index].ref_cnt--; + if (0 == g_hwframe_pool[hwframe_index].ref_cnt && + g_hwframe_pool[hwframe_index].surface.ui16FrameIdx) + { + ni_log(NI_LOG_TRACE, "%s frame idx recycing frame idx %u\n", __func__, + g_hwframe_pool[hwframe_index].surface.ui16FrameIdx); + + ni_hwframe_buffer_recycle2(&g_hwframe_pool[hwframe_index].surface); + } + ni_log(NI_LOG_TRACE, "%s frame idx %u ref_cnt now: %d\n", __func__, + hwframe_index, g_hwframe_pool[hwframe_index].ref_cnt); + } else + { + ni_log(NI_LOG_ERROR, "%s error frame idx %u ref_cnt %d <= 0\n", + __func__, hwframe_index, + g_hwframe_pool[hwframe_index].ref_cnt); + } +} + +static niFrameSurface1_t *hwupload_frame(ni_session_context_t *p_upl_ctx, + ni_session_context_t *p_sca_ctx, + ni_session_data_io_t *p_sw_data, + ni_session_data_io_t *p_hw_data, + ni_session_data_io_t *p_scale_data, + ni_pix_fmt_t pix_fmt, int width, + int height, int pfs, void *yuv_buf, + unsigned long *bytes_sent, int *eos) +{ + int ret, chunk_size; + uint64_t offset; + niFrameSurface1_t *p_hwframe = NULL; + + chunk_size = read_yuv_from_file(pfs, yuv_buf, width, height, pix_fmt, + NI_SW_PIX_FMT_NONE, eos, + p_upl_ctx->session_run_state); + if (chunk_size < 0) + { + ni_log(NI_LOG_ERROR, "Error: read yuv file error\n"); + return NULL; + } + + // need to have the hwframe before open encoder + ret = upload_send_data_get_desc(p_upl_ctx, p_sw_data, p_hw_data, width, + height, *eos ? NULL : yuv_buf, bytes_sent); + if (p_upl_ctx->status == NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL) + { + ni_log(NI_LOG_DEBUG, "No space to write to, try to read a packet\n"); + //file was read so reset read pointer and try again + data_left_size += chunk_size; + if (number_of_frames_in_file && + (number_of_frames > number_of_frames_in_file)) + { + offset = chunk_size * (number_of_frames % number_of_frames_in_file); + } else + { + offset = chunk_size * number_of_frames; + } + lseek(pfs, offset, SEEK_SET); + return NULL; + } else if (ret) + { + ni_log(NI_LOG_ERROR, "Error: upload frame error\n"); + return NULL; + } + + //to determine if from same device and buffer dimensions in memory + //needs to be done where input frame is available to check + p_hwframe = (niFrameSurface1_t *)p_hw_data->data.frame.p_data[3]; + if (p_hw_data->data.frame.end_of_stream) + { + // reach eos + return p_hwframe; + } + + // need to convert into pixel format for NI encoding + if (!is_ni_enc_pix_fmt(pix_fmt)) + { + ni_hw_frame_ref(p_hwframe); + ret = scale_filter(p_sca_ctx, &p_hw_data->data.frame, p_scale_data, + p_upl_ctx->hw_id, width, height, + ni_to_gc620_pix_fmt(pix_fmt), GC620_I420); + ni_hw_frame_unref(p_hwframe->ui16FrameIdx); + if (ret) + { + ni_log(NI_LOG_ERROR, "Error: upload frame error\n"); + return NULL; + } + p_hwframe = (niFrameSurface1_t *)p_scale_data->data.frame.p_data[3]; + } + + return p_hwframe; +} + +static int encoder_open(ni_session_context_t *enc_ctx_list, + ni_xcoder_params_t *p_api_param_list, + int output_total, char p_enc_conf_params[][2048], + char p_enc_conf_gop[][2048], + ni_frame_t *p_ni_frame, int width, int height, + int fps_num, int fps_den, int bitrate, + int codec_format, ni_pix_fmt_t pix_fmt, + int aspect_ratio_idc, int xcoder_guid, + niFrameSurface1_t *p_surface, int multi_thread, + ni_rate_emu_t *p_enc_rate_emu_list, + bool check_zerocopy) +{ + int i, ret = 0; + int color_prim = NI_COL_PRI_UNSPECIFIED; + int color_trc = NI_COL_TRC_UNSPECIFIED; + int color_space = NI_COL_SPC_UNSPECIFIED; + int sar_num = 0; + int sar_den = 0; + int video_full_range_flag = 0; + + if (p_ni_frame != NULL) + { + // open the encode session when the first frame arrives and the session + // is not opened yet, with the source stream and user-configured encode + // info both considered when constructing VUI in the stream headers + color_prim = p_ni_frame->color_primaries; + color_trc = p_ni_frame->color_trc; + color_space = p_ni_frame->color_space; + sar_num = p_ni_frame->sar_width; + sar_den = p_ni_frame->sar_height; + video_full_range_flag = p_ni_frame->video_full_range_flag; + + // calculate the source fps and set it as the default target fps, based + // on the timing_info passed in from the decoded frame + if (p_ni_frame->vui_num_units_in_tick && p_ni_frame->vui_time_scale) + { + if (NI_CODEC_FORMAT_H264 == p_ni_frame->src_codec) + { + if (0 == p_ni_frame->vui_time_scale % 2) + { + fps_num = (int)(p_ni_frame->vui_time_scale / 2); + fps_den = (int)(p_ni_frame->vui_num_units_in_tick); + } else + { + fps_num = (int)(p_ni_frame->vui_time_scale); + fps_den = (int)(2 * p_ni_frame->vui_num_units_in_tick); + } + } else if (NI_CODEC_FORMAT_H265 == p_ni_frame->src_codec) + { + fps_num = p_ni_frame->vui_time_scale; + fps_den = p_ni_frame->vui_num_units_in_tick; + } + } + } + + for (i = 0; i < output_total; i++) + { + // set up encoder p_config, using some info from source + ret = ni_encoder_init_default_params(&p_api_param_list[i], fps_num, + fps_den, bitrate, width, height, + enc_ctx_list[i].codec_format); + if (ret < 0) + { + ni_log(NI_LOG_ERROR, "Error encoder[%d] init default set up error\n", i); + return -1; + } + + // check and set ni_encoder_params from --xcoder-params + // Note: the parameter setting has to be in this order so that user + // configured values can overwrite the source/default ones if + // desired. + if (ni_retrieve_xcoder_params(p_enc_conf_params[i], + &p_api_param_list[i], &enc_ctx_list[i])) + { + ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config parsing error\n", i); + return -1; + } + + if (ni_retrieve_xcoder_gop(p_enc_conf_gop[i], + &p_api_param_list[i], &enc_ctx_list[i])) + { + ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config_gop parsing error\n", i); + return -1; + } + + // set async mode in enc_ctx if encoding is multi-threaded + if (multi_thread) + { + ni_log(NI_LOG_INFO, "Encoder[%d] is multi-threaded, set async mode " + "in the session context!\n", i); + enc_ctx_list[i].async_mode = 1; + } + + // check color primaries configuration + if (color_prim != p_api_param_list[i].color_primaries && + NI_COL_PRI_UNSPECIFIED != p_api_param_list[i].color_primaries) + { + ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color primaries " + "%d to overwrite source %d\n", + i, p_api_param_list[i].color_primaries, color_prim); + color_prim = p_api_param_list[i].color_primaries; + } + + // check color transfer characteristic configuration + if (color_trc != p_api_param_list[i].color_transfer_characteristic && + NI_COL_TRC_UNSPECIFIED != p_api_param_list[i].color_transfer_characteristic) + { + ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color trc %d to " + "overwrite source %d\n", i, + p_api_param_list[i].color_transfer_characteristic, color_trc); + color_trc = p_api_param_list[i].color_transfer_characteristic; + } + + // check color space configuration + if (color_space != p_api_param_list[i].color_space && + NI_COL_SPC_UNSPECIFIED != p_api_param_list[i].color_space) + { + ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color space %d " + "to overwrite source %d\n", + i, p_api_param_list[i].color_space, color_space); + color_space = p_api_param_list[i].color_space; + } + + // check video full range flag configuration + if (p_api_param_list[i].video_full_range_flag >= 0) + { + ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured video full range " + "flag %d\n", i, p_api_param_list[i].video_full_range_flag); + video_full_range_flag = p_api_param_list[i].video_full_range_flag; + } + + // check aspect ratio indicator configuration + if (aspect_ratio_idc > 0 && aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO) + { + sar_num = ni_h264_pixel_aspect_list[aspect_ratio_idc].num; + sar_den = ni_h264_pixel_aspect_list[aspect_ratio_idc].den; + } else if (p_api_param_list[i].sar_denom) + { + sar_num = p_api_param_list[i].sar_num; + sar_den = p_api_param_list[i].sar_denom; + } + + // check hwframe configuration + if (p_surface != NULL) + { + //Items in this else condition could be improved by being handled in libxcoder + enc_ctx_list[i].hw_action = NI_CODEC_HW_ENABLE; + p_api_param_list[i].hwframes = 1; + enc_ctx_list[i].sender_handle = + (ni_device_handle_t)(int64_t)p_surface->device_handle; + p_api_param_list[i].rootBufId = p_surface->ui16FrameIdx; + } + + ret = encoder_open_session(&enc_ctx_list[i], codec_format, xcoder_guid, + &p_api_param_list[i], width, height, + color_prim, color_trc, color_space, + video_full_range_flag, sar_num, sar_den, + pix_fmt, p_enc_rate_emu_list, + check_zerocopy); + if (ret != 0) + { + ni_log(NI_LOG_ERROR, "Error encoder[%d] open session failed!\n", i); + return -1; + } + } + + return ret; +} + +static int encoder_receive(ni_session_context_t *enc_ctx_list, + ni_session_data_io_t *in_frame, + ni_session_data_io_t *pkt, int width, int height, + uint32_t *number_of_packets_list, + int output_total, FILE **pfs_list, + unsigned long long *total_bytes_received_list, + int print_time, device_state_t *xcoder_state) +{ + int i, recycle_index; + int recv_fin_flag = NI_TEST_RETCODE_SUCCESS; + uint32_t prev_num_pkt[MAX_OUTPUT_FILES] = {0}; + + for (i = 0; i < output_total; i++) + { + pkt->data.packet.end_of_stream = 0; + prev_num_pkt[i] = number_of_packets_list[i]; + + recv_fin_flag = encoder_receive_data(&enc_ctx_list[i], pkt, width, + height, pfs_list[i], + &total_bytes_received_list[i], + print_time, + &number_of_packets_list[i], + in_frame); + + recycle_index = pkt->data.packet.recycle_index; + if (prev_num_pkt[i] < number_of_packets_list[i] && + enc_ctx_list[i].hw_action && recycle_index > 0 && + recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx_list[i].ddr_config)) + { + //encoder only returns valid recycle index + //when there's something to recycle. + //This range is suitable for all memory bins + ni_hw_frame_unref(recycle_index); + } else + { + ni_log(NI_LOG_DEBUG, "enc %d recv, prev_num_pkt %u " + "number_of_packets_list %u recycle_index %u\n", i, + prev_num_pkt[i], number_of_packets_list[i], recycle_index); + } + + if (prev_num_pkt[i] < number_of_packets_list[i] && + enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1) + { + // For low delay mode encoding, only one packet is received for one + // frame sent. For non low delay mode, there will be multiple + // packets received for one frame sent. So we need to read out all + // the packets encoded. + ni_xcoder_params_t *p_api_param = + (ni_xcoder_params_t *)enc_ctx_list[i].p_session_config; + if (!p_api_param->low_delay_mode) + { + (void)ni_gettimeofday(¤t_time, NULL); + print_time = need_time_print(¤t_time, &previous_time); + i--; + continue; + } + } + + xcoder_state[i].enc_eos_received = pkt->data.packet.end_of_stream; + + if (recv_fin_flag < 0) + { + ni_log(NI_LOG_DEBUG, "enc %d error, quit !\n", i); + break; + } else if (recv_fin_flag == NI_TEST_RETCODE_EAGAIN) + { + ni_usleep(100); + } + } + + return recv_fin_flag; +} + +static void decoder_stat_report_and_close(ni_session_context_t *p_dec_ctx, + unsigned long long total_bytes_received) +{ + uint32_t time_diff; + + time_diff = (uint32_t)(current_time.tv_sec - start_time.tv_sec); + if (time_diff == 0) + time_diff = 1; + + ni_log(NI_LOG_ERROR, "[R] Got: Frames= %u fps=%f Total bytes %llu\n", + number_of_frames, (float)number_of_frames / (float)time_diff, + total_bytes_received); + + ni_device_session_close(p_dec_ctx, 1, NI_DEVICE_TYPE_DECODER); +} + +static void encoder_stat_report_and_close(ni_session_context_t *p_enc_ctx_list, + int output_total, + uint32_t *number_of_packets_list, + unsigned long long *total_bytes_received_list) +{ + int i; + int nb_recycled; + uint32_t time_diff; + + time_diff = (uint32_t)(current_time.tv_sec - start_time.tv_sec); + if (time_diff == 0) + time_diff = 1; + + nb_recycled = scan_and_clean_hwdescriptors(); + + for (i = 0; i < output_total; i++) + { + ni_log(NI_LOG_ERROR, "[R] Got: enc %d Packets= %u fps=%f Total bytes %llu\n", + (int)i, number_of_packets_list[i], + (float)p_enc_ctx_list[i].frame_num / (float)time_diff, + total_bytes_received_list[i]); + + ni_device_session_close(&p_enc_ctx_list[i], 1, NI_DEVICE_TYPE_ENCODER); + } + + ni_log(NI_LOG_DEBUG, "Cleanup recycled %d internal buffers\n", + nb_recycled); +} + int main(int argc, char *argv[]) { tx_data_t sdPara = {0}; rx_data_t rcPara = {0}; - device_state_t xcodeState = {0}; - int err = 0, pfs = 0, sos_flag = 0; + device_state_t xcoder_state = {0}; + // those variables with MAX_OUTPUT_FILES entries are for the support of + // HW frame ladder encoding only. + device_state_t xcoder_state_list[MAX_OUTPUT_FILES] = {0}; + int pfs = 0; char xcoderGUID[32]; int iXcoderGUID = 0; - uint32_t result = 0; unsigned long total_bytes_sent; + uint32_t number_of_packets_list[MAX_OUTPUT_FILES] = {0}; unsigned long long total_bytes_received; - unsigned long long xcodeRecvTotal; - FILE *p_file = NULL; + unsigned long long total_bytes_received_list[MAX_OUTPUT_FILES]; + FILE *p_file_list[MAX_OUTPUT_FILES]; + char outFileNameList[MAX_OUTPUT_FILES * FILE_NAME_LEN]; char *n; // used for parsing width and height from --size char mode_description[128]; + int end_of_all_streams = 0; int input_video_width; int input_video_height; int arg_width; int arg_height; + int fps_num = 30; + int fps_den = 1; + int bitrate = 200000; int mode = -1; int multi_thread = 0; size_t i; int pkt_size; - int input_exhausted = 0; - int num_post_recycled = 0; - ni_xcoder_params_t api_param; - ni_xcoder_params_t dec_api_param; - niFrameSurface1_t *p_hwframe; - char encConfXcoderParams[2048] = {0}; + ni_xcoder_params_t *p_dec_api_param; + ni_xcoder_params_t *p_enc_api_param_list = NULL; + niFrameSurface1_t *p_hwframe = NULL; + ni_test_frame_list_t frame_list = {0}; + char encConfXcoderParamsList[MAX_OUTPUT_FILES][2048] = {0}; + char encConfXcoderGopList[MAX_OUTPUT_FILES][2048] = {0}; char decConfXcoderParams[2048] = {0}; char scaConfXcoderParams[2048] = {0}; int ret = 0; - int recycle_index = 0; ni_log_level_t log_level = NI_LOG_INFO; - - //inelegant solution but quick when memory is cheap - niFrameSurface1_t hwframe_pool_tracker[NI_MAX_DR_HWDESC_FRAME_INDEX]; - memset(hwframe_pool_tracker, 0, - NI_MAX_DR_HWDESC_FRAME_INDEX * sizeof(niFrameSurface1_t)); - ni_device_handle_t dev_handle = NI_INVALID_DEVICE_HANDLE, - dev_handle_1 = NI_INVALID_DEVICE_HANDLE; + int print_time = 0; + ni_rate_emu_t rate_emu = {0}; int src_codec_format = 0, dst_codec_format = 0; int bit_depth = 8; - + void *yuv_buf; int input_arg_width[MAX_INPUT_FILES] = {0}; int input_arg_height[MAX_INPUT_FILES] = {0}; int input_bit_depth[MAX_INPUT_FILES]; int input_arg_pfs[MAX_INPUT_FILES] = {0}; - ni_h264_sps_t SPS = {0}; // input header SPS ni_h265_sps_t HEVC_SPS = {0}; ni_vp9_header_info_t VP9_INFO = {0}; - int input_index = 0; - int input_total; + int input_index = 0, output_o_index = 0, output_x_index = 0, output_g_index = -1; + int input_total, output_total = 0; int size_index = 0; int bit_depth_index = 0; - + int user_data_sei_passthru = 0; + ni_pix_fmt_t pix_fmt = NI_PIX_FMT_YUV420P; + ni_sw_pix_fmt_t sw_pix_fmt = NI_SW_PIX_FMT_NONE; + int rx_size; + int chunk_size; + int eos = 0; + int send_fin_flag = 0; + int receive_fin_flag = 0; // Input arg handling int opt; int opt_index; - const char *opt_string = "hvtl:c:i:s:m:b:x:d:f:o:r:"; + const char *opt_string = "hvtl:c:i:s:m:b:x:g:d:f:o:r:e:p:u:"; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, @@ -6812,10 +7982,14 @@ int main(int argc, char *argv[]) {"mode", required_argument, NULL, 'm'}, {"bitdepth", required_argument, NULL, 'b'}, {"xcoder-params", required_argument, NULL, 'x'}, + {"xcoder-gop", required_argument, NULL, 'g'}, {"decoder-params", required_argument, NULL, 'd'}, {"scaler-params", required_argument, NULL, 'f'}, {"output", required_argument, NULL, 'o'}, {"repeat", required_argument, NULL, 'r'}, + {"readframerate", required_argument, NULL, 'e'}, + {"pix_fmt", required_argument, NULL, 'p'}, + {"user_data_sei_passthru", required_argument, NULL, 'u'}, {NULL, 0, NULL, 0}, }; @@ -6828,7 +8002,7 @@ int main(int argc, char *argv[]) print_usage(); exit(0); case 'v': - printf("Release ver: %s\n" + printf( "Release ver: %s\n" "API ver: %s\n" "Date: %s\n" "ID: %s\n", @@ -6857,7 +8031,7 @@ int main(int argc, char *argv[]) case 'i': if (input_index == MAX_INPUT_FILES) { - printf("Error: number of input files cannot exceed %d\n", MAX_INPUT_FILES); + ni_log(NI_LOG_ERROR, "Error: number of input files cannot exceed %d\n", MAX_INPUT_FILES); exit(-1); } strcpy(sdPara.fileName[input_index], optarg); @@ -6866,7 +8040,7 @@ int main(int argc, char *argv[]) case 's': if (size_index == MAX_INPUT_FILES) { - printf("Error: number of input resolutions cannot exceed %d\n", MAX_INPUT_FILES); + ni_log(NI_LOG_ERROR, "Error: number of input resolutions cannot exceed %d\n", MAX_INPUT_FILES); exit(-1); } input_arg_width[size_index] = (int)strtol(optarg, &n, 10); @@ -6889,7 +8063,10 @@ int main(int argc, char *argv[]) strcmp(optarg, "u2a") != 0 && strcmp(optarg, "u2h") != 0 && strcmp(optarg, "a2r") != 0 && strcmp(optarg, "h2r") != 0 && strcmp(optarg, "u2x") != 0 && strcmp(optarg, "y2x") != 0 && - strcmp(optarg, "v2y") != 0) + strcmp(optarg, "v2y") != 0 && strcmp(optarg, "y2o") != 0 && + strcmp(optarg, "v2a") != 0 && strcmp(optarg, "v2h") != 0 && + strcmp(optarg, "v2x") != 0 && strcmp(optarg, "a2x") != 0 && + strcmp(optarg, "h2x") != 0) arg_error_exit("-, | --mode", optarg); // determine dec/enc/xcod mode to use @@ -6949,11 +8126,18 @@ int main(int argc, char *argv[]) dst_codec_format = NI_CODEC_FORMAT_AV1; strcat(mode_description, " to AV1"); } + if (optarg[2] == 'o') + { + dst_codec_format = NI_CODEC_FORMAT_AV1; + av1_output_obu = 1; + strcat(mode_description, " to AV1 OBU"); + } break; case 'b': if (bit_depth_index == MAX_INPUT_FILES) { - printf("Error: cannot input more than %d bitdepth\n", MAX_INPUT_FILES); + ni_log(NI_LOG_ERROR, "Error: cannot input more than %d bitdepth\n", + MAX_INPUT_FILES); exit(-1); } if (!(atoi(optarg) == 8 || atoi(optarg) == 10)) @@ -6962,7 +8146,26 @@ int main(int argc, char *argv[]) bit_depth_index++; break; case 'x': - strcpy(encConfXcoderParams, optarg); + if (output_x_index == MAX_OUTPUT_FILES) + { + ni_log(NI_LOG_ERROR, "Error: number of encoder config cannot exceed %d\n", + MAX_OUTPUT_FILES); + exit(-1); + } + + // Set the index of corresponding xcoder-gop the same as the current index of xcoder-params + output_g_index = output_x_index; + strcpy(encConfXcoderParamsList[output_x_index], optarg); + output_x_index++; + break; + case 'g': + if(output_g_index != output_x_index - 1) + { + ni_log(NI_LOG_ERROR, "Error: xcoder-gop must follow xcoder-params, not the other way around\n"); + exit(-1); + } + + strcpy(encConfXcoderGopList[output_g_index], optarg); break; case 'd': strcpy(decConfXcoderParams, optarg); @@ -6970,13 +8173,56 @@ int main(int argc, char *argv[]) case 'f': strcpy(scaConfXcoderParams, optarg); break; - case 'o': - strcpy(rcPara.fileName, optarg); + case 'o': + strcpy(rcPara.fileName, optarg); + if (output_o_index == MAX_OUTPUT_FILES) + { + ni_log(NI_LOG_ERROR, "Error: number of output files cannot exceed %d\n", + MAX_OUTPUT_FILES); + exit(-1); + } + + for (i = 0; i < output_o_index; i++) + { + if (0 == strcmp(&outFileNameList[i * FILE_NAME_LEN], + optarg)) + { + ni_log(NI_LOG_ERROR, "Error: output file names must be unique: %s\n", + optarg); + exit(-1); + } + } + + strcpy(&outFileNameList[output_o_index * FILE_NAME_LEN], + optarg); + output_o_index++; + break; + case 'r': + if (!(atoi(optarg) >= 1)) + arg_error_exit("-r | --repeat", optarg); + g_repeat = atoi(optarg); + break; + case 'p': + pix_fmt = ni_pixel_format_search(optarg); + if (pix_fmt == NI_PIX_FMT_NONE) + { + if (!strcmp(optarg, "yuv444p")) + { + sw_pix_fmt = NI_SW_PIX_FMT_YUV444P; + } + else + { + arg_error_exit("-p | --pix_fmt", optarg); + } + } + break; + case 'u': + user_data_sei_passthru = atoi(optarg) >= 1; break; - case 'r': - if (!(atoi(optarg) >= 1)) - arg_error_exit("-r | --repeat", optarg); - g_repeat = atoi(optarg); + case 'e': + if (atoi(optarg) < 0) + arg_error_exit("-e | --readframerate", optarg); + rate_emu.rate_emu_framerate = atoi(optarg); break; default: print_usage(); @@ -6984,33 +8230,67 @@ int main(int argc, char *argv[]) } } + // readframerate parameter check + if (rate_emu.rate_emu_framerate != 0) + { + if (mode != XCODER_APP_ENCODE) + { + ni_log(NI_LOG_ERROR, "Error: readframerate %d setting only available for ENCODE mode - y2a, y2h, y2x, y2o\n", rate_emu.rate_emu_framerate); + exit(-1); + } + } + // sequence change input parameter check if (input_index != size_index) { if (mode == XCODER_APP_ENCODE) { - printf("Error: number of input files %d does not match with number of input resolutions %d\n", input_index, size_index); + ni_log(NI_LOG_ERROR, "Error: number of input files %d does not match with number of input resolutions %d\n", input_index, size_index); exit(-1); } } - + input_total = input_index; if (input_total > 1) { if (mode != XCODER_APP_ENCODE) { - printf("Error: multiple input files not supported for mode %d\n", mode); + ni_log(NI_LOG_ERROR, "Error: multiple input files not supported for mode %d\n", mode); exit(-1); } if (g_repeat > 1) { - printf("Error: multiple input files not supported when repeat %d greater than one\n", g_repeat); + ni_log(NI_LOG_ERROR, "Error: multiple input files not supported when repeat %d greater than one\n", g_repeat); exit(-1); } } + // checking for HW frame ladder encode support + if (output_x_index > 1 && output_o_index != output_x_index) + { + ni_log(NI_LOG_ERROR, "Error: number of output files: %d does not match number of " + "encode config: %d\n", + output_o_index, output_x_index); + exit(-1); + } + + if ((sw_pix_fmt == NI_SW_PIX_FMT_YUV444P || + sw_pix_fmt == NI_SW_PIX_FMT_YUV444P10LE) && output_o_index != 2) + { + ni_log(NI_LOG_ERROR, "Error: Must indicate 2 output files for yuv444p encoding\n"); + exit(-1); + } + + if (output_o_index > 1 && NI_CODEC_FORMAT_AV1 == dst_codec_format) + { + ni_log(NI_LOG_ERROR, "Error: multi-encoding is only supported for non-AV1 codec\n"); + exit(-1); + } + + output_total = output_o_index; + for ( ; bit_depth_index < MAX_INPUT_FILES; bit_depth_index++) { input_bit_depth[bit_depth_index] = 8; @@ -7023,7 +8303,20 @@ int main(int argc, char *argv[]) // Check required args are present if (!sdPara.fileName[0][0]) { - printf("Error: missing argument for -i | --input\n"); + ni_log(NI_LOG_ERROR, "Error: missing argument for -i | --input\n"); + exit(-1); + } + + if (ni_posix_memalign(&yuv_buf, sysconf(_SC_PAGESIZE), MAX_YUV_FRAME_SIZE)) + { + ni_log(NI_LOG_ERROR, "Error: failed to allocate YUV data buffer"); + exit(-1); + } + + p_dec_api_param = malloc(sizeof(*p_dec_api_param)); + if (!p_dec_api_param) + { + ni_log(NI_LOG_ERROR, "Error: failed to allocate p_dec_api_param\n"); exit(-1); } @@ -7031,7 +8324,7 @@ int main(int argc, char *argv[]) { if (!sdPara.fileName[input_index][0]) { - printf("Error: incorrect input file %d\n", input_index); + ni_log(NI_LOG_ERROR, "Error: incorrect input file %d\n", input_index); exit(-1); } @@ -7043,12 +8336,11 @@ int main(int argc, char *argv[]) if (input_arg_pfs[input_index] < 0) { - fprintf(stderr, "Error: cannot open %s\n", sdPara.fileName[input_index]); - fprintf(stderr, "Error: input file read failure\n"); - err_flag = 1; + ni_log(NI_LOG_ERROR, "Error: cannot open %s\n", sdPara.fileName[input_index]); + ni_log(NI_LOG_ERROR, "Error: input file read failure\n"); goto end; } - printf("SUCCESS: Opened input file: %s with file id = %d\n", + ni_log(NI_LOG_INFO, "SUCCESS: Opened input file: %s with file id = %d\n", sdPara.fileName[input_index], input_arg_pfs[input_index]); } @@ -7059,12 +8351,12 @@ int main(int argc, char *argv[]) (mode != XCODER_APP_ENCODE) && (mode != XCODER_APP_HWUP_ENCODE) && (mode != XCODER_APP_FILTER)) { - printf("Error: missing argument for -m | --mode\n"); + ni_log(NI_LOG_ERROR, "Error: missing argument for -m | --mode\n"); exit(-1); } if (!rcPara.fileName[0]) { - printf("Error: missing argument for -o | --output\n"); + ni_log(NI_LOG_ERROR, "Error: missing argument for -o | --output\n"); exit(-1); } @@ -7072,66 +8364,43 @@ int main(int argc, char *argv[]) rcPara.mode = mode; // Print high-level description of processing to occur and codecs involved - printf("%s...\n", mode_description); - - pkt_size = 131040; // hardcoded input data chunk size (for H.265) - - lseek(pfs, 0, SEEK_END); - total_file_size = lseek(pfs, 0, SEEK_CUR); - lseek(pfs, 0, SEEK_SET); - unsigned long tmpFileSize = total_file_size; - - /* - if (fileName2[0]) - { - - - - -#ifdef _WIN32 - pfs2 = open(fileName2, O_RDONLY | O_BINARY); -#else - pfs2 = open(fileName2, O_RDONLY); -#endif + ni_log(NI_LOG_INFO, "%s...\n", mode_description); - if (pfs2 < 0) - { - fprintf(stderr, "Error: cannot open %s\n", fileName2); - fprintf(stderr, "Error: input file read failure\n"); - err_flag = 1; - goto end; - } - printf("SUCCESS: Opened 2nd input file for sequence change: %s with file id = %d\n", - fileName2, pfs2); - - lseek(pfs2, 0, SEEK_SET); - } - */ + pkt_size = 131040; // hardcoded input data chunk size (for H.265 1080p) + get_total_file_size(pfs); if (mode == XCODER_APP_ENCODE || mode == XCODER_APP_HWUP_ENCODE) { ni_log(NI_LOG_DEBUG, "YUV input read will repeat %d times\n", g_repeat); ni_log(NI_LOG_DEBUG, "YUV input, do not read all to cache\n"); } else { + uint32_t read_chunk = 4096; + uint64_t tmpFileSize = total_file_size; + //try to allocate memory for input file buffer, quit if failure if (total_file_size > 0 && !(g_file_cache = malloc(total_file_size))) { - fprintf(stderr, - "Error: input file size %u exceeding max malloc, quit\n", - total_file_size); + ni_log(NI_LOG_ERROR, + "Error: input file size %llu exceeding max malloc, quit\n", + (unsigned long long)total_file_size); goto end; } g_curr_cache_pos = g_file_cache; - printf("Reading %u bytes in total ..\n", total_file_size); + ni_log(NI_LOG_INFO, "Reading %llu bytes in total ..\n", (unsigned long long)total_file_size); + while (tmpFileSize) { - int one_read_size = read(pfs, g_curr_cache_pos, 4096); + if (read_chunk > tmpFileSize) + { + read_chunk = tmpFileSize; + } + int one_read_size = read(pfs, g_curr_cache_pos, read_chunk); if (one_read_size == -1) { - fprintf(stderr, "Error: reading file, quit! left-to-read %lu\n", - tmpFileSize); - fprintf(stderr, "Error: input file read error\n"); + ni_log(NI_LOG_ERROR, "Error: reading file, quit! left-to-read %llu\n", + (unsigned long long)tmpFileSize); + ni_log(NI_LOG_ERROR, "Error: input file read error\n"); goto end; } else { @@ -7139,25 +8408,39 @@ int main(int argc, char *argv[]) g_curr_cache_pos += one_read_size; } } - printf("read %u bytes from input file into memory\n", total_file_size); + ni_log(NI_LOG_INFO, "read %llu bytes from input file into memory\n", (unsigned long long)total_file_size); } g_curr_cache_pos = g_file_cache; - data_left_size = total_file_size; - if (strcmp(rcPara.fileName, "null") != 0 && strcmp(rcPara.fileName, "/dev/null") != 0) + // HWUP + ladder encode single-thread uses multi output setup + for (i = 0; i < output_total; i++) { - p_file = fopen(rcPara.fileName, "wb"); - if (p_file == NULL) + if (strcmp(&outFileNameList[i * FILE_NAME_LEN], "null") != 0 && + strcmp(&outFileNameList[i * FILE_NAME_LEN], "/dev/null") != 0) { - fprintf(stderr, "Error: cannot open %s\n", rcPara.fileName); - err_flag = 1; - goto end; + p_file_list[i] = + fopen(&outFileNameList[i * FILE_NAME_LEN], "wb"); + if (p_file_list[i] == NULL) + { + ni_log(NI_LOG_ERROR, "Error: cannot open %s\n", + &outFileNameList[i * FILE_NAME_LEN]); + goto end; + } + ni_log(NI_LOG_INFO, "SUCCESS: Opened output file: %s\n", + &outFileNameList[i * FILE_NAME_LEN]); + } else + { + p_file_list[i] = NULL; + ni_log(NI_LOG_INFO, "SUCCESS: output %d file %s implies dropping output\n", + (int)i + 1, &outFileNameList[i * FILE_NAME_LEN]); } - printf("SUCCESS: Opened output file: %s\n", rcPara.fileName); } - else + + p_enc_api_param_list = calloc(output_total, sizeof(ni_xcoder_params_t)); + if (!p_enc_api_param_list) { - printf("SUCCESS: output file %s implies dropping output\n", rcPara.fileName); + ni_log(NI_LOG_ERROR, "Error: calloc for enc ladder parameters.\n"); + goto end; } // for H.264, probe the source and use the probed source info as defaults @@ -7167,7 +8450,7 @@ int main(int argc, char *argv[]) { if (probe_h264_stream_info(&SPS)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "ERROR: H.264 file probing complete, source file format " "not supported !\n"); goto end; @@ -7180,11 +8463,11 @@ int main(int argc, char *argv[]) arg_width = SPS.width; arg_height = SPS.height; } else if (NI_CODEC_FORMAT_H265 == src_codec_format && - (mode == XCODER_APP_DECODE)) + (mode == XCODER_APP_DECODE || mode == XCODER_APP_TRANSCODE)) { if (probe_h265_stream_info(&HEVC_SPS)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "ERROR: H.265 file probing complete, source file format " "not supported !\n"); goto end; @@ -7201,18 +8484,18 @@ int main(int argc, char *argv[]) "resolution %dx%d\n", HEVC_SPS.bit_depth_chroma, arg_width, arg_height); } else if (NI_CODEC_FORMAT_VP9 == src_codec_format && - (mode == XCODER_APP_DECODE)) + (mode == XCODER_APP_DECODE || mode == XCODER_APP_TRANSCODE)) { if (probe_vp9_stream_info(&VP9_INFO)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "ERROR: VP9 file probing complete, source file format " "not supported !\n"); goto end; } ni_log(NI_LOG_INFO, "Using probed VP9 source info: %d profile " - "resolution %dx%d, timebase %d/%d\n", + "resolution %ux%u, timebase %u/%u\n", VP9_INFO.profile, VP9_INFO.width, VP9_INFO.height, VP9_INFO.timebase.den, VP9_INFO.timebase.num); bit_depth = VP9_INFO.profile ? 10 : 8; @@ -7226,10 +8509,10 @@ int main(int argc, char *argv[]) rcPara.arg_height = arg_height; // set up decoder p_config with some hard coded numbers - if (ni_decoder_init_default_params(&dec_api_param, 25, 1, 200000, arg_width, + if (ni_decoder_init_default_params(p_dec_api_param, 25, 1, 200000, arg_width, arg_height) < 0) { - fprintf(stderr, "Error: decoder p_config set up error\n"); + ni_log(NI_LOG_ERROR, "Error: decoder p_config set up error\n"); return -1; } @@ -7237,62 +8520,68 @@ int main(int argc, char *argv[]) receive_fin_flag = 0; ni_session_context_t dec_ctx = {0}; - ni_session_context_t enc_ctx = {0}; + ni_session_context_t enc_ctx_list[MAX_OUTPUT_FILES] = {0}; ni_session_context_t upl_ctx = {0}; ni_session_context_t sca_ctx = {0}; ni_session_context_t crop_ctx = {0}; ni_session_context_t pad_ctx = {0}; ni_session_context_t ovly_ctx = {0}; ni_session_context_t fmt_ctx = {0}; + ni_rate_emu_t enc_rate_emu_list[MAX_OUTPUT_FILES] = {0}; if (ni_device_session_context_init(&dec_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } - if (ni_device_session_context_init(&enc_ctx) < 0) + for (i = 0; i < output_total; i++) { - fprintf(stderr, "Error: init decoder context error\n"); - return -1; + if (ni_device_session_context_init(&enc_ctx_list[i]) < 0) + { + ni_log(NI_LOG_ERROR, "Error: init encoder ladder %d context error\n", + (int)i); + return -1; + } } + if (ni_device_session_context_init(&upl_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } if (ni_device_session_context_init(&sca_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } if (ni_device_session_context_init(&crop_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } if (ni_device_session_context_init(&pad_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } if (ni_device_session_context_init(&ovly_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } if (ni_device_session_context_init(&fmt_ctx) < 0) { - fprintf(stderr, "Error: init decoder context error\n"); + ni_log(NI_LOG_ERROR, "Error: init decoder context error\n"); return -1; } sdPara.p_dec_ctx = (void *)&dec_ctx; - sdPara.p_enc_ctx = (void *)&enc_ctx; + sdPara.p_enc_ctx = (void *)&enc_ctx_list[0]; sdPara.p_upl_ctx = (void *)&upl_ctx; sdPara.p_sca_ctx = (void *)&sca_ctx; sdPara.p_crop_ctx = (void *)&crop_ctx; @@ -7300,7 +8589,7 @@ int main(int argc, char *argv[]) sdPara.p_ovly_ctx = (void *)&ovly_ctx; sdPara.p_fmt_ctx = (void *)&fmt_ctx; rcPara.p_dec_ctx = (void *)&dec_ctx; - rcPara.p_enc_ctx = (void *)&enc_ctx; + rcPara.p_enc_ctx = (void *)&enc_ctx_list[0]; rcPara.p_upl_ctx = (void *)&upl_ctx; rcPara.p_sca_ctx = (void *)&sca_ctx; rcPara.p_crop_ctx = (void *)&crop_ctx; @@ -7308,13 +8597,16 @@ int main(int argc, char *argv[]) rcPara.p_ovly_ctx = (void *)&ovly_ctx; rcPara.p_fmt_ctx = (void *)&fmt_ctx; - enc_ctx.nb_rois = 0; - enc_ctx.roi_side_data_size = 0; - enc_ctx.nb_rois = 0; - enc_ctx.roi_side_data_size = 0; - enc_ctx.av_rois = NULL; - - enc_ctx.codec_format = dst_codec_format; + for (i = 0; i < output_total; i++) + { + enc_ctx_list[i].nb_rois = 0; + enc_ctx_list[i].roi_side_data_size = 0; + enc_ctx_list[i].nb_rois = 0; + enc_ctx_list[i].roi_side_data_size = 0; + enc_ctx_list[i].av_rois = NULL; + enc_ctx_list[i].codec_format = dst_codec_format; + enc_rate_emu_list[i].rate_emu_framerate = rate_emu.rate_emu_framerate; + } if (mode == XCODER_APP_TRANSCODE || mode == XCODER_APP_DECODE || mode == XCODER_APP_FILTER) @@ -7323,9 +8615,9 @@ int main(int argc, char *argv[]) dec_ctx.session_id = NI_INVALID_SESSION_ID; dec_ctx.codec_format = src_codec_format; - // default decode the UDU; ToDo: make it configurable - if (src_codec_format == NI_CODEC_FORMAT_H264) - dec_ctx.enable_user_data_sei_passthru = 1; + // user_data_sei_passthru disabled by default + if ((NI_CODEC_FORMAT_H264 == src_codec_format) || (NI_CODEC_FORMAT_H265 == src_codec_format)) + dec_ctx.enable_user_data_sei_passthru = user_data_sei_passthru; // no need to directly allocate resource context rcPara.p_dec_rsrc_ctx = sdPara.p_dec_rsrc_ctx = NULL; @@ -7336,7 +8628,7 @@ int main(int argc, char *argv[]) NI_INVALID_DEVICE_HANDLE; dec_ctx.hw_id = iXcoderGUID; - dec_ctx.p_session_config = &dec_api_param; + dec_ctx.p_session_config = p_dec_api_param; // default: little endian dec_ctx.src_bit_depth = bit_depth; dec_ctx.src_endian = NI_FRAME_LITTLE_ENDIAN; @@ -7347,23 +8639,34 @@ int main(int argc, char *argv[]) } // check and set ni_decoder_params from --xcoder-params - if (retrieve_decoder_params(decConfXcoderParams, &dec_api_param, - &dec_ctx)) // + if (ni_retrieve_decoder_params(decConfXcoderParams, p_dec_api_param, + &dec_ctx)) { - fprintf(stderr, "Error: encoder p_config parsing error\n"); + ni_log(NI_LOG_ERROR, "Error: encoder p_config parsing error\n"); return -1; } - if (dec_ctx.hw_action && mode == XCODER_APP_DECODE) + if (p_dec_api_param->dec_input_params.hwframes && + mode == XCODER_APP_DECODE && + strcmp(rcPara.fileName, "null") != 0 && + strcmp(rcPara.fileName, "/dev/null") != 0) { - fprintf( - stderr, - "Error: decode only with hwframes produces unusable output\n"); - return -1; + ni_log(NI_LOG_ERROR, "Error: decode only with hwframes supports null " + "output only\n"); + goto end; + } + + // set async mode in dec_ctx if multi-threaded + if ((mode == XCODER_APP_DECODE || mode == XCODER_APP_TRANSCODE) && + multi_thread) + { + ni_log(NI_LOG_INFO, "Decoding is multi-threaded, set async mode in " + "session context !\n"); + dec_ctx.async_mode = 1; } // Decode, use all the parameters specified by user - if (0 != - (ret = decoder_open_session(&dec_ctx, iXcoderGUID, &dec_api_param))) + ret = decoder_open_session(&dec_ctx, iXcoderGUID, p_dec_api_param); + if (ret != 0) { goto end; } @@ -7385,12 +8688,10 @@ int main(int argc, char *argv[]) // encoder session open, if needed, will be at the first frame arrival as it // carries source stream info that may be useful in encoding config - sos_flag = 1; total_bytes_received = 0; - xcodeRecvTotal = 0; total_bytes_sent = 0; - printf("user video resolution: %dx%d\n", arg_width, arg_height); + ni_log(NI_LOG_INFO, "user video resolution: %dx%d\n", arg_width, arg_height); if (arg_width == 0 || arg_height == 0) { input_video_width = 1280; @@ -7408,21 +8709,27 @@ int main(int argc, char *argv[]) (void)ni_gettimeofday(¤t_time, NULL); start_timestamp = privious_timestamp = current_timestamp = time(NULL); -#if 0 -#if __linux__ || __APPLE__ - struct timespec start, end; - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); -#endif -#endif + if (bit_depth == 10 && (pix_fmt != NI_PIX_FMT_YUV420P10LE && + pix_fmt != NI_PIX_FMT_P010LE)) + { + ni_log(NI_LOG_INFO, "Warning: The -b | --bit_depth option would be " + "deprecated in the future. If you have indicated both of the " + "pixel format and bith depth option here, please notice the " + "compatibility. Here it would set the pixel format as " + "yuv420p10le by force with bit depth of 10!\n"); + pix_fmt = NI_PIX_FMT_YUV420P10LE; + } if (mode == XCODER_APP_DECODE) { - printf("Decoding Mode: %dx%d to %dx%d HWFrames %d\n", input_video_width, - input_video_height, output_video_width, output_video_height, - dec_ctx.hw_action); + void *p_stream_info = NULL; ni_session_data_io_t in_pkt = {0}; ni_session_data_io_t out_frame = {0}; - void *p_stream_info = NULL; + + ni_log(NI_LOG_INFO, "Decoding Mode: %dx%d to %dx%d HWFrames %d\n", input_video_width, + input_video_height, output_video_width, output_video_height, + dec_ctx.hw_action); + if (src_codec_format == NI_CODEC_FORMAT_H264) p_stream_info = &SPS; else if (src_codec_format == NI_CODEC_FORMAT_H265) @@ -7443,23 +8750,23 @@ int main(int argc, char *argv[]) dec_send_param.pkt_size = pkt_size; dec_send_param.print_time = 0; // not support now dec_send_param.p_total_bytes_sent = &total_bytes_sent; - dec_send_param.p_xcodeState = &xcodeState; + dec_send_param.p_xcoder_state = &xcoder_state; dec_send_param.p_stream_info = p_stream_info; dec_recv_param.p_dec_ctx = &dec_ctx; dec_recv_param.p_out_frame = &out_frame; dec_recv_param.output_video_width = output_video_width; dec_recv_param.output_video_height = output_video_height; - dec_recv_param.p_file = p_file; + dec_recv_param.p_file = p_file_list[0]; dec_recv_param.p_total_bytes_received = &total_bytes_received; - dec_recv_param.p_xcodeState = &xcodeState; + dec_recv_param.p_xcoder_state = &xcoder_state; dec_recv_param.mode = mode; - dec_recv_param.test_frame_list = NULL; + dec_recv_param.frame_list = NULL; if (ni_pthread_create(&dec_send_tid, NULL, decoder_send_thread, &dec_send_param)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: create decoder send thread failed in decode " "mode\n"); return -1; @@ -7467,641 +8774,588 @@ int main(int argc, char *argv[]) if (ni_pthread_create(&dec_recv_tid, NULL, decoder_receive_thread, &dec_recv_param)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: create decoder receive thread failed in decode " "mode\n"); return -1; } + ni_pthread_join(dec_send_tid, NULL); ni_pthread_join(dec_recv_tid, NULL); + (void)ni_gettimeofday(¤t_time, NULL); } else { while (send_fin_flag == 0 || receive_fin_flag == 0) { (void)ni_gettimeofday(¤t_time, NULL); - int print_time = - ((current_time.tv_sec - previous_time.tv_sec) > 1); + print_time = need_time_print(¤t_time, &previous_time); // Sending - send_fin_flag = decoder_send_data( - &dec_ctx, &in_pkt, sos_flag, input_video_width, - input_video_height, pkt_size, total_file_size, - &total_bytes_sent, print_time, &xcodeState, p_stream_info); - sos_flag = 0; + send_fin_flag = decoder_send_data(&dec_ctx, &in_pkt, + input_video_width, + input_video_height, pkt_size, + &total_bytes_sent, print_time, + &xcoder_state, p_stream_info); if (send_fin_flag < 0) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: decoder_send_data() failed, rc: %d\n", send_fin_flag); break; } // Receiving - receive_fin_flag = decoder_receive_data( - &dec_ctx, &out_frame, output_video_width, - output_video_height, p_file, &total_bytes_received, - print_time, 1, &xcodeState); - ni_decoder_frame_buffer_free(&(out_frame.data.frame)); - if (print_time) + do { - previous_time = current_time; - } + rx_size = 0; + receive_fin_flag = decoder_receive_data(&dec_ctx, &out_frame, + output_video_width, + output_video_height, + p_file_list[0], + &total_bytes_received, + print_time, 1, + &xcoder_state, + &rx_size); + + if (dec_ctx.hw_action == NI_CODEC_HW_ENABLE) + { + if (receive_fin_flag != NI_TEST_RETCODE_EAGAIN && + receive_fin_flag != NI_TEST_RETCODE_END_OF_STREAM) + { + ni_frame_t *p_ni_frame = &out_frame.data.frame; + p_hwframe = (niFrameSurface1_t *)p_ni_frame->p_data[3]; + ni_log(NI_LOG_DEBUG, "decoder_receive_data HW decode-only. recycle HW frame idx %u\n", p_hwframe->ui16FrameIdx); + ni_hwframe_buffer_recycle2(p_hwframe); + ni_frame_buffer_free(p_ni_frame); + } + } + else + { + ni_decoder_frame_buffer_free(&(out_frame.data.frame)); + } + + if (print_time) + { + previous_time = current_time; + } + + // Error or eos + if (receive_fin_flag < 0 || out_frame.data.frame.end_of_stream) + { + break; + } - // Error or eos + (void)ni_gettimeofday(¤t_time, NULL); + print_time = need_time_print(¤t_time, &previous_time); + } while (!dec_ctx.decoder_low_delay && rx_size > 0); //drain consecutive outputs + // Error or eos if (receive_fin_flag < 0 || out_frame.data.frame.end_of_stream) { break; } } } - unsigned int time_diff = - (unsigned int)(current_time.tv_sec - start_time.tv_sec); - if (time_diff == 0) - time_diff = 1; - printf("[R] Got: Frames= %u fps=%f Total bytes %llu\n", - number_of_frames, ((float)number_of_frames / (float)time_diff), - total_bytes_received); + decoder_stat_report_and_close(&dec_ctx, total_bytes_received); - ni_device_session_close(&dec_ctx, 1, NI_DEVICE_TYPE_DECODER); ni_rsrc_free_device_context(sdPara.p_dec_rsrc_ctx); rcPara.p_dec_rsrc_ctx = NULL; sdPara.p_dec_rsrc_ctx = NULL; ni_packet_buffer_free(&(in_pkt.data.packet)); - ni_decoder_frame_buffer_free(&(out_frame.data.frame)); - } else if (mode == XCODER_APP_ENCODE) - { - printf("Encoding Mode: %dx%d to %dx%d\n", input_video_width, - input_video_height, output_video_width, output_video_height); - - // set up encoder p_config, using some hard coded numbers - if (ni_encoder_init_default_params(&api_param, 30, 1, 200000, arg_width, - arg_height, - enc_ctx.codec_format) < 0) + if (dec_ctx.hw_action != NI_CODEC_HW_ENABLE) { - fprintf(stderr, "Error: encoder init default set up error\n"); - return -1; + ni_decoder_frame_buffer_free(&(out_frame.data.frame)); } + } else if (mode == XCODER_APP_ENCODE) + { + ni_session_data_io_t in_frame = {0}; + ni_session_data_io_t out_packet = {0}; + ni_session_data_io_t sw_pix_frame[2]; + memset(sw_pix_frame, 0, 2 * sizeof(ni_session_data_io_t)); - // check and set ni_encoder_params from --xcoder-params - if (retrieve_xcoder_params(encConfXcoderParams, &api_param, &enc_ctx)) - { - fprintf(stderr, "Error: encoder p_config parsing error\n"); - return -1; - } + ni_log(NI_LOG_INFO, "Encoding Mode: %dx%d to %dx%d\n", input_video_width, + input_video_height, output_video_width, output_video_height); - ni_hrd_params_t hrd_params; - int video_full_range_flag = 0; - if (api_param.video_full_range_flag >= 0) - { - ni_log(NI_LOG_DEBUG, "Using user-configured video_full_range_flag " - "%d\n", - api_param.video_full_range_flag); - video_full_range_flag = api_param.video_full_range_flag; - } - - // for encode from YUV, use all the parameters specified by user - if (0 != - (ret = encoder_open_session( - &enc_ctx, dst_codec_format, iXcoderGUID, &api_param, bit_depth, - arg_width, arg_height, &hrd_params, api_param.color_primaries, - api_param.color_transfer_characteristic, api_param.color_space, - video_full_range_flag, api_param.sar_num, api_param.sar_denom, - 1))) + in_frame.data.frame.pixel_format = pix_fmt; + ret = encoder_open(&enc_ctx_list[0], p_enc_api_param_list, output_total, + &encConfXcoderParamsList[0], &encConfXcoderGopList[0], NULL, arg_width, + arg_height, fps_num, fps_den, bitrate, + dst_codec_format, pix_fmt, 0, iXcoderGUID, NULL, + multi_thread, &enc_rate_emu_list[0], + (sw_pix_fmt != NI_SW_PIX_FMT_NONE) ? false : true); // zero copy is currently not supported for YUV444P + if (ret != 0) { goto end; } - ni_session_data_io_t in_frame = {0}; - ni_session_data_io_t out_packet = {0}; - - /* // currently xcoder demo app does not support semi-planar - following is for future reference - int is_planar = 1; - in_frame.data.frame.pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P : NI_PIX_FMT_NV12); - if (10 == bit_depth) - { - in_frame.data.frame.pixel_format = - (is_planar ? NI_PIX_FMT_YUV420P10LE : NI_PIX_FMT_P010LE); - } - */ - in_frame.data.frame.pixel_format = NI_PIX_FMT_YUV420P; - if (10 == bit_depth) - { - in_frame.data.frame.pixel_format = NI_PIX_FMT_YUV420P10LE; - } - if (multi_thread) { ni_pthread_t enc_send_tid, enc_recv_tid; enc_send_param_t enc_send_param = {0}; enc_recv_param_t enc_recv_param = {0}; - enc_send_param.p_enc_ctx = &enc_ctx; + enc_send_param.p_enc_ctx = &enc_ctx_list[0]; enc_send_param.p_in_frame = &in_frame; enc_send_param.input_video_width = input_video_width; enc_send_param.input_video_height = input_video_height; enc_send_param.pfs = pfs; + enc_send_param.yuv_buf = yuv_buf; memcpy(enc_send_param.input_arg_width, input_arg_width, sizeof(enc_send_param.input_arg_width)); memcpy(enc_send_param.input_arg_height, input_arg_height, sizeof(enc_send_param.input_arg_height)); memcpy(enc_send_param.input_bit_depth, input_bit_depth, sizeof(enc_send_param.input_bit_depth)); memcpy(enc_send_param.input_arg_pfs, input_arg_pfs, sizeof(enc_send_param.input_arg_pfs)); + enc_send_param.output_total = output_total; enc_send_param.p_total_bytes_sent = &total_bytes_sent; - enc_send_param.p_xcodeState = &xcodeState; + enc_send_param.p_xcoder_state = &xcoder_state_list[0]; enc_send_param.mode = mode; - enc_send_param.test_frame_list = NULL; + enc_send_param.frame_list = NULL; enc_send_param.dec_codec_format = -1; // not use heres - enc_send_param.p_input_exhausted = NULL; // not use heres - enc_send_param.p_hwframe_pool_tracker = NULL; // not use heres enc_send_param.input_total = input_total; + enc_send_param.sw_pix_fmt = sw_pix_fmt; + enc_send_param.p_rate_emu = &enc_rate_emu_list[0]; - enc_recv_param.p_enc_ctx = &enc_ctx; + enc_recv_param.p_enc_ctx = &enc_ctx_list[0]; enc_recv_param.p_out_packet = &out_packet; enc_recv_param.output_video_width = output_video_width; enc_recv_param.output_video_height = output_video_height; - enc_recv_param.p_file = p_file; - enc_recv_param.p_total_bytes_received = &total_bytes_received; - enc_recv_param.p_xcodeState = &xcodeState; + enc_recv_param.p_file = &p_file_list[0]; + enc_recv_param.output_total = output_total; + enc_recv_param.p_number_of_packets = &number_of_packets_list[0]; + enc_recv_param.p_total_bytes_received = &total_bytes_received_list[0]; + enc_recv_param.p_xcoder_state = &xcoder_state_list[0]; enc_recv_param.mode = mode; - enc_recv_param.p_hwframe_pool_tracker = NULL; enc_recv_param.p_buffered_frame = &in_frame; if (ni_pthread_create(&enc_send_tid, NULL, encoder_send_thread, &enc_send_param)) { - fprintf(stderr, - "Error: create encoder send thread failed in encode " - "mode\n"); + ni_log(NI_LOG_ERROR, "Error: create encoder send thread failed in " + "encode mode\n"); return -1; } if (ni_pthread_create(&enc_recv_tid, NULL, encoder_receive_thread, &enc_recv_param)) { - fprintf(stderr, - "Error: create encoder recieve thread failed in encode " - "mode\n"); + ni_log(NI_LOG_ERROR, "Error: create encoder recieve thread failed " + "in encode mode\n"); return -1; } + ni_pthread_join(enc_send_tid, NULL); ni_pthread_join(enc_recv_tid, NULL); (void)ni_gettimeofday(¤t_time, NULL); } else { - while (send_fin_flag == NI_TEST_RETCODE_SUCCESS || receive_fin_flag == NI_TEST_RETCODE_SUCCESS) + while (!end_of_all_streams && + (send_fin_flag == NI_TEST_RETCODE_SUCCESS || + receive_fin_flag == NI_TEST_RETCODE_SUCCESS)) { (void)ni_gettimeofday(¤t_time, NULL); - int print_time = - ((current_time.tv_sec - previous_time.tv_sec) > 1); + print_time = need_time_print(¤t_time, &previous_time); - // Sending - send_fin_flag = encoder_send_data( - &enc_ctx, &in_frame, sos_flag, input_arg_width[input_index], - input_arg_height[input_index], input_arg_pfs[input_index], total_file_size, &total_bytes_sent, - &xcodeState, input_bit_depth[input_index], (input_index == (input_total-1))); - sos_flag = 0; - - if (send_fin_flag == NI_TEST_RETCODE_EAGAIN) //Error - impossible case, since write buffer full is handled by encoder_send_data need_to_resend - { - break; - } else if (send_fin_flag == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change) + // encoder send again + if (send_fin_flag == NI_TEST_RETCODE_EAGAIN) { - input_index++; - lseek(input_arg_pfs[input_index], 0, SEEK_END); - total_file_size = lseek(input_arg_pfs[input_index], 0, SEEK_CUR); - lseek(input_arg_pfs[input_index], 0, SEEK_SET); - data_left_size = total_file_size; - send_fin_flag = NI_TEST_RETCODE_SUCCESS; + goto enc_mode_send; } - enc_receive: - // Receiving - receive_fin_flag = encoder_receive_data( - &enc_ctx, &out_packet, output_video_width, - output_video_height, p_file, &total_bytes_received, - print_time, &in_frame); // in_frame is passed in for the new resolution info of sequence change + chunk_size = read_yuv_from_file(input_arg_pfs[input_index], + yuv_buf, + input_arg_width[input_index], + input_arg_height[input_index], + pix_fmt, sw_pix_fmt, &eos, + enc_ctx_list[0].session_run_state); + if (chunk_size < 0) + { + goto end; + } - if (enc_ctx.codec_format == NI_CODEC_FORMAT_AV1) + // YUV444P reading + if (sw_pix_fmt != NI_SW_PIX_FMT_NONE) { - if (!out_packet.data.packet.av1_show_frame && - number_of_packets >= 2) + ret = convert_yuv_444p_to_420p(&sw_pix_frame[0], + eos ? NULL : yuv_buf, + input_arg_width[input_index], + input_arg_height[input_index], + sw_pix_fmt, 0, dst_codec_format); + if (ret < 0) { - ni_log(NI_LOG_DEBUG, "AV1 got not shown frames\n"); - number_of_packets -= 1; - goto enc_receive; + goto end; } } - if (print_time) +enc_mode_send: + for (i = 0; i < output_total; i++) { - previous_time = current_time; + if (sw_pix_fmt != NI_SW_PIX_FMT_NONE) + { + send_fin_flag = encoder_send_data3(&enc_ctx_list[i], + &sw_pix_frame[i], + input_arg_width[input_index], + input_arg_height[input_index], + &xcoder_state_list[i], eos); + } else + { + send_fin_flag = encoder_send_data(&enc_ctx_list[i], + &in_frame, eos ? NULL : yuv_buf, + input_arg_width[input_index], + input_arg_height[input_index], + &total_bytes_sent, + &xcoder_state_list[i], + input_index == input_total - 1, + &enc_rate_emu_list[i]); + } + + if (send_fin_flag == NI_TEST_RETCODE_EAGAIN) + { + break; + } else if (send_fin_flag == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change) + { + input_index++; + get_total_file_size(input_arg_pfs[input_index]); + send_fin_flag = NI_TEST_RETCODE_SUCCESS; + } } - // Error or eos - if (receive_fin_flag < 0 || - out_packet.data.packet.end_of_stream) + receive_fin_flag = encoder_receive(&enc_ctx_list[0], + &in_frame, &out_packet, + output_video_width, + output_video_height, + &number_of_packets_list[0], + output_total, &p_file_list[0], + &total_bytes_received_list[0], + print_time, + &xcoder_state_list[0]); + for (i = 0; receive_fin_flag >= 0 && i < output_total; i++) { - break; - } else if (receive_fin_flag == NI_TEST_RETCODE_SEQ_CHANGE_DONE) + if (!xcoder_state_list[i].enc_eos_received) + { + ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i); + end_of_all_streams = 0; + break; + } else + { + ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i); + end_of_all_streams = 1; + } + } + + if (print_time) { - xcodeState.enc_seq_change = 0; - receive_fin_flag = NI_TEST_RETCODE_SUCCESS; + previous_time = current_time; } } } - int timeDiff = (int)(current_time.tv_sec - start_time.tv_sec); - if (timeDiff == 0) - timeDiff = 1; - printf("[R] Got: Packets= %u fps=%f Total bytes %llu\n", - number_of_packets, - ((float)number_of_packets) / ((float)timeDiff), - total_bytes_received); - ni_device_session_close(&enc_ctx, 1, NI_DEVICE_TYPE_ENCODER); + encoder_stat_report_and_close(&enc_ctx_list[0], output_total, + &number_of_packets_list[0], + &total_bytes_received_list[0]); + ni_rsrc_free_device_context(sdPara.p_enc_rsrc_ctx); rcPara.p_enc_rsrc_ctx = NULL; sdPara.p_enc_rsrc_ctx = NULL; ni_frame_buffer_free(&(in_frame.data.frame)); ni_packet_buffer_free(&(out_packet.data.packet)); + for (i = 0; i < sizeof(sw_pix_frame)/sizeof(ni_session_data_io_t); i++) + { + ni_frame_buffer_free(&sw_pix_frame[i].data.frame); + } } else if (mode == XCODER_APP_HWUP_ENCODE) { ni_session_data_io_t in_frame = {0}; + ni_session_data_io_t scale_frame = {0}; ni_session_data_io_t swin_frame = {0}; ni_session_data_io_t out_packet = {0}; - printf("Upload + Encoding Mode: %dx%d to %dx%d\n", input_video_width, + int is_p2p = 0; + int pool_size = 3; //3 starting buffers to be augmented with additional + + ni_log(NI_LOG_INFO, "Upload + Encoding Mode: %dx%d to %dx%d\n", input_video_width, input_video_height, output_video_width, output_video_height); + // open and config uploader for encoding + int upload_width = arg_width; + int upload_height = arg_height; + // pad to minimum encoder supported width and height + if (arg_width < NI_MIN_WIDTH) + { + upload_width = NI_MIN_WIDTH; + } + if (arg_height < NI_MIN_HEIGHT) + { + upload_height = NI_MIN_HEIGHT; + } + // buffers by downstream entity like encoders + ret = uploader_open_session(&upl_ctx, iXcoderGUID, upload_width, upload_height, + pix_fmt, is_p2p, pool_size); + if (ret != 0) + { + goto end; + } if (multi_thread) { - ni_test_frame_list_t test_frame_list = {0}; - ni_pthread_t uploader_tid; uploader_param_t uploader_param = {0}; - ni_pthread_t enc_send_tid, enc_recv_tid; + ni_pthread_t enc_send_tid, enc_recv_tid, uploader_tid; enc_send_param_t enc_send_param = {0}; enc_recv_param_t enc_recv_param = {0}; ni_frame_t *p_ni_frame = NULL; - //open uploader - int pool_size = - 3; //3 starting buffers to be augmented with additional - // buffers by downstream entity like encoders - if (0 != - (ret = uploader_open_session(&upl_ctx, iXcoderGUID, bit_depth, - arg_width, arg_height, - 1 /*assume planar*/, pool_size))) - { - goto end; - } - uploader_param.p_upl_ctx = &upl_ctx; + uploader_param.p_sca_ctx = &sca_ctx; uploader_param.p_swin_frame = &swin_frame; + uploader_param.p_scale_frame = &scale_frame; uploader_param.input_video_width = input_video_width; uploader_param.input_video_height = input_video_height; uploader_param.pfs = pfs; + uploader_param.yuv_buf = yuv_buf; uploader_param.p_total_bytes_sent = &total_bytes_sent; - uploader_param.p_input_exhausted = &input_exhausted; uploader_param.pool_size = pool_size; - uploader_param.test_frame_list = &test_frame_list; + uploader_param.frame_list = &frame_list; if (ni_pthread_create(&uploader_tid, NULL, uploader_thread, &uploader_param)) { - fprintf( - stderr, - "Error: create uploader thread failed in upload mode\n"); + ni_log(NI_LOG_ERROR, "Error: create uploader thread failed in " + "upload mode\n"); return -1; } - // wait until received first HW frame - while (test_frames_isempty(&test_frame_list)) + // polling the first received HW frame + while (frame_list_is_empty(&frame_list) && !g_end_of_all_threads) { ni_usleep(100); } - p_ni_frame = - &test_frame_list.ni_test_frame[test_frame_list.head].data.frame; - // set up encoder p_config, using some hard coded numbers - if (ni_encoder_init_default_params(&api_param, 30, 1, 200000, - arg_width, arg_height, - enc_ctx.codec_format) < 0) - { - fprintf(stderr, "Error: encoder init default set up error\n"); - return -1; - } - - // check and set ni_encoder_params from --xcoder-params - if (retrieve_xcoder_params(encConfXcoderParams, &api_param, - &enc_ctx)) - { - fprintf(stderr, "Error: encoder p_config parsing error\n"); - return -1; - } - - ni_hrd_params_t hrd_params; - int video_full_range_flag = 0; - if (api_param.video_full_range_flag >= 0) - { - ni_log(NI_LOG_DEBUG, "Using user-configured video_full_range_flag " - "%d\n", - api_param.video_full_range_flag); - video_full_range_flag = api_param.video_full_range_flag; - } - - //always HWframe mode if preceeded by HWUPLOAD - enc_ctx.hw_action = NI_CODEC_HW_ENABLE; - api_param.hwframes = 1; - //to determine if from same device and buffer dimensions in memory - //needs to be done where input frame is available to check - p_hwframe = (niFrameSurface1_t *)p_ni_frame->p_data[3]; - enc_ctx.sender_handle = - (ni_device_handle_t)(int64_t)p_hwframe->device_handle; - api_param.rootBufId = p_hwframe->ui16FrameIdx; - - // for encode from YUV, use all the parameters specified by user - if (0 != - (ret = encoder_open_session( - &enc_ctx, dst_codec_format, iXcoderGUID, &api_param, bit_depth, - arg_width, arg_height, &hrd_params, api_param.color_primaries, - api_param.color_transfer_characteristic, api_param.color_space, - video_full_range_flag, api_param.sar_num, api_param.sar_denom, - 1))) + if (!g_end_of_all_threads) { - goto end; - } - - // init and create encoding thread - enc_send_param.p_enc_ctx = &enc_ctx; - enc_send_param.p_in_frame = NULL; - enc_send_param.input_video_width = input_video_width; - enc_send_param.input_video_height = input_video_height; - enc_send_param.pfs = pfs; - enc_send_param.p_total_bytes_sent = &total_bytes_sent; - enc_send_param.p_xcodeState = &xcodeState; - enc_send_param.mode = mode; - enc_send_param.test_frame_list = &test_frame_list; - enc_send_param.dec_codec_format = dec_ctx.codec_format; - enc_send_param.p_input_exhausted = &input_exhausted; - enc_send_param.p_hwframe_pool_tracker = hwframe_pool_tracker; + p_ni_frame = &frame_list.frames[frame_list.head].data.frame; + p_hwframe = (niFrameSurface1_t *)p_ni_frame->p_data[3]; - enc_recv_param.p_enc_ctx = &enc_ctx; - enc_recv_param.p_out_packet = &out_packet; - enc_recv_param.output_video_width = output_video_width; - enc_recv_param.output_video_height = output_video_height; - enc_recv_param.p_file = p_file; - enc_recv_param.p_total_bytes_received = &total_bytes_received; - enc_recv_param.p_xcodeState = &xcodeState; - enc_recv_param.mode = mode; - enc_recv_param.p_hwframe_pool_tracker = hwframe_pool_tracker; + ret = encoder_open(&enc_ctx_list[0], p_enc_api_param_list, + output_total, &encConfXcoderParamsList[0], + &encConfXcoderGopList[0], + NULL, arg_width, arg_height, fps_num, + fps_den, bitrate, dst_codec_format, pix_fmt, + 0, iXcoderGUID, p_hwframe, multi_thread, + &enc_rate_emu_list[0], false); + if (ret != 0) + { + goto end; + } - if (ni_pthread_create(&enc_send_tid, NULL, encoder_send_thread, - &enc_send_param)) - { - fprintf(stderr, - "Error: create encoder send thread failed in transcode " - "mode\n"); - return -1; - } - if (ni_pthread_create(&enc_recv_tid, NULL, encoder_receive_thread, - &enc_recv_param)) - { - fprintf(stderr, - "Error: create encoder recieve thread failed in " - "transcode mode\n"); - return -1; - } - ni_pthread_join(uploader_tid, NULL); - ni_pthread_join(enc_send_tid, NULL); - ni_pthread_join(enc_recv_tid, NULL); - (void)ni_gettimeofday(¤t_time, NULL); - drain_test_list(&enc_send_param, &test_frame_list); - for (i = 0; i < NI_MAX_BUFFERED_FRAME; i++) - { - ni_frame_buffer_free( - &(test_frame_list.ni_test_frame[i].data.frame)); - } - } else - { - //open uploader - int pool_size = - 3; //3 starting buffers to be augmented with additional - // buffers by downstream entity like encoders - if (0 != - (ret = uploader_open_session(&upl_ctx, iXcoderGUID, bit_depth, - arg_width, arg_height, - 1 /*assume planar*/, pool_size))) - { - goto end; - } + // init and create encoding thread + enc_send_param.p_enc_ctx = &enc_ctx_list[0]; + enc_send_param.p_in_frame = NULL; + enc_send_param.input_video_width = input_video_width; + enc_send_param.input_video_height = input_video_height; + enc_send_param.pfs = pfs; + enc_send_param.yuv_buf = yuv_buf; + enc_send_param.output_total = output_total; + enc_send_param.p_total_bytes_sent = &total_bytes_sent; + enc_send_param.p_xcoder_state = &xcoder_state_list[0]; + enc_send_param.mode = mode; + enc_send_param.frame_list = &frame_list; + enc_send_param.dec_codec_format = dec_ctx.codec_format; + enc_send_param.sw_pix_fmt = NI_SW_PIX_FMT_NONE; + enc_send_param.p_rate_emu = &enc_rate_emu_list[0]; + + enc_recv_param.p_enc_ctx = &enc_ctx_list[0]; + enc_recv_param.p_out_packet = &out_packet; + enc_recv_param.output_video_width = output_video_width; + enc_recv_param.output_video_height = output_video_height; + enc_recv_param.p_file = &p_file_list[0]; + enc_recv_param.output_total = output_total; + enc_recv_param.p_number_of_packets = &number_of_packets_list[0]; + enc_recv_param.p_total_bytes_received = &total_bytes_received_list[0]; + enc_recv_param.p_xcoder_state = &xcoder_state_list[0]; + enc_recv_param.mode = mode; + + if (ni_pthread_create(&enc_send_tid, NULL, encoder_send_thread, + &enc_send_param)) + { + ni_log(NI_LOG_ERROR, + "Error: create encoder send thread failed in transcode " + "mode\n"); + return -1; + } + if (ni_pthread_create(&enc_recv_tid, NULL, encoder_receive_thread, + &enc_recv_param)) + { + ni_log(NI_LOG_ERROR, + "Error: create encoder recieve thread failed in " + "transcode mode\n"); + return -1; + } - //need to have the hwframe before open encoder - if (upload_send_data_get_desc(&upl_ctx, &swin_frame, &in_frame, - input_video_width, input_video_height, - pfs, total_file_size, - &total_bytes_sent, &input_exhausted)) - { - fprintf(stderr, "Error: upload frame error\n"); - return -1; + ni_pthread_join(enc_send_tid, NULL); + ni_pthread_join(enc_recv_tid, NULL); } + ni_pthread_join(uploader_tid, NULL); - // set up encoder p_config, using some hard coded numbers - if (ni_encoder_init_default_params(&api_param, 30, 1, 200000, - arg_width, arg_height, - enc_ctx.codec_format) < 0) - { - fprintf(stderr, "Error: encoder init default set up error\n"); - return -1; - } + (void)ni_gettimeofday(¤t_time, NULL); + + hwframe_list_release(&frame_list, pix_fmt); + } else + { + int read_from_file = 0; + ni_session_data_io_t *p_in_frame; - // check and set ni_encoder_params from --xcoder-params - if (retrieve_xcoder_params(encConfXcoderParams, &api_param, - &enc_ctx)) + p_hwframe = hwupload_frame(&upl_ctx, &sca_ctx, &swin_frame, + &in_frame, &scale_frame, pix_fmt, + input_video_width, input_video_height, + pfs, yuv_buf, &total_bytes_sent, &eos); + if (p_hwframe == NULL) { - fprintf(stderr, "Error: encoder p_config parsing error\n"); - return -1; + goto end; } - ni_hrd_params_t hrd_params; - int video_full_range_flag = 0; - if (api_param.video_full_range_flag >= 0) - { - ni_log(NI_LOG_DEBUG, "Using user-configured video_full_range_flag " - "%d\n", - api_param.video_full_range_flag); - video_full_range_flag = api_param.video_full_range_flag; - } - - //always HWframe mode if preceeded by HWUPLOAD - enc_ctx.hw_action = NI_CODEC_HW_ENABLE; - api_param.hwframes = 1; - //to determine if from same device and buffer dimensions in memory - //needs to be done where input frame is available to check - p_hwframe = (niFrameSurface1_t *)in_frame.data.frame.p_data[3]; - enc_ctx.sender_handle = - (ni_device_handle_t)(int64_t)p_hwframe->device_handle; - api_param.rootBufId = p_hwframe->ui16FrameIdx; - - // for encode from YUV, use all the parameters specified by user - if (0 != - (ret = encoder_open_session( - &enc_ctx, dst_codec_format, iXcoderGUID, &api_param, bit_depth, - arg_width, arg_height, &hrd_params, api_param.color_primaries, - api_param.color_transfer_characteristic, api_param.color_space, - video_full_range_flag, api_param.sar_num, api_param.sar_denom, - 1))) + ret = encoder_open(&enc_ctx_list[0], p_enc_api_param_list, + output_total, &encConfXcoderParamsList[0], &encConfXcoderGopList[0], + NULL, arg_width, arg_height, fps_num, + fps_den, bitrate, dst_codec_format, + is_ni_enc_pix_fmt(pix_fmt) ? pix_fmt : NI_PIX_FMT_YUV420P, + 0, iXcoderGUID, p_hwframe, multi_thread, + &enc_rate_emu_list[0], false); + if (ret != 0) { goto end; } - int read_from_file = 0; - int need_to_resend = 0; - unsigned int prev_num_pkt; - while (send_fin_flag == 0 || receive_fin_flag == 0) + + while (!end_of_all_streams && + (send_fin_flag == 0 || receive_fin_flag == 0)) { (void)ni_gettimeofday(¤t_time, NULL); - int print_time = - ((current_time.tv_sec - previous_time.tv_sec) > 1); + print_time = need_time_print(¤t_time, &previous_time); - if (read_from_file && !input_exhausted && need_to_resend == 0) + if (read_from_file && !eos) { - if (upload_send_data_get_desc( - &upl_ctx, &swin_frame, &in_frame, input_video_width, - input_video_height, pfs, total_file_size, - &total_bytes_sent, &input_exhausted)) + p_hwframe = hwupload_frame(&upl_ctx, &sca_ctx, &swin_frame, + &in_frame, &scale_frame, pix_fmt, + input_video_width, + input_video_height, pfs, yuv_buf, + &total_bytes_sent, &eos); + if (upl_ctx.status == NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL) { - if ((&upl_ctx)->status == - NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL) - { - ni_log( - NI_LOG_DEBUG, - "No space to write to, try to read a packet\n"); - goto receive_pkt; - } else - { - fprintf(stderr, "Error: upload frame error\n"); - return -1; - } + ni_log(NI_LOG_DEBUG, "No space to write to, try to " + "read a packet\n"); + p_in_frame = &in_frame; + goto receive_pkt; + } else if (p_hwframe == NULL) + { + ret = -1; + goto end; } } // Sending - send_fin_flag = encoder_send_data3( - &enc_ctx, &in_frame, sos_flag, input_video_width, - input_video_height, &xcodeState, input_exhausted, - &need_to_resend); - read_from_file = 1; //since first frame read before while-loop - - sos_flag = 0; - if (send_fin_flag == 2) //Error + p_in_frame = is_ni_enc_pix_fmt(pix_fmt) ? &in_frame : &scale_frame; + for (i = 0; i < output_total; i++) { - break; - } - //track in array with unique index, free when enc read finds - //this must be implemented in application space for complete - //tracking of hwframes - if (need_to_resend == 0) - { - //successful read means there is recycle to check - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *)in_frame.data.frame - .p_data[3])) - ->ui16FrameIdx; - memcpy(&hwframe_pool_tracker[current_hwframe_index], - (uint8_t *)in_frame.data.frame.p_data[3], - sizeof(niFrameSurface1_t)); + send_fin_flag = encoder_send_data3(&enc_ctx_list[i], + p_in_frame, + input_video_width, + input_video_height, + &xcoder_state_list[i], + eos); + read_from_file = 1; //since first frame read before while-loop + if (send_fin_flag < 0) //Error + { + ni_log(NI_LOG_ERROR, "enc %d send error, quit !\n", i); + ni_hw_frame_ref(p_hwframe); + end_of_all_streams = 1; + break; + } + //track in array with unique index, free when enc read finds + //this must be implemented in application space for complete + //tracking of hwframes + if (!xcoder_state_list[i].enc_resend) + { + //successful read means there is recycle to check + ni_hw_frame_ref(p_hwframe); + } else + { + ni_log(NI_LOG_DEBUG, "enc %d need to re-send !\n", i); + ni_usleep(500); + i--; + continue; + } } + if (end_of_all_streams) + break; receive_pkt: - // Receiving - prev_num_pkt = number_of_packets; - receive_fin_flag = encoder_receive_data( - &enc_ctx, &out_packet, output_video_width, - output_video_height, p_file, &total_bytes_received, - print_time, &in_frame); // in_frame is passed in for future sequence change support (XCODER_APP_HWUP_ENCODE does not support sequence change yet) - recycle_index = out_packet.data.packet.recycle_index; - if (prev_num_pkt < number_of_packets && enc_ctx.hw_action && - recycle_index > 0 && - recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx.ddr_config)) - //encoder only returns valid recycle index - //when there's something to recycle. - //This range is suitable for all memory bins + receive_fin_flag = encoder_receive(&enc_ctx_list[0], + p_in_frame, &out_packet, + output_video_width, + output_video_height, + &number_of_packets_list[0], + output_total, &p_file_list[0], + &total_bytes_received_list[0], + print_time, + &xcoder_state_list[0]); + for (i = 0; receive_fin_flag >= 0 && i < output_total; i++) { - if (hwframe_pool_tracker[recycle_index].ui16FrameIdx) + if (!xcoder_state_list[i].enc_eos_received) { - ni_hwframe_buffer_recycle( - &hwframe_pool_tracker[recycle_index], - hwframe_pool_tracker[recycle_index].device_handle); - //zero for tracking purposes - hwframe_pool_tracker[recycle_index].ui16FrameIdx = 0; - } - } - if (enc_ctx.codec_format == NI_CODEC_FORMAT_AV1) - { - if (!out_packet.data.packet.av1_show_frame && - number_of_packets >= 2) + ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i); + end_of_all_streams = 0; + break; + } else { - ni_log(NI_LOG_DEBUG, "AV1 got not shown frames\n"); - number_of_packets -= 1; - goto receive_pkt; + ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i); + end_of_all_streams = 1; } } + if (print_time) { previous_time = current_time; } + } // encoder send/receive while loop + } // encoder send/receive single thread mode - // Error or eos - if (receive_fin_flag < 0 || - out_packet.data.packet.end_of_stream) - { - break; - } - } - } - int timeDiff = (int)(current_time.tv_sec - start_time.tv_sec); - if (timeDiff == 0) - timeDiff = 1; - printf("[R] Got: Packets= %u fps=%f Total bytes %llu\n", - number_of_packets, - ((float)number_of_packets) / ((float)timeDiff), - total_bytes_received); + encoder_stat_report_and_close(&enc_ctx_list[0], output_total, + &number_of_packets_list[0], + &total_bytes_received_list[0]); - num_post_recycled = scan_and_clean_hwdescriptors(hwframe_pool_tracker); - ni_log(NI_LOG_DEBUG, "Cleanup recycled %d internal buffers\n", - num_post_recycled); - ni_device_session_close(&enc_ctx, 1, NI_DEVICE_TYPE_ENCODER); ni_device_session_close(&upl_ctx, 1, NI_DEVICE_TYPE_UPLOAD); + if (!is_ni_enc_pix_fmt(pix_fmt)) + { //Uploading rgba requires scaler conversion so close the session too + ni_device_session_close(&sca_ctx, 1, NI_DEVICE_TYPE_SCALER); + } ni_rsrc_free_device_context(sdPara.p_enc_rsrc_ctx); rcPara.p_enc_rsrc_ctx = NULL; sdPara.p_enc_rsrc_ctx = NULL; rcPara.p_upl_rsrc_ctx = NULL; sdPara.p_upl_rsrc_ctx = NULL; - ni_frame_buffer_free(&(in_frame.data.frame)); - ni_frame_buffer_free(&(swin_frame.data.frame)); + ni_frame_buffer_free(&in_frame.data.frame); + ni_frame_buffer_free(&swin_frame.data.frame); ni_packet_buffer_free(&(out_packet.data.packet)); } else if (mode == XCODER_APP_FILTER) { #ifndef _WIN32 // not support on windows - printf("Scaling Mode\n"); + ni_log(NI_LOG_INFO, "Scaling Mode\n"); // default filter params ni_filter_params_t filter_params = {0}; filter_params.scale_width = 1280; filter_params.scale_height = 720; filter_params.format = GC620_I420; - if (0 != - (ret = retrieve_filter_params(scaConfXcoderParams, &filter_params))) + ret = retrieve_filter_params(scaConfXcoderParams, &filter_params); + if (ret != 0) { return -1; } - int is_p2p = filter_params.p2p; + int scale_width = filter_params.scale_width; int scale_height = filter_params.scale_height; int out_format = filter_params.format; - if (is_p2p) + if (filter_params.p2p) { sca_ctx.isP2P = 1; if (out_format != GC620_I420) @@ -8110,55 +9364,47 @@ int main(int argc, char *argv[]) ovly_ctx.isP2P = 1; } - niFrameSurface1_t dec_hwframe_tracker = {0}; - niFrameSurface1_t scaler_hwframe_tracker = {0}; - niFrameSurface1_t drawbox_hwframe_tracker = {0}; - disp_buffer_t *disp1 = NULL; - disp_buffer_t *disp2 = NULL; - if (is_p2p) + disp_buffer_t *disp_buf[2] = { NULL }; + if (filter_params.p2p) { - disp1 = calloc(1, sizeof(disp_buffer_t)); - disp2 = calloc(1, sizeof(disp_buffer_t)); + for (i = 0; i < sizeof(disp_buf)/sizeof(disp_buffer_t *); i++) + { + disp_buf[i] = calloc(1, sizeof(disp_buffer_t)); + } } ni_session_data_io_t in_pkt = {0}; ni_session_data_io_t out_frame = {0}; FILE *p_ovly_out = NULL; - if (p_file) + + if (p_file_list[0]) { - char *ovly_outfile; - char *p = strtok(rcPara.fileName, "."); - if (!p) + char ovly_file[FILE_NAME_LEN] = {0}; + strcat(ovly_file, "overlay_"); + strcat(ovly_file, rcPara.fileName); + ni_log(NI_LOG_INFO, "overlay output filename %s\n", ovly_file); + p_ovly_out = fopen(ovly_file, "wb"); + if (!p_ovly_out) { - ovly_outfile = strcat(rcPara.fileName, "_overlay"); - } - while (p) - { - char *name = (char *)malloc(strlen(p)); - strcpy(name, p); - strcat(name, "_overlay."); - p = strtok(NULL, "."); - ovly_outfile = strcat(name, p); - break; + ni_log(NI_LOG_ERROR, "Error: cannot open %s\n", ovly_file); + goto end; } - printf("overlay output filename %s\n", ovly_outfile); - p_ovly_out = fopen(ovly_outfile, "wb"); } while (send_fin_flag == 0 || receive_fin_flag == 0) { (void)ni_gettimeofday(¤t_time, NULL); - int print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1); + print_time = need_time_print(¤t_time, &previous_time); // Sending - send_fin_flag = decoder_send_data( - &dec_ctx, &in_pkt, sos_flag, input_video_width, - input_video_height, pkt_size, total_file_size, - &total_bytes_sent, print_time, &xcodeState, &SPS); - sos_flag = 0; + send_fin_flag = decoder_send_data(&dec_ctx, &in_pkt, + input_video_width, + input_video_height, pkt_size, + &total_bytes_sent, print_time, + &xcoder_state, &SPS); if (send_fin_flag < 0) { - fprintf(stderr, "Error: decoder_send_data() failed, rc: %d\n", + ni_log(NI_LOG_ERROR, "Error: decoder_send_data() failed, rc: %d\n", send_fin_flag); break; } @@ -8166,8 +9412,8 @@ int main(int argc, char *argv[]) // Receiving receive_fin_flag = decoder_receive_data( &dec_ctx, &out_frame, output_video_width, output_video_height, - p_file, &total_bytes_received, print_time, 0, - &xcodeState); // not write to file + p_file_list[0], &total_bytes_received, print_time, 0, + &xcoder_state, &rx_size); // not write to file if (print_time) { previous_time = current_time; @@ -8180,83 +9426,55 @@ int main(int argc, char *argv[]) } else if (receive_fin_flag != 2) { // got yuv hwframe from decoder. save dec hwframe idx - memcpy(&dec_hwframe_tracker, - (uint8_t *)out_frame.data.frame.p_data[3], - sizeof(niFrameSurface1_t)); - niFrameSurface1_t *decoded_surface = - (niFrameSurface1_t *)(out_frame.data.frame.p_data[3]); - - // set decoded frame params - decoded_surface->ui16width = output_video_width; - decoded_surface->ui16height = output_video_height; - decoded_surface->bit_depth = 1; - decoded_surface->encoding_type = NI_PIXEL_PLANAR_FORMAT_PLANAR; + p_hwframe = (niFrameSurface1_t *)out_frame.data.frame.p_data[3]; + ni_hw_frame_ref(p_hwframe); + + // set decoded hwframe descriptor + p_hwframe->ui16width = output_video_width; + p_hwframe->ui16height = output_video_height; + p_hwframe->bit_depth = 1; + p_hwframe->encoding_type = NI_PIXEL_PLANAR_FORMAT_PLANAR; // scale the decoded frame(always yuv) and write to output file ni_session_data_io_t scale_session_data = {0}; - ret = scale_filter(&sca_ctx, &(out_frame.data.frame), - &scale_session_data, scale_width, - scale_height, out_format); + ret = scale_filter(&sca_ctx, &out_frame.data.frame, + &scale_session_data, iXcoderGUID,scale_width, + scale_height, GC620_I420, out_format); if (ret != 0) break; - // Save scaler HwFrameIdx - memcpy(&scaler_hwframe_tracker, - (uint8_t *)(scale_session_data.data.frame.p_data[3]), - sizeof(niFrameSurface1_t)); + ret = scaler_output_write(&sca_ctx, &scale_session_data, scale_width, scale_height, out_format, - p_file, disp1); + p_file_list[0], disp_buf[0]); if (ret != 0) break; - if (scaler_hwframe_tracker.ui16FrameIdx) - { - ni_hwframe_buffer_recycle( - &scaler_hwframe_tracker, - scaler_hwframe_tracker.device_handle); - scaler_hwframe_tracker.ui16FrameIdx = 0; - } // draw box on the decoded frame and write to output file ni_session_data_io_t drawbox_session_data = {0}; ret = drawbox_filter(&crop_ctx, &pad_ctx, &ovly_ctx, &fmt_ctx, - &(out_frame.data.frame), - &drawbox_session_data, NULL, out_format); + &out_frame.data.frame, + &drawbox_session_data, NULL, iXcoderGUID, + GC620_I420, out_format); if (ret != 0) break; - // Save drawbox HwFrameIdx - memcpy(&drawbox_hwframe_tracker, - (uint8_t *)(drawbox_session_data.data.frame.p_data[3]), - sizeof(niFrameSurface1_t)); + if (out_format == GC620_I420) ret = scaler_output_write( &ovly_ctx, &drawbox_session_data, output_video_width, - output_video_height, out_format, p_ovly_out, disp2); + output_video_height, out_format, p_ovly_out, disp_buf[1]); else ret = scaler_output_write( &fmt_ctx, &drawbox_session_data, output_video_width, - output_video_height, out_format, p_ovly_out, disp2); + output_video_height, out_format, p_ovly_out, disp_buf[1]); if (ret != 0) break; - if (drawbox_hwframe_tracker.ui16FrameIdx) - { - ni_hwframe_buffer_recycle( - &drawbox_hwframe_tracker, - drawbox_hwframe_tracker.device_handle); - drawbox_hwframe_tracker.ui16FrameIdx = 0; - } // free decoded hw frame - if (dec_hwframe_tracker.ui16FrameIdx) - { - ni_hwframe_buffer_recycle( - &dec_hwframe_tracker, - dec_hwframe_tracker.device_handle); - dec_hwframe_tracker.ui16FrameIdx = 0; - } + ni_hw_frame_unref(p_hwframe->ui16FrameIdx); // free decoded frame and scaler output frame - ni_frame_buffer_free(&(out_frame.data.frame)); - ni_frame_buffer_free(&(scale_session_data.data.frame)); - ni_frame_buffer_free(&(drawbox_session_data.data.frame)); + ni_frame_buffer_free(&out_frame.data.frame); + ni_frame_buffer_free(&scale_session_data.data.frame); + ni_frame_buffer_free(&drawbox_session_data.data.frame); } else { @@ -8264,47 +9482,26 @@ int main(int argc, char *argv[]) } } - unsigned int time_diff = - (unsigned int)(current_time.tv_sec - start_time.tv_sec); - if (time_diff == 0) - time_diff = 1; - - printf("[R] Got: Frames= %u fps=%f Total bytes %llu\n", - number_of_frames, ((float)number_of_frames / (float)time_diff), - total_bytes_received); + decoder_stat_report_and_close(&dec_ctx, total_bytes_received); // close device - if (is_p2p) + if (filter_params.p2p) { - if (disp1) - { - if (disp1->fd >= 0) - { - if (disp1->mmap_data != MAP_FAILED) - { - munmap((void *)disp1->mmap_data, disp1->len); - } - close(disp1->fd); - free(disp1->data); - } - free(disp1); - } - if (disp2) + for (i = 0; i < sizeof(disp_buf)/sizeof(disp_buffer_t *); i++) { - if (disp2->fd >= 0) + if (disp_buf[i]->fd >= 0) { - if (disp2->mmap_data != MAP_FAILED) + if (disp_buf[i]->mmap_data != MAP_FAILED) { - munmap((void *)disp2->mmap_data, disp2->len); + munmap((void *)disp_buf[i]->mmap_data,disp_buf[i]->len); } - close(disp2->fd); - free(disp2->data); + close(disp_buf[i]->fd); + free(disp_buf[i]->data); } - free(disp2); + free(disp_buf[i]); } } - ni_device_session_close(&dec_ctx, 1, NI_DEVICE_TYPE_DECODER); ni_device_session_close(&sca_ctx, 1, NI_DEVICE_TYPE_SCALER); ni_device_session_close(&crop_ctx, 1, NI_DEVICE_TYPE_SCALER); ni_device_session_close(&pad_ctx, 1, NI_DEVICE_TYPE_SCALER); @@ -8330,44 +9527,35 @@ int main(int argc, char *argv[]) sdPara.p_ovly_rsrc_ctx = NULL; sdPara.p_fmt_rsrc_ctx = NULL; - // Recycle hwframe - if (dec_hwframe_tracker.ui16FrameIdx) - ni_hwframe_buffer_recycle(&dec_hwframe_tracker, - dec_hwframe_tracker.device_handle); - - if (scaler_hwframe_tracker.ui16FrameIdx) - ni_hwframe_buffer_recycle(&scaler_hwframe_tracker, - scaler_hwframe_tracker.device_handle); - - if (drawbox_hwframe_tracker.ui16FrameIdx) - ni_hwframe_buffer_recycle(&drawbox_hwframe_tracker, - drawbox_hwframe_tracker.device_handle); - - ni_packet_buffer_free(&(in_pkt.data.packet)); - ni_frame_buffer_free(&(out_frame.data.frame)); + scan_and_clean_hwdescriptors(); + ni_packet_buffer_free(&in_pkt.data.packet); + ni_frame_buffer_free(&out_frame.data.frame); #endif - } else if (mode == XCODER_APP_TRANSCODE) { - printf("Xcoding Mode: %dx%d to %dx%d\n", input_video_width, - input_video_height, output_video_width, output_video_height); - ni_session_data_io_t in_pkt = {0}; ni_session_data_io_t out_frame = {0}; ni_session_data_io_t enc_in_frame = {0}; ni_session_data_io_t out_packet = {0}; - uint32_t prev_num_pkt; ni_frame_t *p_ni_frame = NULL; void *p_stream_info = NULL; + + ni_log(NI_LOG_INFO, "Xcoding Mode: %dx%d to %dx%d\n", input_video_width, + input_video_height, output_video_width, output_video_height); + if (src_codec_format == NI_CODEC_FORMAT_H264) p_stream_info = &SPS; else if (src_codec_format == NI_CODEC_FORMAT_H265) p_stream_info = &HEVC_SPS; + else if (src_codec_format == NI_CODEC_FORMAT_VP9) + { + p_stream_info = &VP9_INFO; + fps_num = VP9_INFO.timebase.den; + fps_den = VP9_INFO.timebase.num; + } if (multi_thread) { - ni_test_frame_list_t test_frame_list = {0}; - ni_pthread_t dec_send_tid, dec_recv_tid; dec_send_param_t dec_send_param = {0}; dec_recv_param_t dec_recv_param = {0}; @@ -8384,22 +9572,22 @@ int main(int argc, char *argv[]) dec_send_param.pkt_size = pkt_size; dec_send_param.print_time = 0; // not support now dec_send_param.p_total_bytes_sent = &total_bytes_sent; - dec_send_param.p_xcodeState = &xcodeState; + dec_send_param.p_xcoder_state = &xcoder_state; dec_send_param.p_stream_info = p_stream_info; dec_recv_param.p_dec_ctx = &dec_ctx; dec_recv_param.p_out_frame = NULL; dec_recv_param.output_video_width = output_video_width; dec_recv_param.output_video_height = output_video_height; - dec_recv_param.p_file = p_file; + dec_recv_param.p_file = p_file_list[0]; dec_recv_param.p_total_bytes_received = &total_bytes_received; - dec_recv_param.p_xcodeState = &xcodeState; + dec_recv_param.p_xcoder_state = &xcoder_state; dec_recv_param.mode = mode; - dec_recv_param.test_frame_list = &test_frame_list; + dec_recv_param.frame_list = &frame_list; if (ni_pthread_create(&dec_send_tid, NULL, decoder_send_thread, &dec_send_param)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: create decoder send thread failed in transcode " "mode\n"); return -1; @@ -8407,217 +9595,111 @@ int main(int argc, char *argv[]) if (ni_pthread_create(&dec_recv_tid, NULL, decoder_receive_thread, &dec_recv_param)) { - fprintf(stderr, + ni_log(NI_LOG_ERROR, "Error: create decoder receive thread failed in " "transcode mode\n"); return -1; } - // wait until received first decoded frame - while (test_frames_isempty(&test_frame_list)) + // polling the first received decoded frame + while (frame_list_is_empty(&frame_list) && !g_end_of_all_threads) { ni_usleep(100); } - p_ni_frame = - &test_frame_list.ni_test_frame[test_frame_list.head].data.frame; - // open the encode session when the first frame arrives and the session - // is not opened yet, with the source stream and user-configured encode - // info both considered when constructing VUI in the stream headers - int color_pri = p_ni_frame->color_primaries; - int color_trc = p_ni_frame->color_trc; - int color_space = p_ni_frame->color_space; - int video_full_range_flag = p_ni_frame->video_full_range_flag; - int sar_num = p_ni_frame->sar_width; - int sar_den = p_ni_frame->sar_height; - int fps_num = 0, fps_den = 0; - - // calculate the source fps and set it as the default target fps, based - // on the timing_info passed in from the decoded frame - if (p_ni_frame->vui_num_units_in_tick && p_ni_frame->vui_time_scale) - { - if (NI_CODEC_FORMAT_H264 == p_ni_frame->src_codec) - { - if (0 == (p_ni_frame->vui_time_scale % 2)) - { - fps_num = (int)(p_ni_frame->vui_time_scale / 2); - fps_den = (int)(p_ni_frame->vui_num_units_in_tick); - } else - { - fps_num = (int)(p_ni_frame->vui_time_scale); - fps_den = (int)(2 * p_ni_frame->vui_num_units_in_tick); - } - } else if (NI_CODEC_FORMAT_H265 == p_ni_frame->src_codec) + if (!g_end_of_all_threads) + { + p_ni_frame = &frame_list.frames[frame_list.head].data.frame; + p_hwframe = dec_ctx.hw_action == NI_CODEC_HW_ENABLE ? + (niFrameSurface1_t *)p_ni_frame->p_data[3] : NULL; + + ret = encoder_open(&enc_ctx_list[0], p_enc_api_param_list, + output_total, &encConfXcoderParamsList[0], + &encConfXcoderGopList[0], + p_ni_frame, arg_width, arg_height, fps_num, + fps_den, bitrate, dst_codec_format, + dec_ctx.pixel_format, + p_ni_frame->aspect_ratio_idc, iXcoderGUID, + p_hwframe, multi_thread, + &enc_rate_emu_list[0], false); + if (ret != 0) { - fps_num = p_ni_frame->vui_time_scale; - fps_den = p_ni_frame->vui_num_units_in_tick; + goto end; } - } - - // set up encoder p_config, using some info from source - if (ni_encoder_init_default_params(&api_param, fps_num, fps_den, - 200000, arg_width, arg_height, - enc_ctx.codec_format) < 0) - { - fprintf(stderr, "Error: encoder init default set up error\n"); - return -1; - } - - // check and set ni_encoder_params from --xcoder-params - // Note: the parameter setting has to be in this order so that user - // configured values can overwrite the source/default ones if - // desired. - if (retrieve_xcoder_params(encConfXcoderParams, &api_param, - &enc_ctx)) - { - fprintf(stderr, "Error: encoder p_config parsing error\n"); - return -1; - } - - if (color_pri != api_param.color_primaries && - NI_COL_PRI_UNSPECIFIED != api_param.color_primaries) - { - ni_log(NI_LOG_DEBUG, "Using user-configured color primaries %d to " - "overwrite source %d\n", - api_param.color_primaries, color_pri); - color_pri = api_param.color_primaries; - } - if (color_trc != api_param.color_transfer_characteristic && - NI_COL_TRC_UNSPECIFIED != - api_param.color_transfer_characteristic) - { - ni_log(NI_LOG_DEBUG, "Using user-configured color trc %d to overwrite" - " source %d\n", - api_param.color_transfer_characteristic, - color_trc); - color_trc = api_param.color_transfer_characteristic; - } - if (color_space != api_param.color_space && - NI_COL_SPC_UNSPECIFIED != api_param.color_space) - { - ni_log(NI_LOG_DEBUG, "Using user-configured color space %d to " - "overwrite source %d\n", - api_param.color_space, color_space); - color_space = api_param.color_space; - } - if (api_param.video_full_range_flag >= 0) - { - ni_log(NI_LOG_DEBUG, "Using user-configured video_full_range_flag " - "%d\n", - api_param.video_full_range_flag); - video_full_range_flag = api_param.video_full_range_flag; - } - if (p_ni_frame->aspect_ratio_idc > 0 && - p_ni_frame->aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO) - { - sar_num = - ni_h264_pixel_aspect_list[p_ni_frame->aspect_ratio_idc].num; - sar_den = - ni_h264_pixel_aspect_list[p_ni_frame->aspect_ratio_idc].den; - } else if (api_param.sar_denom) - { - sar_num = api_param.sar_num; - sar_den = api_param.sar_denom; - } - - ni_hrd_params_t hrd_params; - if (!dec_ctx.hw_action) - { - enc_ctx.hw_action = NI_CODEC_HW_NONE; - } else - { - //Items in this else condition could be improved by being handled in libxcoder - enc_ctx.hw_action = NI_CODEC_HW_ENABLE; - api_param.hwframes = 1; - //to determine if from same device and buffer dimensions in memory - //needs to be done where input frame is available to check - p_hwframe = (niFrameSurface1_t *)p_ni_frame->p_data[3]; - enc_ctx.sender_handle = - (ni_device_handle_t)(int64_t)p_hwframe->device_handle; - api_param.rootBufId = p_hwframe->ui16FrameIdx; - } - - if (0 != - (ret = encoder_open_session( - &enc_ctx, dst_codec_format, iXcoderGUID, &api_param, - bit_depth, arg_width, arg_height, &hrd_params, color_pri, - color_trc, color_space, video_full_range_flag, sar_num, - sar_den, 1))) - { - ni_log(NI_LOG_ERROR, "Error: encoder_open_session failed, stop!\n"); - goto end; - } - - // init and create encoding thread - enc_send_param.p_enc_ctx = &enc_ctx; - enc_send_param.p_in_frame = &enc_in_frame; - enc_send_param.input_video_width = input_video_width; - enc_send_param.input_video_height = input_video_height; - enc_send_param.pfs = pfs; - enc_send_param.p_total_bytes_sent = &total_bytes_sent; - enc_send_param.p_xcodeState = &xcodeState; - enc_send_param.mode = mode; - enc_send_param.test_frame_list = &test_frame_list; - enc_send_param.dec_codec_format = dec_ctx.codec_format; - enc_send_param.p_input_exhausted = NULL; // not use heres - enc_send_param.p_hwframe_pool_tracker = hwframe_pool_tracker; - enc_recv_param.p_enc_ctx = &enc_ctx; - enc_recv_param.p_out_packet = &out_packet; - enc_recv_param.output_video_width = output_video_width; - enc_recv_param.output_video_height = output_video_height; - enc_recv_param.p_file = p_file; - enc_recv_param.p_total_bytes_received = &xcodeRecvTotal; - enc_recv_param.p_xcodeState = &xcodeState; - enc_recv_param.mode = mode; - enc_recv_param.p_hwframe_pool_tracker = hwframe_pool_tracker; + // init and create encoding thread + enc_send_param.p_enc_ctx = &enc_ctx_list[0]; + enc_send_param.p_in_frame = &enc_in_frame; + enc_send_param.input_video_width = input_video_width; + enc_send_param.input_video_height = input_video_height; + enc_send_param.pfs = pfs; + enc_send_param.yuv_buf = yuv_buf; + enc_send_param.output_total = output_total; + enc_send_param.p_total_bytes_sent = &total_bytes_sent; + enc_send_param.p_xcoder_state = &xcoder_state_list[0]; + enc_send_param.mode = mode; + enc_send_param.frame_list = &frame_list; + enc_send_param.dec_codec_format = dec_ctx.codec_format; + enc_send_param.sw_pix_fmt = NI_SW_PIX_FMT_NONE; + enc_send_param.p_rate_emu = &enc_rate_emu_list[0]; + + enc_recv_param.p_enc_ctx = &enc_ctx_list[0]; + enc_recv_param.p_out_packet = &out_packet; + enc_recv_param.output_video_width = output_video_width; + enc_recv_param.output_video_height = output_video_height; + enc_recv_param.p_file = &p_file_list[0]; + enc_recv_param.output_total = output_total; + enc_recv_param.p_number_of_packets = &number_of_packets_list[0]; + enc_recv_param.p_total_bytes_received = &total_bytes_received_list[0]; + enc_recv_param.p_xcoder_state = &xcoder_state_list[0]; + enc_recv_param.mode = mode; + + if (ni_pthread_create(&enc_send_tid, NULL, encoder_send_thread, + &enc_send_param)) + { + ni_log(NI_LOG_ERROR, "Error: create encoder send thread failed " + "in transcode mode\n"); + return -1; + } + if (ni_pthread_create(&enc_recv_tid, NULL, encoder_receive_thread, + &enc_recv_param)) + { + ni_log(NI_LOG_ERROR, "Error: create encoder recieve thread " + "failed in transcode mode\n"); + return -1; + } - if (ni_pthread_create(&enc_send_tid, NULL, encoder_send_thread, - &enc_send_param)) - { - fprintf(stderr, - "Error: create encoder send thread failed in transcode " - "mode\n"); - return -1; - } - if (ni_pthread_create(&enc_recv_tid, NULL, encoder_receive_thread, - &enc_recv_param)) - { - fprintf(stderr, - "Error: create encoder recieve thread failed in " - "transcode mode\n"); - return -1; + ni_pthread_join(enc_send_tid, NULL); + ni_pthread_join(enc_recv_tid, NULL); } ni_pthread_join(dec_send_tid, NULL); ni_pthread_join(dec_recv_tid, NULL); - ni_pthread_join(enc_send_tid, NULL); - ni_pthread_join(enc_recv_tid, NULL); + (void)ni_gettimeofday(¤t_time, NULL); - drain_test_list(&enc_send_param, &test_frame_list); - for (i = 0; i < NI_MAX_BUFFERED_FRAME; i++) - { - ni_frame_buffer_free( - &(test_frame_list.ni_test_frame[i].data.frame)); - } + + hwframe_list_release(&frame_list, pix_fmt); } else { - int need_to_resend = 0; - while (send_fin_flag == 0 || receive_fin_flag == 0) + int encoder_opened = 0; + + while (!end_of_all_streams && + (send_fin_flag == 0 || receive_fin_flag == 0)) { (void)ni_gettimeofday(¤t_time, NULL); - int print_time = - ((current_time.tv_sec - previous_time.tv_sec) > 1); + print_time = need_time_print(¤t_time, &previous_time); + if (print_time) + { + previous_time = current_time; + } - if (need_to_resend) - goto encode_send; // bitstream Sending - send_fin_flag = decoder_send_data( - &dec_ctx, &in_pkt, sos_flag, input_video_width, - input_video_height, pkt_size, total_file_size, - &total_bytes_sent, print_time, &xcodeState, p_stream_info); - - sos_flag = 0; - if (send_fin_flag == 2) //Error + decode_send: + send_fin_flag = decoder_send_data(&dec_ctx, &in_pkt, + input_video_width, + input_video_height, pkt_size, + &total_bytes_sent, print_time, + &xcoder_state, p_stream_info); + if (send_fin_flag < 0) { break; } @@ -8625,15 +9707,10 @@ int main(int argc, char *argv[]) // YUV Receiving: not writing to file receive_fin_flag = decoder_receive_data( &dec_ctx, &out_frame, output_video_width, - output_video_height, p_file, &total_bytes_received, - print_time, 0, &xcodeState); - - if (print_time) - { - previous_time = current_time; - } + output_video_height, p_file_list[0], &total_bytes_received, + print_time, 0, &xcoder_state, &rx_size); - if (2 == receive_fin_flag) + if (receive_fin_flag == NI_TEST_RETCODE_EAGAIN) { ni_log(NI_LOG_DEBUG, "no decoder output, jump to encoder receive!\n"); @@ -8644,270 +9721,120 @@ int main(int argc, char *argv[]) { ni_frame_buffer_free(&(out_frame.data.frame)); } - goto encode_recv; - } else if (NI_INVALID_SESSION_ID == enc_ctx.session_id || - NI_INVALID_DEVICE_HANDLE == enc_ctx.blk_io_handle) - { - // open the encode session when the first frame arrives and the session - // is not opened yet, with the source stream and user-configured encode - // info both considered when constructing VUI in the stream headers - int color_pri = out_frame.data.frame.color_primaries; - int color_trc = out_frame.data.frame.color_trc; - int color_space = out_frame.data.frame.color_space; - int video_full_range_flag = - out_frame.data.frame.video_full_range_flag; - int sar_num = out_frame.data.frame.sar_width; - int sar_den = out_frame.data.frame.sar_height; - int fps_num = 0, fps_den = 0; - - // calculate the source fps and set it as the default target fps, based - // on the timing_info passed in from the decoded frame - if (out_frame.data.frame.vui_num_units_in_tick && - out_frame.data.frame.vui_time_scale) - { - if (NI_CODEC_FORMAT_H264 == - out_frame.data.frame.src_codec) - { - if (0 == (out_frame.data.frame.vui_time_scale % 2)) - { - fps_num = - (int)(out_frame.data.frame.vui_time_scale / - 2); - fps_den = (int)(out_frame.data.frame - .vui_num_units_in_tick); - } else - { - fps_num = - (int)(out_frame.data.frame.vui_time_scale); - fps_den = (int)(2 * - out_frame.data.frame - .vui_num_units_in_tick); - } - } else if (NI_CODEC_FORMAT_H265 == - out_frame.data.frame.src_codec) - { - fps_num = out_frame.data.frame.vui_time_scale; - fps_den = - out_frame.data.frame.vui_num_units_in_tick; - } - } - - // set up encoder p_config, using some info from source - if (ni_encoder_init_default_params( - &api_param, fps_num, fps_den, 200000, arg_width, - arg_height, enc_ctx.codec_format) < 0) - { - fprintf(stderr, - "Error: encoder init default set up error\n"); - break; - } - - // check and set ni_encoder_params from --xcoder-params - // Note: the parameter setting has to be in this order so that user - // configured values can overwrite the source/default ones if - // desired. - if (retrieve_xcoder_params(encConfXcoderParams, &api_param, - &enc_ctx)) - { - fprintf(stderr, - "Error: encoder p_config parsing error\n"); - break; - } - - if (color_pri != api_param.color_primaries && - NI_COL_PRI_UNSPECIFIED != api_param.color_primaries) - { - ni_log(NI_LOG_DEBUG, - "Using user-configured color primaries %d to " - "overwrite source %d\n", - api_param.color_primaries, color_pri); - color_pri = api_param.color_primaries; - } - if (color_trc != api_param.color_transfer_characteristic && - NI_COL_TRC_UNSPECIFIED != - api_param.color_transfer_characteristic) - { - ni_log(NI_LOG_DEBUG, - "Using user-configured color trc %d to overwrite" - " source %d\n", - api_param.color_transfer_characteristic, color_trc); - color_trc = api_param.color_transfer_characteristic; - } - if (color_space != api_param.color_space && - NI_COL_SPC_UNSPECIFIED != api_param.color_space) - { - ni_log(NI_LOG_DEBUG, - "Using user-configured color space %d to " - "overwrite source %d\n", - api_param.color_space, color_space); - color_space = api_param.color_space; - } - if (api_param.video_full_range_flag >= 0) - { - ni_log(NI_LOG_DEBUG, - "Using user-configured video_full_range_flag " - "%d\n", - api_param.video_full_range_flag); - video_full_range_flag = api_param.video_full_range_flag; - } - if (out_frame.data.frame.aspect_ratio_idc > 0 && - out_frame.data.frame.aspect_ratio_idc < - NI_NUM_PIXEL_ASPECT_RATIO) - { - sar_num = - ni_h264_pixel_aspect_list[out_frame.data.frame - .aspect_ratio_idc] - .num; - sar_den = - ni_h264_pixel_aspect_list[out_frame.data.frame - .aspect_ratio_idc] - .den; - } else if (api_param.sar_denom) - { - sar_num = api_param.sar_num; - sar_den = api_param.sar_denom; - } - ni_hrd_params_t hrd_params; - if (!dec_ctx.hw_action) + // use first encode config low delay flag for call flow + if (p_enc_api_param_list[0].low_delay_mode <= 0 && + encoder_opened) { - enc_ctx.hw_action = NI_CODEC_HW_NONE; + ni_log(NI_LOG_DEBUG, + "no decoder output, jump to encoder receive!\n"); + goto encode_recv; } else - { //Items in this else condition could be improved by being handled in libxcoder - enc_ctx.hw_action = NI_CODEC_HW_ENABLE; - api_param.hwframes = 1; - //to determine if from same device and buffer dimensions in memory - //needs to be done where input frame is available to check - p_hwframe = (niFrameSurface1_t *)out_frame.data.frame.p_data[3]; - enc_ctx.sender_handle = - (ni_device_handle_t)( - int64_t)p_hwframe->device_handle; - api_param.rootBufId = p_hwframe->ui16FrameIdx; + { + ni_log(NI_LOG_DEBUG, + "no decoder output, encode low_delay, jump to " + "decoder send!\n"); + goto decode_send; } - if (0 != - (ret = encoder_open_session( - &enc_ctx, dst_codec_format, iXcoderGUID, - &api_param, bit_depth, arg_width, arg_height, - &hrd_params, color_pri, color_trc, color_space, - video_full_range_flag, sar_num, sar_den, 1))) + } else if (!encoder_opened) + { + p_hwframe = dec_ctx.hw_action == NI_CODEC_HW_ENABLE ? + (niFrameSurface1_t *)out_frame.data.frame.p_data[3] : NULL; + + ret = encoder_open(&enc_ctx_list[0], p_enc_api_param_list, + output_total, &encConfXcoderParamsList[0], + &encConfXcoderGopList[0], + &out_frame.data.frame, arg_width, + arg_height, fps_num, fps_den, bitrate, + dst_codec_format, dec_ctx.pixel_format, + out_frame.data.frame.aspect_ratio_idc, + iXcoderGUID, p_hwframe, multi_thread, + &enc_rate_emu_list[0], false); + if (ret != 0) { - ni_log(NI_LOG_ERROR, - "Error: encoder_open_session failed, stop!\n"); break; } + encoder_opened = 1; } - // encoded bitstream Receiving - encode_send: - need_to_resend = 0; - // YUV Sending - send_fin_flag = encoder_send_data2( - &enc_ctx, dec_ctx.codec_format, &out_frame, &enc_in_frame, - sos_flag, input_video_width, input_video_height, pfs, - total_file_size, &total_bytes_sent, &xcodeState); - sos_flag = 0; - if (send_fin_flag < 0) //Error + //encode_send + for (i = 0; i < output_total; i++) { - if (!enc_ctx.hw_action) + // YUV Sending + send_fin_flag = encoder_send_data2(&enc_ctx_list[i], + &out_frame, + &enc_in_frame, + input_video_width, + input_video_height, + &total_bytes_sent, + &xcoder_state_list[i]); + if (send_fin_flag < 0) //Error { - ni_decoder_frame_buffer_free(&(out_frame.data.frame)); - } else + break; + } else if (send_fin_flag == NI_TEST_RETCODE_EAGAIN) { - //pre close cleanup will clear it out - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *)out_frame.data - .frame.p_data[3])) - ->ui16FrameIdx; - memcpy(&hwframe_pool_tracker[current_hwframe_index], - (uint8_t *)out_frame.data.frame.p_data[3], - sizeof(niFrameSurface1_t)); + // need to resend + continue; } + } + + // encoder send handling + if (send_fin_flag < 0) + { break; - } else if (send_fin_flag == 2) + } else if (enc_ctx_list[0].hw_action) { - need_to_resend = 1; - goto encode_recv; - } - if (enc_ctx.hw_action) - { //track in array with unique index, free when enc read finds - //this must be implemented in application space for complete - //tracking of hwframes - //If encoder write had no buffer avail space the next time we - //update the tracker will be redundant - uint16_t current_hwframe_index = - ((niFrameSurface1_t *)((uint8_t *)out_frame.data.frame - .p_data[3])) - ->ui16FrameIdx; - memcpy(&hwframe_pool_tracker[current_hwframe_index], - (uint8_t *)out_frame.data.frame.p_data[3], - sizeof(niFrameSurface1_t)); - ni_frame_wipe_aux_data( - &(out_frame.data.frame)); //reusebuff + p_hwframe = (niFrameSurface1_t *)out_frame.data.frame.p_data[3]; + ni_hw_frame_ref(p_hwframe); + ni_frame_wipe_aux_data(&out_frame.data.frame); } else { - ni_decoder_frame_buffer_free(&(out_frame.data.frame)); + ni_decoder_frame_buffer_free(&out_frame.data.frame); } - // encoded bitstream Receiving encode_recv: - prev_num_pkt = number_of_packets; - receive_fin_flag = encoder_receive_data( - &enc_ctx, &out_packet, output_video_width, - output_video_height, p_file, &xcodeRecvTotal, print_time, &out_frame); // out_frame is passed in for future sequence change support (XCODER_APP_TRANSCODE does not support sequence change yet) - recycle_index = out_packet.data.packet.recycle_index; - if (prev_num_pkt < number_of_packets && //skip if nothing read - enc_ctx.hw_action && recycle_index > 0 && - recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx.ddr_config)) - //encoder only returns valid recycle index - //when there's something to recycle. This range is suitable for all memory bins + receive_fin_flag = encoder_receive(&enc_ctx_list[0], + &out_frame, &out_packet, + output_video_width, + output_video_height, + &number_of_packets_list[0], + output_total, &p_file_list[0], + &total_bytes_received_list[0], + print_time, + &xcoder_state_list[0]); + for (i = 0; receive_fin_flag >= 0 && i < output_total; i++) { - if (hwframe_pool_tracker[recycle_index].ui16FrameIdx) + if (!xcoder_state_list[i].enc_eos_received) + { + ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i); + end_of_all_streams = 0; + break; + } else { - ni_hwframe_buffer_recycle( - &hwframe_pool_tracker[recycle_index], - hwframe_pool_tracker[recycle_index].device_handle); - //zero for tracking purposes - hwframe_pool_tracker[recycle_index].ui16FrameIdx = 0; + ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i); + end_of_all_streams = 1; } } + if (print_time) { previous_time = current_time; } - - // Error or encoder eos - if (receive_fin_flag < 0 || - out_packet.data.packet.end_of_stream) - { - break; - } } } - unsigned int time_diff = - (unsigned int)(current_time.tv_sec - start_time.tv_sec); - if (time_diff == 0) - time_diff = 1; - printf("[R] Got: Frames= %u fps=%f Total bytes %llu\n", - number_of_frames, ((float)number_of_frames / (float)time_diff), - total_bytes_received); - printf("[R] Got: Packets= %u fps=%f Total bytes %llu\n", - number_of_packets, - ((float)number_of_packets) / ((float)time_diff), xcodeRecvTotal); + decoder_stat_report_and_close(&dec_ctx, total_bytes_received); - num_post_recycled = scan_and_clean_hwdescriptors(hwframe_pool_tracker); - ni_log(NI_LOG_DEBUG, "Cleanup recycled %d internal buffers\n", - num_post_recycled); - ni_device_session_close(&dec_ctx, 1, NI_DEVICE_TYPE_DECODER); + encoder_stat_report_and_close(&enc_ctx_list[0], output_total, + &number_of_packets_list[0], + &total_bytes_received_list[0]); ni_rsrc_free_device_context(sdPara.p_dec_rsrc_ctx); rcPara.p_dec_rsrc_ctx = NULL; sdPara.p_dec_rsrc_ctx = NULL; - ni_packet_buffer_free(&(in_pkt.data.packet)); - ni_frame_buffer_free(&(out_frame.data.frame)); - - ni_device_session_close(&enc_ctx, 1, NI_DEVICE_TYPE_ENCODER); + ni_packet_buffer_free(&in_pkt.data.packet); + ni_frame_buffer_free(&out_frame.data.frame); ni_rsrc_free_device_context(sdPara.p_enc_rsrc_ctx); rcPara.p_enc_rsrc_ctx = NULL; @@ -8955,7 +9882,6 @@ int main(int argc, char *argv[]) */ ni_device_session_context_clear(&dec_ctx); - ni_device_session_context_clear(&enc_ctx); ni_device_session_context_clear(&upl_ctx); ni_device_session_context_clear(&sca_ctx); ni_device_session_context_clear(&crop_ctx); @@ -8963,6 +9889,15 @@ int main(int argc, char *argv[]) ni_device_session_context_clear(&ovly_ctx); ni_device_session_context_clear(&fmt_ctx); + for (i = 0; i < output_total; i++) + { + ni_device_session_context_clear(&enc_ctx_list[i]); + if (p_file_list[i] != NULL) + { + fclose(p_file_list[i]); + } + } + for (input_index = 0; input_index < input_total; input_index++) { if (input_arg_pfs[input_index]) @@ -8970,15 +9905,13 @@ int main(int argc, char *argv[]) close(input_arg_pfs[input_index]); } } - if (p_file) - { - fclose(p_file); - } - + ni_aligned_free(yuv_buf); + free(p_dec_api_param); + free(p_enc_api_param_list); free(g_file_cache); g_file_cache = NULL; - printf("All Done.\n"); + ni_log(NI_LOG_INFO, "All Done.\n"); return ret; } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.h index b6286ba9..d94d15c3 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_device_test.h @@ -20,12 +20,12 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_device_test.h -* -* \brief Example code on how to programmatically work with NI Quadra using -* libxcoder API -* -*******************************************************************************/ + * \file ni_device_test.h + * + * \brief Application for performing video processing with libxcoder API. + * Its code provides examples on how to programatically use libxcoder + * API. + ******************************************************************************/ #pragma once @@ -45,21 +45,7 @@ #define lseek _lseek #endif -#if defined(LRETURN) -#undef LRETURN -#define LRETURN goto end; -#undef END -#define END \ - end: -#else -#define LRETURN goto end; -#define END \ - end: -#endif - -#define NVME_CMD_SEM_PROTECT 1 - - +#define NVME_CMD_SEM_PROTECT 1 #define FILE_NAME_LEN 256 #define XCODER_APP_TRANSCODE 0 @@ -68,9 +54,10 @@ #define XCODER_APP_HWUP_ENCODE 3 #define XCODER_APP_FILTER 4 -#define ENC_CONF_STRUCT_SIZE 0x100 +#define ENC_CONF_STRUCT_SIZE 0x100 #define MAX_INPUT_FILES 3 +#define MAX_OUTPUT_FILES 4 #define NI_TEST_RETCODE_FAILURE -1 #define NI_TEST_RETCODE_SUCCESS 0 @@ -81,20 +68,47 @@ #define NI_ALIGN(x, a) (((x)+(a)-1)&~((a)-1)) +typedef enum +{ + NI_SW_PIX_FMT_NONE = -1, /* invalid format */ + NI_SW_PIX_FMT_YUV444P, /* 8-bit YUV444 planar */ + NI_SW_PIX_FMT_YUV444P10LE, /* 10-bit YUV444 planar */ +} ni_sw_pix_fmt_t; + +typedef struct _ni_pix_fmt_name +{ + const char *name; + ni_pix_fmt_t pix_fmt; +} ni_pix_fmt_name_t; + +typedef struct _ni_gc620_pix_fmt +{ + ni_pix_fmt_t pix_fmt_ni; + int pix_fmt_gc620; +} ni_gc620_pix_fmt_t; + typedef struct _device_state { + int dec_sos_sent; int dec_eos_sent; int dec_eos_received; + int enc_resend; + int enc_sos_sent; int enc_eos_sent; int enc_eos_received; - int enc_seq_change; } device_state_t; +// simplistic ref counted HW frame +typedef struct _ni_hwframe_ref_t +{ + int ref_cnt; + niFrameSurface1_t surface; +} ni_hwframe_ref_t; + typedef struct _tx_data { char fileName[MAX_INPUT_FILES][FILE_NAME_LEN]; uint32_t DataSizeLimit; - int device_handle; int mode; ni_session_context_t *p_dec_ctx; @@ -121,7 +135,6 @@ typedef struct RecvDataStruct_ { char fileName[FILE_NAME_LEN]; uint32_t DataSizeLimit; - int device_handle; int mode; ni_session_context_t *p_dec_ctx; @@ -145,6 +158,13 @@ typedef struct RecvDataStruct_ int arg_height; } rx_data_t; +typedef struct ni_rate_emu +{ + int rate_emu_framerate; // target framerate to emulate + uint64_t rate_emu_start; // start time in ns for rate emulation + uint64_t rate_emu_input_frames; // number of frames processed +} ni_rate_emu_t; + typedef struct _ni_drawbox_params { int box_w; @@ -447,57 +467,57 @@ typedef struct _ni_vp9_header_info } ni_vp9_header_info_t; int decoder_send_data(ni_session_context_t * p_dec_ctx, - ni_session_data_io_t * p_in_data, int stFlag, - int input_video_width, int input_video_height, int pfs, - unsigned int fileSize, unsigned long *sentTotal, - int printT, device_state_t *xState, void *stream_info); + ni_session_data_io_t * p_in_data, + int input_video_width, int input_video_height, + int pfs, unsigned long *sentTotal, int printT, + device_state_t *xState, void *stream_info); int decoder_receive_data(ni_session_context_t * p_dec_ctx, ni_session_data_io_t * p_out_data, int output_video_width, int output_video_height, FILE *pfr, unsigned long long *recvTotal, int printT, - int writeToFile, device_state_t *xState); - -int encoder_send_data( - ni_session_context_t * p_enc_ctx, ni_session_data_io_t * p_in_data, - int stFlag, int input_video_width, int input_video_height, int pfs, - unsigned int fileSize, unsigned long *sentSize, device_state_t *xState, - int bit_depth, int is_last_input); - -int encoder_send_data2( - ni_session_context_t * p_enc_ctx, uint32_t dec_codec_format, - ni_session_data_io_t * p_dec_out_data, ni_session_data_io_t * p_enc_in_data, - int stFlag, int input_video_width, int input_video_height, int pfs, - unsigned int fileSize, unsigned long *sentSize, device_state_t *xState); + int writeToFile, device_state_t *xState, + int * p_rx_size); + +int encoder_send_data(ni_session_context_t * p_enc_ctx, + ni_session_data_io_t * p_in_data, void *yuv_buf, + int input_video_width, int input_video_height, + unsigned long *sent_size, device_state_t *xState, + int is_last_input, + ni_rate_emu_t *p_rate_emu); + +int encoder_send_data2(ni_session_context_t * p_enc_ctx, + ni_session_data_io_t * p_dec_out_data, + ni_session_data_io_t * p_enc_in_data, + int input_video_width, int input_video_height, + unsigned long *sent_size, device_state_t *xState); int encoder_close_session(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_in_data, - ni_session_data_io_t *p_out_data); + ni_session_data_io_t *p_in_data, + ni_session_data_io_t *p_out_data); int encoder_init_session(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_in_data, - ni_session_data_io_t *p_out_data, - int arg_width, - int arg_height, - int bit_depth); + ni_session_data_io_t *p_in_data, + ni_session_data_io_t *p_out_data, + int arg_width, int arg_height, + ni_pix_fmt_t pix_fmt); int encoder_sequence_change(ni_session_context_t *p_enc_ctx, - ni_session_data_io_t *p_in_data, - ni_session_data_io_t *p_out_data, - int width, - int height, - int bit_depth_factor); + ni_session_data_io_t *p_in_data, + ni_session_data_io_t *p_out_data, + int width, int height, ni_pix_fmt_t pix_fmt); int scale_filter(ni_session_context_t * p_ctx, ni_frame_t * p_frame_in, - ni_session_data_io_t * p_data_out, int scale_width, - int scale_height, int out_format); - -int drawbox_filter( - ni_session_context_t * p_crop_ctx, ni_session_context_t * p_pad_ctx, - ni_session_context_t * p_overlay_ctx, ni_session_context_t * p_fmt_ctx, - ni_frame_t * p_frame_in, ni_session_data_io_t * p_data_out, - box_params_t * p_box_params, int output_format); - + ni_session_data_io_t * p_data_out, int guid, int scale_width, + int scale_height, int in_format, int out_format); + +int drawbox_filter(ni_session_context_t * p_crop_ctx, + ni_session_context_t * p_pad_ctx, + ni_session_context_t * p_overlay_ctx, + ni_session_context_t * p_fmt_ctx, + ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, + box_params_t *p_box_params, int guid, + int input_format, int output_format); #ifdef __cplusplus } #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.c index 237d12ef..3412c0d4 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.c @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_getopt.c -* -* \brief Implementation of getopt and getopt_long with Windows API. -* -*******************************************************************************/ + * \file ni_getopt.c + * + * \brief Implementation of getopt() and getopt_long() for Windows environment + ******************************************************************************/ #include #include @@ -97,7 +96,6 @@ int getopt(int argc, char *argv[], const char *optstring) return c; } - int getopt_long(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex) { diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.h index e1d85dd3..b3571824 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_getopt.h @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_getopt.h -* -* \brief Implementation of getopt and getopt_long with Windows API. -* -*******************************************************************************/ + * \file ni_getopt.h + * + * \brief Implementation of getopt() and getopt_long() for Windows environment + ******************************************************************************/ #pragma once diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.c index 075147c9..df40ab82 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.c @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_lat_meas.c -* -* \brief utility functions for measuring frame latency -* -*******************************************************************************/ + * \file ni_lat_meas.c + * + * \brief Utility definitions for measuring frame/packet processing time in + * NETINT video processing devices + ******************************************************************************/ #ifdef __linux__ #include @@ -71,6 +71,7 @@ ni_lat_meas_q_t *ni_lat_meas_q_create(int capacity) queue->capacity = capacity; queue->front = queue->size = 0; queue->rear = capacity - 1; + queue->last_benchmark_time = ni_gettime_ns(); queue->array = (ni_lat_meas_q_entry_t *)malloc( queue->capacity * sizeof(ni_lat_meas_q_entry_t)); if (!queue->array) @@ -180,8 +181,8 @@ void *ni_lat_meas_q_front(ni_lat_meas_q_t *queue) void *ni_lat_meas_q_add_entry(ni_lat_meas_q_t *frame_time_q, uint64_t abs_time, int64_t ts_time) { - // ni_log(NI_LOG_DEBUG, "ni_lat_meas_q_add_entry abs_time=%lu ts_time=" - // "%ld\n", abs_time, ts_time); + // ni_log(NI_LOG_DEBUG, "ni_lat_meas_q_add_entry abs_time=%" PRIu64 " " + // "ts_time=%" PRId64 "\n", abs_time, ts_time); ni_lat_meas_q_entry_t entry = {.abs_timenano = abs_time, .ts_time = ts_time}; return ni_lat_meas_q_enqueue(frame_time_q, entry); @@ -200,8 +201,9 @@ void *ni_lat_meas_q_add_entry(ni_lat_meas_q_t *frame_time_q, uint64_t abs_time, uint64_t ni_lat_meas_q_check_latency(ni_lat_meas_q_t *frame_time_q, uint64_t abs_time, int64_t ts_time) { - // ni_log(NI_LOG_DEBUG, "ni_lat_meas_q_check_latency abs_time=%lu ts_time=" - // "%ld\n", abs_time, ts_time); + // ni_log(NI_LOG_DEBUG, "ni_lat_meas_q_check_latency abs_time=%" PRIu64 " " + // "ts_time="%" PRId64 "\n", abs_time, ts_time); + uint64_t ret = -1; uint32_t dequeue_count = 0; ni_lat_meas_q_entry_t *entry = ni_lat_meas_q_front(frame_time_q); @@ -231,11 +233,11 @@ uint64_t ni_lat_meas_q_check_latency(ni_lat_meas_q_t *frame_time_q, if ((entry == NULL) || (entry->ts_time > ts_time)) { // queue overrun OR // queue miss, perhaps frame was not enqueued properly or TS was offset - return -1; + ret = -1; } else if (entry->ts_time == ts_time) - { // queue item is perfectly matched, calculate latency - return (abs_time - entry->abs_timenano); + { + ret = abs_time - entry->abs_timenano; } - return -1; + return ret; } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.h index 0910871c..46ef9428 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_lat_meas.h @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_lat_meas.h -* -* \brief utility functions for measuring frame latency -* -*******************************************************************************/ + * \file ni_lat_meas.h + * + * \brief Utility definitions for measuring frame/packet processing time in + * NETINT video processing devices + ******************************************************************************/ #pragma once @@ -39,6 +39,7 @@ typedef struct _ni_lat_meas_q_entry_t typedef struct _ni_lat_meas_q_t { int front, rear, size, capacity; + uint64_t last_benchmark_time; ni_lat_meas_q_entry_t *array; } ni_lat_meas_q_t; @@ -51,4 +52,4 @@ void *ni_lat_meas_q_add_entry(ni_lat_meas_q_t *frame_time_q, uint64_t abs_time, int64_t ts_time); uint64_t ni_lat_meas_q_check_latency(ni_lat_meas_q_t *frame_time_q, - uint64_t abs_time, int64_t ts_time); \ No newline at end of file + uint64_t abs_time, int64_t ts_time); diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading.h index 3d7ca7a8..b0fe416c 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading.h @@ -20,13 +20,12 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_libxcoder_dynamic_loading.h -* -* \brief Libxcoder API dynamic loading support for Linux -* -* \author Netflix, Inc. (2022) -* -*******************************************************************************/ + * \file ni_libxcoder_dynamic_loading.h + * + * \brief Libxcoder API dynamic loading support for Linux + * + * \author Netflix, Inc. (2022) + ******************************************************************************/ #pragma once @@ -61,17 +60,26 @@ typedef int (LIB_API* PNISHOULDSENDSEIWITHFRAME) (ni_session_context_t *p_enc_ctx, ni_pic_type_t pic_type, ni_xcoder_params_t *p_param); typedef void (LIB_API* PNIDECRETRIEVEAUXDATA) (ni_frame_t *frame); typedef void (LIB_API* PNIENCPREPAUXDATA) (ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_codec_format_t codec_format, int should_send_sei_with_frame, uint8_t *mdcv_data, uint8_t *cll_data, uint8_t *cc_data, uint8_t *udu_data, uint8_t *hdrp_data); -typedef void (LIB_API* PNIENCCOPYAUXDATA) (ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_codec_format_t codec_format, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data, int is_hwframe, int is_nv12frame); +typedef void (LIB_API* PNIENCCOPYAUXDATA) (ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_codec_format_t codec_format, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data, int is_hwframe, int is_semiplanar); +typedef int (LIB_API* PNIENCWRITEFROMYUVBUFFER) (ni_session_context_t *p_ctx, ni_frame_t *p_enc_frame, uint8_t *p_yuv_buffer); +typedef int (LIB_API* PNIEXTRACTCUSTOMSEI) (uint8_t *pkt_data, int pkt_size, long index, ni_packet_t *p_packet, uint8_t sei_type, int vcl_found); +typedef int (LIB_API* PNIDECPACKETPARSE) (ni_session_context_t *p_session_ctx, ni_xcoder_params_t *p_param, uint8_t *data, int size, ni_packet_t *p_packet, int low_delay, int codec_format, int pkt_nal_bitmap, int custom_sei_type, int *svct_skip_next_packet, int *is_lone_sei_pkt); +typedef int (LIB_API* PNIEXPANDFRAME) (ni_frame_t *dst, ni_frame_t *src, int dst_stride[], int raw_width, int raw_height, int ni_fmt, int nb_planes); // // Function pointers for ni_util.h // -typedef void (LIB_API* PNIGETHWYUV420PDIM) (int width, int height, int bit_depth_factor, int is_nv12, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS]); -typedef void (LIB_API* PNICOPYHWYUV420P) (uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int width, int height, int bit_depth_factor, int is_nv12, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS]); +typedef void (LIB_API* PNIGETHWYUV420PDIM) (int width, int height, int bit_depth_factor, int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS]); +typedef void (LIB_API* PNIGETFRAMEDIM) (int width, int height, ni_pix_fmt_t pix_fmt, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS]); +typedef void (LIB_API* PNIGETMINFRAMEDIM) (int width, int height, ni_pix_fmt_t pix_fmt, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS]); +typedef void (LIB_API* PNICOPYHWYUV420P) (uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int width, int height, int bit_depth_factor, int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS]); +typedef void (LIB_API* PNICOPYFRAMEDATA) (uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, ni_pix_fmt_t pix_fmt, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS]); +typedef void (LIB_API* PNICOPYYUV444PTO420P) (uint8_t *p_dst0[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int width, int height, int factor, int mode); typedef int (LIB_API* PNIINSERTEMULATIONPREVENTBYTES) (uint8_t *buf, int size); typedef int (LIB_API* PNIREMOVEEMULATIONPREVENTBYTES) (uint8_t *buf, int size); typedef int32_t (LIB_API* PNIGETTIMEOFDAY) (struct timeval *p_tp, void *p_tzp); typedef uint64_t (LIB_API* PNIGETTIMENS) (void); typedef void (LIB_API* PNIUSLEEP) (int64_t usec); +typedef char * (LIB_API* PNISTRTOK) (char *s, const char *delim, char **saveptr); typedef ni_retcode_t (LIB_API* PNINETWORKLAYERCONVERTOUTPUT) (float *dst, uint32_t num, ni_packet_t *p_packet, ni_network_data_t *p_network, uint32_t layer); typedef uint32_t (LIB_API* PNIAINETWORKLAYERSIZE) (ni_network_layer_params_t *p_param); typedef uint32_t (LIB_API* PNIAINETWORKLAYERDIMS) (ni_network_layer_params_t *p_param); @@ -80,9 +88,33 @@ typedef ni_retcode_t (LIB_API* PNINETWORKCONVERTTENSORTODATA) (uint8_t *dst, uin typedef ni_retcode_t (LIB_API* PNINETWORKCONVERTDATATOTENSOR) (float *dst, uint32_t dst_len, uint8_t *src, uint32_t src_len, ni_network_layer_params_t *p_param); typedef void (LIB_API* PNICALCULATESHA256) (const uint8_t aui8Data[], size_t ui32DataLength, uint8_t aui8Hash[]); typedef void (LIB_API* PNICOPYHWDESCRIPTORS) (uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS]); -typedef char* (LIB_API* PNIGETLIBXCODERAPIVER) (void); -typedef char* (LIB_API* PNIGETCOMPATFWAPIVER) (void); -typedef char* (LIB_API* PNIGETLIBXCODERRELEASEVER) (void); +typedef char * (LIB_API* PNIGETLIBXCODERAPIVER) (void); +typedef char * (LIB_API* PNIGETCOMPATFWAPIVER) (void); +typedef void (LIB_API* PNIFMTFWAPIVERSTR) (const char ver_str[], char fmt_str[]); +typedef int (LIB_API* PNICMPFWAPIVER) (const char ver1[], const char ver2[]); +typedef char * (LIB_API* PNIGETLIBXCODERRELEASEVER) (void); +typedef const char * (LIB_API* PNIGETRCTXT) (ni_retcode_t rc); +typedef int (LIB_API* PNIPARAMGETKEYVALUE) (char *p_str, char *key, char *value); +typedef int (LIB_API* PNIRETRIEVEXCODERPARAMS) (char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx); +typedef int (LIB_API* PNIRETRIEVEXCODERGOP) (char xcoderGop[], ni_xcoder_params_t *params, ni_session_context_t *ctx); +typedef int (LIB_API* PNIRETRIEVEDECODERPARAMS) (char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx); +typedef int (LIB_API* PNIPTHREADMUTEXINIT) (ni_pthread_mutex_t *mutex); +typedef int (LIB_API* PNIPTHREADMUTEXDESTROY) (ni_pthread_mutex_t *mutex); +typedef int (LIB_API* PNIPTHREADMUTEXLOCK) (ni_pthread_mutex_t *mutex); +typedef int (LIB_API* PNIPTHREADMUTEXUNLOCK) (ni_pthread_mutex_t *mutex); +typedef int (LIB_API* PNIPTHREADCREATE) (ni_pthread_t *thread, const ni_pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); +typedef int (LIB_API* PNIPTHREADJOIN) (ni_pthread_t thread, void **value_ptr); +typedef int (LIB_API* PNIPTHREADCONDINIT) (ni_pthread_cond_t *cond, const ni_pthread_condattr_t *attr); +typedef int (LIB_API* PNIPTHREADCONDDESTROY) (ni_pthread_cond_t *cond); +typedef int (LIB_API* PNIPTHREADCONDBROADCAST) (ni_pthread_cond_t *cond); +typedef int (LIB_API* PNIPTHREADCONDWAIT) (ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex); +typedef int (LIB_API* PNIPTHREADCONDSIGNAL) (ni_pthread_cond_t *cond); +typedef int (LIB_API* PNIPTHREADCONDTIMEDWAIT) (ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex, const struct timespec *abstime); +typedef int (LIB_API* PNIPTHREADSIGMASK) (int how, const ni_sigset_t *set, ni_sigset_t *oldset); +typedef int (LIB_API* PNIPOSIXMEMALIGN) (void **memptr, size_t alignment, size_t size); +typedef const char * (LIB_API* PNIAIERRNOTOSTR) (int rc); +// + // // Function pointers for ni_device_api.h // @@ -90,7 +122,7 @@ typedef ni_session_context_t * (LIB_API* PNIDEVICESESSIONCONTEXTALLOCINIT) (void typedef ni_retcode_t (LIB_API* PNIDEVICESESSIONCONTEXTINIT) (ni_session_context_t *p_ctx); typedef void (LIB_API* PNIDEVICESESSIONCONTEXTCLEAR) (ni_session_context_t *p_ctx); typedef void (LIB_API* PNIDEVICESESSIONCONTEXTFREE) (ni_session_context_t *p_ctx); -typedef ni_event_handle_t (LIB_API* PNICREATEEVENT) (); +typedef ni_event_handle_t (LIB_API* PNICREATEEVENT) (void); typedef void (LIB_API* PNICLOSEEVENT) (ni_event_handle_t event_handle); typedef ni_device_handle_t (LIB_API* PNIDEVICEOPEN) (const char *dev, uint32_t *p_max_io_size_out); typedef void (LIB_API* PNIDEVICECLOSE) (ni_device_handle_t dev); @@ -103,9 +135,19 @@ typedef ni_retcode_t (LIB_API* PNIDEVICEDECSESSIONFLUSH) (ni_session_context_t * typedef int (LIB_API* PNIDEVICESESSIONWRITE) (ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type); typedef int (LIB_API* PNIDEVICESESSIONREAD) (ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type); typedef ni_retcode_t (LIB_API* PNIDEVICESESSIONQUERY) (ni_session_context_t *p_ctx, ni_device_type_t device_type); +typedef ni_retcode_t (LIB_API* PNIDEVICESESSIONQUERYDETAIL) (ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_detail_status_t *detail_data); +typedef ni_retcode_t (LIB_API* PNIDEVICESESSIONQUERYDETAILV1) (ni_session_context_t* p_ctx, ni_device_type_t device_type, ni_instance_mgr_detail_status_v1_t *detail_data); +typedef ni_retcode_t (LIB_API* PNIDEVICECONFIGNAMESPACENUM) (ni_device_handle_t device_handle, uint32_t namespace_num, uint32_t sriov_index); +typedef ni_retcode_t (LIB_API* PNIDEVICECONFIGQOS) (ni_device_handle_t device_handle, uint32_t mode); +typedef ni_retcode_t (LIB_API* PNIDEVICECONFIGQOSOP) (ni_device_handle_t device_handle, ni_device_handle_t device_handle_t, uint32_t over_provision); typedef ni_retcode_t (LIB_API* PNIFRAMEBUFFERALLOC) (ni_frame_t *p_frame, int video_width, int video_height, int alignment, int metadata_flag, int factor, int hw_frame_count, int is_planar); +typedef ni_retcode_t (LIB_API* PNIENCFRAMEBUFFERALLOC) (ni_frame_t *p_frame, int video_width, int video_height, int alignment, int metadata_flag, int factor, int hw_frame_count, int is_planar, ni_pix_fmt_t pix_fmt); +typedef ni_retcode_t (LIB_API* PNIFRAMEBUFFERALLOCDL) (ni_frame_t *p_frame, int video_width, int video_height, int pixel_format); typedef ni_retcode_t (LIB_API* PNIDECODERFRAMEBUFFERALLOC) (ni_buf_pool_t *p_pool, ni_frame_t *pframe, int alloc_mem, int video_width, int video_height, int alignment, int factor, int is_planar); typedef ni_retcode_t (LIB_API* PNIENCODERFRAMEBUFFERALLOC) (ni_frame_t *pframe, int video_width, int video_height, int linesize[], int alignment, int extra_len, bool alignment_2pass_wa); +typedef ni_retcode_t (LIB_API* PNISCALERDESTFRAMEALLOC) (ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params, niFrameSurface1_t *p_surface); +typedef ni_retcode_t (LIB_API* PNISCALERINPUTFRAMEALLOC) (ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params, niFrameSurface1_t *p_src_surface); +typedef ni_retcode_t (LIB_API* PNISCALERFRAMEPOOLALLOC) (ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params); typedef ni_retcode_t (LIB_API* PNIFRAMEBUFFERALLOCNV) (ni_frame_t *p_frame, int video_width, int video_height, int linesize[], int extra_len, bool alignment_2pass_wa); typedef ni_retcode_t (LIB_API* PNIENCODERSWFRAMEBUFFERALLOC) (bool planar, ni_frame_t *p_frame, int video_width, int video_height, int linesize[], int alignment, int extra_len, bool alignment_2pass_wa); typedef ni_retcode_t (LIB_API* PNIFRAMEBUFFERFREE) (ni_frame_t *pframe); @@ -133,30 +175,63 @@ typedef int (LIB_API* PNIDEVICESESSIONHWDL) (ni_session_context_t *p_ctx, ni_ses typedef int (LIB_API* PNIDEVICESESSIONHWUP) (ni_session_context_t* p_ctx, ni_session_data_io_t *p_src_data, niFrameSurface1_t* hwdesc); typedef ni_retcode_t (LIB_API* PNIFRAMEBUFFERALLOCHWENC) (ni_frame_t *pframe, int video_width, int video_height, int extra_len); typedef ni_retcode_t (LIB_API* PNIHWFRAMEBUFFERRECYCLE) (niFrameSurface1_t *surface, int32_t device_handle); +typedef ni_retcode_t (LIB_API* PNIHWFRAMEBUFFERRECYCLE2) (niFrameSurface1_t *surface); typedef ni_retcode_t (LIB_API* PNISCALERSETPARAMS) (ni_session_context_t *p_ctx, ni_scaler_params_t *p_params); typedef ni_retcode_t (LIB_API* PNIDEVICEALLOCFRAME) (ni_session_context_t* p_ctx, int width, int height, int format, int options, int rectangle_width, int rectangle_height, int rectangle_x, int rectangle_y, int rgba_color, int frame_index, ni_device_type_t device_type); +typedef ni_retcode_t (LIB_API* PNIDEVICEALLOCDSTFRAME) (ni_session_context_t *p_ctx, niFrameSurface1_t *p_out_surface, ni_device_type_t device_type); +typedef ni_retcode_t (LIB_API* PNIDEVICECLONEHWFRAME) (ni_session_context_t *p_ctx, ni_frameclone_desc_t *p_frameclone_desc); typedef ni_retcode_t (LIB_API* PNIDEVICECONFIGFRAME) (ni_session_context_t *p_ctx, ni_frame_config_t *p_cfg); +typedef ni_retcode_t (LIB_API* PNISCALERSETDRAWBOXPARAMS) (ni_session_context_t *p_ctx, ni_scaler_drawbox_params_t *p_params); +typedef ni_retcode_t (LIB_API* PNISCALERSETWATERMARKPARAMS) (ni_session_context_t *p_ctx, ni_scaler_watermark_params_t *p_params); +typedef ni_retcode_t (LIB_API* PNIDEVICEMULTICONFIGFRAME) (ni_session_context_t *p_ctx, ni_frame_config_t p_cfg_in[], int numInCfgs, ni_frame_config_t *p_cfg_out); typedef ni_retcode_t (LIB_API* PNIFRAMEBUFFERALLOCPIXFMT) (ni_frame_t *pframe, int pixel_format, int video_width, int video_height, int linesize[], int alignment, int extra_len); typedef ni_retcode_t (LIB_API* PNIAICONFIGNETWORKBINARY) (ni_session_context_t *p_ctx, ni_network_data_t *p_network, const char *file); typedef ni_retcode_t (LIB_API* PNIAIFRAMEBUFFERALLOC) (ni_frame_t *p_frame, ni_network_data_t *p_network); typedef ni_retcode_t (LIB_API* PNIAIPACKETBUFFERALLOC) (ni_packet_t *p_packet, ni_network_data_t *p_network); typedef ni_retcode_t (LIB_API* PNIRECONFIGBITRATE) (ni_session_context_t *p_ctx, int32_t bitrate); +typedef ni_retcode_t (LIB_API* PNIRECONFIGVUI) (ni_session_context_t *p_ctx, ni_vui_hrd_t *vui); typedef ni_retcode_t (LIB_API* PNIFORCEIDRFRAMETYPE) (ni_session_context_t *p_ctx); typedef ni_retcode_t (LIB_API* PNISETLTR) (ni_session_context_t *p_ctx, ni_long_term_ref_t *ltr); typedef ni_retcode_t (LIB_API* PNISETLTRINTERVAL) (ni_session_context_t *p_ctx, int32_t ltr_interval); typedef ni_retcode_t (LIB_API* PNISETFRAMEREFINVALID) (ni_session_context_t *p_ctx, int32_t frame_num); typedef ni_retcode_t (LIB_API* PNIRECONFIGFRAMERATE) (ni_session_context_t *p_ctx, ni_framerate_t *framerate); +typedef ni_retcode_t (LIB_API* PNIRECONFIGMAXFRAMESIZE) (ni_session_context_t *p_ctx, int32_t max_frame_size); +typedef ni_retcode_t (LIB_API* PNIRECONFIGMINMAXQP) (ni_session_context_t *p_ctx, ni_rc_min_max_qp *p_min_max_qp); typedef int (LIB_API* PNIDEVICESESSIONACQUIRE) (ni_session_context_t *p_upl_ctx, ni_frame_t *p_frame); typedef ni_retcode_t (LIB_API* PNIUPLOADERFRAMEBUFFERLOCK) (ni_session_context_t *p_upl_ctx, ni_frame_t *p_frame); typedef ni_retcode_t (LIB_API* PNIUPLOADERFRAMEBUFFERUNLOCK) (ni_session_context_t *p_upl_ctx, ni_frame_t *p_frame); typedef ni_retcode_t (LIB_API* PNIUPLOADERP2PTESTSEND) (ni_session_context_t *p_upl_ctx, uint8_t *p_data, uint32_t len, ni_frame_t *p_hwframe); typedef ni_retcode_t (LIB_API* PNIENCODERSETINPUTFRAMEFORMAT) (ni_session_context_t *p_enc_ctx, ni_xcoder_params_t *p_enc_params, int width, int height, int bit_depth, int src_endian, int planar); typedef ni_retcode_t (LIB_API* PNIUPLOADERSETFRAMEFORMAT) (ni_session_context_t *p_upl_ctx, int width, int height, ni_pix_fmt_t pixel_format, int isP2P); +typedef ni_retcode_t (LIB_API* PNISCALERP2PFRAMEACQUIRE) (ni_session_context_t *p_ctx, niFrameSurface1_t *p_surface, int data_len); typedef ni_retcode_t (LIB_API* PNIHWFRAMEP2PBUFFERRECYCLE) (ni_frame_t *p_frame); typedef int (LIB_API* PNIENCODERSESSIONREADSTREAMHEADER) (ni_session_context_t *p_ctx, ni_session_data_io_t *p_data); typedef int32_t (LIB_API* PNIGETDMABUFFILEDESCRIPTOR) (const ni_frame_t* p_frame); typedef ni_retcode_t (LIB_API* PNIDEVICESESSIONSEQUENCECHANGE) (ni_session_context_t *p_ctx, int width, int height, int bit_depth_factor, ni_device_type_t device_type); - +typedef ni_retcode_t (LIB_API* PNIAISESSIONREADMETRICS) (ni_session_context_t *p_ctx, ni_network_perf_metrics_t *p_metrics); +typedef ni_retcode_t (LIB_API* PNIQUERYNVMESTATUS) (ni_session_context_t *p_ctx, ni_load_query_t *p_load_query); +typedef ni_retcode_t (LIB_API* PNIQUERYFLFWVERSIONS) (ni_device_handle_t device_handle, ni_device_info_t *p_dev_info); +typedef ni_retcode_t (LIB_API* PNIQUERYVFNSID) (ni_device_handle_t device_handle, ni_device_vf_ns_id_t *p_dev_ns_vf, uint8_t fw_rev[]); +typedef ni_retcode_t (LIB_API* PNIQUERYTEMPERATURE) (ni_device_handle_t device_handle, ni_device_temp_t *p_dev_temp, uint8_t fw_rev[]); +typedef ni_retcode_t (LIB_API* PNIQUERYEXTRAINFO) (ni_device_handle_t device_handle, ni_device_extra_info_t *p_dev_extra_info, uint8_t fw_rev[]); +typedef ni_retcode_t (LIB_API* PNIENCODERFRAMEZEROCOPYCHECK) (ni_session_context_t *p_enc_ctx, ni_xcoder_params_t *p_enc_params, int width, int height, const int linesize[], bool set_linesize); +typedef ni_retcode_t (LIB_API* PNIENCODERFRAMEZEROCOPYBUFFERALLOC) (ni_frame_t *p_frame, int video_width, int video_height, const int linesize[], const uint8_t *data[], int extra_len); +typedef ni_retcode_t (LIB_API* PNIUPLOADERFRAMEZEROCOPYCHECK) (ni_session_context_t *p_upl_ctx, int width, int height, const int linesize[], int pixel_format); +typedef ni_retcode_t (LIB_API* PNIRECONFIGCRF) (ni_session_context_t *p_ctx, int32_t crf); +typedef ni_retcode_t (LIB_API* PNIRECONFIGCRF2) (ni_session_context_t *p_ctx, float crf); +typedef ni_retcode_t (LIB_API* PNIDEVICEALLOCANDGETFIRMWARELOGS) (ni_session_context_t *p_ctx, void** p_log_buffer, bool gen_log_file); +typedef ni_retcode_t (LIB_API* PNIRECONFIGVBVVALUE) (ni_session_context_t *p_ctx, int32_t vbvMaxRate, int32_t vbvBufferSize); +typedef ni_retcode_t (LIB_API* PNIDEVICESESSIONUPDATEFRAMEPOOL) (ni_session_context_t *p_ctx, uint32_t pool_size); +typedef ni_retcode_t (LIB_API* PNISETDEMOROIMAP) (ni_session_context_t *p_enc_ctx); +typedef ni_retcode_t (LIB_API* PNIENCPREPRECONFDEMODATA) (ni_session_context_t *p_enc_ctx, ni_frame_t *p_frame); +typedef void (LIB_API* PNIGOPPARAMSCHECKSET) (ni_xcoder_params_t *p_param, char *value); +typedef bool (LIB_API* PNIGOPPARAMSCHECK) (ni_xcoder_params_t *p_param); +typedef ni_retcode_t (LIB_API* PNIRECONFIGMAXFRAMESIZERATIO) (ni_session_context_t *p_ctx, int32_t max_frame_size_ratio); +typedef ni_retcode_t (LIB_API* PNIRECONFIGINTRAPRD) (ni_session_context_t *p_ctx, int32_t intra_period); +typedef ni_retcode_t (LIB_API* PNIP2PXFER) (ni_session_context_t *pSession, niFrameSurface1_t *source, uint64_t ui64DestAddr, uint32_t ui32FrameSize); +typedef int (LIB_API* PNICALCULATETOTALFRAMESIZE) (const ni_session_context_t *p_upl_ctx, const int linesize[]); +typedef ni_retcode_t (LIB_API* PNIRECONFIGSLICEARG) (ni_session_context_t *p_ctx, int16_t sliceArg); + /* End API function pointers */ @@ -173,16 +248,22 @@ typedef struct _NETINT_LIBXCODER_API_FUNCTION_LIST PNIDECRETRIEVEAUXDATA niDecRetrieveAuxData; /** Client should access ::ni_dec_retrieve_aux_data API through this pointer */ PNIENCPREPAUXDATA niEncPrepAuxData; /** Client should access ::ni_enc_prep_aux_data API through this pointer */ PNIENCCOPYAUXDATA niEncCopyAuxData; /** Client should access ::ni_enc_copy_aux_data API through this pointer */ + PNIENCWRITEFROMYUVBUFFER niEncWriteFromYuvBuffer; /** Client should access ::ni_enc_write_from_yuv_buffer API through this pointer */ + PNIEXTRACTCUSTOMSEI niExtractCustomSei; /** Client should access ::ni_extract_custom_sei API through this pointer */ + PNIDECPACKETPARSE niDecPacketParse; /** Client should access ::ni_dec_packet_parse API through this pointer */ + PNIEXPANDFRAME niExpandFrame; /** Client should access ::ni_expand_frame API through this pointer */ // // API function list for ni_util.h // PNIGETHWYUV420PDIM niGetHwYuv420PDim; /** Client should access ::ni_get_hw_yuv420p_dim API through this pointer */ PNICOPYHWYUV420P niCopyHwYuv420P; /** Client should access ::ni_copy_hw_yuv420p API through this pointer */ + PNICOPYYUV444PTO420P niCopyYuv444PTo420P; /** Client should access ::ni_copy_yuv_444p_to_420p API through this pointer */ PNIINSERTEMULATIONPREVENTBYTES niInsertEmulationPreventBytes; /** Client should access ::ni_insert_emulation_prevent_bytes API through this pointer */ PNIREMOVEEMULATIONPREVENTBYTES niRemoveEmulationPreventBytes; /** Client should access ::ni_remove_emulation_prevent_bytes API through this pointer */ PNIGETTIMEOFDAY niGettimeofday; /** Client should access ::ni_gettimeofday API through this pointer */ PNIGETTIMENS niGettimeNs; /** Client should access ::ni_gettime_ns API through this pointer */ PNIUSLEEP niUsleep; /** Client should access ::ni_usleep API through this pointer */ + PNISTRTOK niStrtok; /** Client should access ::ni_strtok API through this pointer */ PNINETWORKLAYERCONVERTOUTPUT niNetworkLayerConvertOutput; /** Client should access ::ni_network_layer_convert_output API through this pointer */ PNIAINETWORKLAYERSIZE niAiNetworkLayerSize; /** Client should access ::ni_ai_network_layer_size API through this pointer */ PNIAINETWORKLAYERDIMS niAiNetworkLayerDims; /** Client should access ::ni_ai_network_layer_dims API through this pointer */ @@ -193,7 +274,29 @@ typedef struct _NETINT_LIBXCODER_API_FUNCTION_LIST PNICOPYHWDESCRIPTORS niCopyHwDescriptors; /** Client should access ::ni_copy_hw_descriptors API through this pointer */ PNIGETLIBXCODERAPIVER niGetLibxcoderApiVer; /** Client should access ::ni_get_libxcoder_api_ver API through this pointer */ PNIGETCOMPATFWAPIVER niGetCompatFwApiVer; /** Client should access ::ni_get_compat_fw_api_ver API through this pointer */ + PNIFMTFWAPIVERSTR niFmtFwApiVerStr; /** Client should access ::ni_fmt_fw_api_ver_str API through this pointer */ + PNICMPFWAPIVER niCmpFwApiVer; /** Client should access ::ni_cmp_fw_api_ver API through this pointer */ PNIGETLIBXCODERRELEASEVER niGetLibxcoderReleaseVer; /** Client should access ::ni_get_libxcoder_release_ver API through this pointer */ + PNIGETRCTXT niGetRcTxt; /** Client should access ::ni_get_rc_txt API through this pointer */ + PNIPARAMGETKEYVALUE niParamGetKeyValue; /** Client should access ::ni_param_get_key_value API through this pointer */ + PNIRETRIEVEXCODERPARAMS niRetrieveXcoderParams; /** Client should access ::ni_retrieve_xcoder_params API through this pointer */ + PNIRETRIEVEXCODERGOP niRetrieveXcoderGop; /** Client should access ::ni_retrieve_xcoder_gop API through this pointer */ + PNIRETRIEVEDECODERPARAMS niRetrieveDecoderParams; /** Client should access ::ni_retrieve_decoder_params API through this pointer */ + PNIPTHREADMUTEXINIT niPthreadMutexInit; /** Client should access ::ni_pthread_mutex_init API through this pointer */ + PNIPTHREADMUTEXDESTROY niPthreadMutexDestroy; /** Client should access ::ni_pthread_mutex_destroy API through this pointer */ + PNIPTHREADMUTEXLOCK niPthreadMutexLock; /** Client should access ::ni_pthread_mutex_lock API through this pointer */ + PNIPTHREADMUTEXUNLOCK niPthreadMutexUnlock; /** Client should access ::ni_pthread_mutex_unlock API through this pointer */ + PNIPTHREADCREATE niPthreadCreate; /** Client should access ::ni_pthread_create API through this pointer */ + PNIPTHREADJOIN niPthreadJoin; /** Client should access ::ni_pthread_join API through this pointer */ + PNIPTHREADCONDINIT niPthreadCondInit; /** Client should access ::ni_pthread_cond_init API through this pointer */ + PNIPTHREADCONDDESTROY niPthreadCondDestroy; /** Client should access ::ni_pthread_cond_destroy API through this pointer */ + PNIPTHREADCONDBROADCAST niPthreadCondBroadcast; /** Client should access ::ni_pthread_cond_broadcast API through this pointer */ + PNIPTHREADCONDWAIT niPthreadCondWait; /** Client should access ::ni_pthread_cond_wait API through this pointer */ + PNIPTHREADCONDSIGNAL niPthreadCondSignal; /** Client should access ::ni_pthread_cond_signal API through this pointer */ + PNIPTHREADCONDTIMEDWAIT niPthreadCondTimedwait; /** Client should access ::ni_pthread_cond_timedwait API through this pointer */ + PNIPTHREADSIGMASK niPthreadSigmask; /** Client should access ::ni_pthread_sigmask API through this pointer */ + PNIPOSIXMEMALIGN niPosixMemalign; /** Client should access ::ni_posix_memalign API through this pointer */ + PNIAIERRNOTOSTR niAiErrnoToStr; /** Client should access ::ni_ai_errno_to_str API through this pointer */ // // API function list for ni_device_api.h // @@ -214,9 +317,18 @@ typedef struct _NETINT_LIBXCODER_API_FUNCTION_LIST PNIDEVICESESSIONWRITE niDeviceSessionWrite; /** Client should access ::ni_device_session_write API through this pointer */ PNIDEVICESESSIONREAD niDeviceSessionRead; /** Client should access ::ni_device_session_read API through this pointer */ PNIDEVICESESSIONQUERY niDeviceSessionQuery; /** Client should access ::ni_device_session_query API through this pointer */ + PNIDEVICESESSIONQUERYDETAIL niDeviceSessionQueryDetail; /** Client should access ::ni_device_session_query_detail API through this pointer */ + PNIDEVICESESSIONQUERYDETAILV1 niDeviceSessionQueryDetailV1; /** Client should access ::ni_device_session_query_detail_v1 API through this pointer */ + PNIDEVICECONFIGNAMESPACENUM niDeviceConfigNamespaceNum; /** Client should access ::ni_device_config_namespace_num API through this pointer */ + PNIDEVICECONFIGQOS niDeviceConfigQos; /** Client should access ::ni_device_config_qos API through this pointer */ + PNIDEVICECONFIGQOSOP niDeviceConfigQosOp; /** Client should access ::ni_device_config_qos_op API through this pointer */ PNIFRAMEBUFFERALLOC niFrameBufferAlloc; /** Client should access ::ni_frame_buffer_alloc API through this pointer */ + PNIFRAMEBUFFERALLOCDL niFrameBufferAllocDl; /** Client should access ::ni_frame_buffer_alloc_dl API through this pointer */ PNIDECODERFRAMEBUFFERALLOC niDecoderFrameBufferAlloc; /** Client should access ::ni_decoder_frame_buffer_alloc API through this pointer */ PNIENCODERFRAMEBUFFERALLOC niEncoderFrameBufferAlloc; /** Client should access ::ni_encoder_frame_buffer_alloc API through this pointer */ + PNISCALERDESTFRAMEALLOC niScalerDestFrameAlloc; /** Client should access ::ni_scaler_dest_frame_alloc API through this pointer */ + PNISCALERINPUTFRAMEALLOC niScalerInputFrameAlloc; /** Client should access ::ni_scaler_input_frame_alloc API through this pointer */ + PNISCALERFRAMEPOOLALLOC niScalerFramePoolAlloc; /** Client should access ::ni_scaler_frame_pool_alloc API through this pointer */ PNIFRAMEBUFFERALLOCNV niFrameBufferAllocNv; /** Client should access ::ni_frame_buffer_alloc_nv API through this pointer */ PNIENCODERSWFRAMEBUFFERALLOC niEncoderSwFrameBufferAlloc; /** Client should access ::ni_encoder_sw_frame_buffer_alloc API through this pointer */ PNIFRAMEBUFFERFREE niFrameBufferFree; /** Client should access ::ni_frame_buffer_free API through this pointer */ @@ -244,29 +356,66 @@ typedef struct _NETINT_LIBXCODER_API_FUNCTION_LIST PNIDEVICESESSIONHWUP niDeviceSessionHwup; /** Client should access ::ni_device_session_hwup API through this pointer */ PNIFRAMEBUFFERALLOCHWENC niFrameBufferAllocHwenc; /** Client should access ::ni_frame_buffer_alloc_hwenc API through this pointer */ PNIHWFRAMEBUFFERRECYCLE niHwframeBufferRecycle; /** Client should access ::ni_hwframe_buffer_recycle API through this pointer */ + PNIHWFRAMEBUFFERRECYCLE2 niHwframeBufferRecycle2; /** Client should access ::ni_hwframe_buffer_recycle2 API through this pointer */ PNISCALERSETPARAMS niScalerSetParams; /** Client should access ::ni_scaler_set_params API through this pointer */ PNIDEVICEALLOCFRAME niDeviceAllocFrame; /** Client should access ::ni_device_alloc_frame API through this pointer */ + PNIDEVICEALLOCDSTFRAME niDeviceAllocDstFrame; /** Client should access ::ni_device_alloc_dst_frame API through this pointer */ + PNIDEVICECLONEHWFRAME niDeviceCloneHwframe; /** Client should access ::ni_device_clone_hwframe API through this pointer */ PNIDEVICECONFIGFRAME niDeviceConfigFrame; /** Client should access ::ni_device_config_frame API through this pointer */ + PNIDEVICEMULTICONFIGFRAME niDeviceMultiConfigFrame; /** Client should access ::ni_device_multi_config_frame API through this pointer */ PNIFRAMEBUFFERALLOCPIXFMT niFrameBufferAllocPixfmt; /** Client should access ::ni_frame_buffer_alloc_pixfmt API through this pointer */ PNIAICONFIGNETWORKBINARY niAiConfigNetworkBinary; /** Client should access ::ni_ai_config_network_binary API through this pointer */ PNIAIFRAMEBUFFERALLOC niAiFrameBufferAlloc; /** Client should access ::ni_ai_frame_buffer_alloc API through this pointer */ PNIAIPACKETBUFFERALLOC niAiPacketBufferAlloc; /** Client should access ::ni_ai_packet_buffer_alloc API through this pointer */ PNIRECONFIGBITRATE niReconfigBitrate; /** Client should access ::ni_reconfig_bitrate API through this pointer */ + PNIRECONFIGVUI niReconfigVui; /** Client should access ::ni_reconfig_vui API through this pointer */ PNIFORCEIDRFRAMETYPE niForceIdrFrameType; /** Client should access ::ni_force_idr_frame_type API through this pointer */ PNISETLTR niSetLtr; /** Client should access ::ni_set_ltr API through this pointer */ PNISETLTRINTERVAL niSetLtrInterval; /** Client should access ::ni_set_ltr_interval API through this pointer */ PNISETFRAMEREFINVALID niSetFrameRefInvalid; /** Client should access ::ni_set_frame_ref_invalid API through this pointer */ PNIRECONFIGFRAMERATE niReconfigFramerate; /** Client should access ::ni_reconfig_framerate API through this pointer */ + PNIRECONFIGMAXFRAMESIZE niReconfigMaxFrameSize; /** Client should access ::ni_reconfig_max_frame_size API through this pointer */ + PNIRECONFIGMINMAXQP niReconfigMinMaxQp; /** Client should access ::ni_reconfig_min_max_qp API through this pointer */ PNIDEVICESESSIONACQUIRE niDeviceSessionAcquire; /** Client should access ::ni_device_session_acquire API through this pointer */ PNIUPLOADERFRAMEBUFFERLOCK niUploaderFrameBufferLock; /** Client should access ::ni_uploader_frame_buffer_lock API through this pointer */ PNIUPLOADERFRAMEBUFFERUNLOCK niUploaderFrameBufferUnlock; /** Client should access ::ni_uploader_frame_buffer_unlock API through this pointer */ PNIUPLOADERP2PTESTSEND niUploaderP2PTestSend; /** Client should access ::ni_uploader_p2p_test_send API through this pointer */ PNIENCODERSETINPUTFRAMEFORMAT niEncoderSetInputFrameFormat; /** Client should access ::ni_encoder_set_input_frame_format API through this pointer */ PNIUPLOADERSETFRAMEFORMAT niUploaderSetFrameFormat; /** Client should access ::ni_uploader_set_frame_format API through this pointer */ + PNISCALERP2PFRAMEACQUIRE niScalerP2PFrameAcquire; /** Client should access ::ni_scaler_p2p_frame_acquire API through this pointer */ PNIHWFRAMEP2PBUFFERRECYCLE niHwframeP2PBufferRecycle; /** Client should access ::ni_hwframe_p2p_buffer_recycle API through this pointer */ PNIENCODERSESSIONREADSTREAMHEADER niEncoderSessionReadStreamHeader; /** Client should access ::ni_encoder_session_read_stream_header API through this pointer */ PNIGETDMABUFFILEDESCRIPTOR niGetDmaBufFileDescriptor; /** Client should access ::ni_get_dma_buf_file_descriptor API through this pointer */ PNIDEVICESESSIONSEQUENCECHANGE niDeviceSessionSequenceChange; /** Client should access ::ni_device_session_sequence_change API through this pointer */ + PNISCALERSETDRAWBOXPARAMS niScalerSetDrawboxParams; /** Client should access ::ni_scaler_set_drawbox_params API through this pointer */ + PNISCALERSETWATERMARKPARAMS niScalerSetWatermarkParams; /** Client should access ::ni_scaler_set_watermark_params API through this pointer */ + PNIAISESSIONREADMETRICS niAiSessionReadMetrics; /** Client should access ::ni_ai_session_read_metrics API through this pointer */ + PNIQUERYNVMESTATUS niQueryNvmeStatus; /** Client should access ::ni_query_nvme_status API through this pointer */ + PNIQUERYFLFWVERSIONS niQueryFlFwVersions; /** Client should access ::ni_query_fl_fw_versions API through this pointer */ + PNIQUERYVFNSID niQueryVfNsId; /** Client should access ::ni_query_vf_ns_id API through this pointer */ + PNIQUERYTEMPERATURE niQueryTemperature; /** Client should access ::ni_query_temperature API through this pointer */ + PNIQUERYEXTRAINFO niQueryExtraInfo; /** Client should access ::ni_query_extra_info API through this pointer */ + PNIENCODERFRAMEZEROCOPYCHECK niEncoderFrameZerocopyCheck; /** Client should access ::ni_encoder_frame_zerocopy_check API through this pointer */ + PNIENCODERFRAMEZEROCOPYBUFFERALLOC niEncoderFrameZerocopyBufferAlloc; /** Client should access ::ni_encoder_frame_zerocopy_buffer_alloc API through this pointer */ + PNIUPLOADERFRAMEZEROCOPYCHECK niUploaderFrameZerocopyCheck; /** Client should access ::ni_uploader_frame_zerocopy_check API through this pointer */ + PNIRECONFIGCRF niReconfigCrf; /** Client should access ::ni_reconfig_crf API through this pointer */ + PNIRECONFIGCRF2 niReconfigCrf2; /** Client should access ::ni_reconfig_crf2 API through this pointer */ + PNIDEVICEALLOCANDGETFIRMWARELOGS niDeviceAllocAndGetFirmwareLogs; /** Client should access ::ni_device_alloc_and_get_firmware_logs API through this pointer */ + PNIRECONFIGVBVVALUE niReconfigVbvValue; /** Client should access ::ni_reconfig_vbv_value API through this pointer */ + PNIDEVICESESSIONUPDATEFRAMEPOOL niDeviceSessionUpdateFramepool; /** Client should access ::ni_device_session_update_framepool API through this pointer */ + PNIGETFRAMEDIM niGetFrameDim; /** Client should access ::ni_get_frame_dim API through this pointer */ + PNIGETMINFRAMEDIM niGetMinFrameDim; /** Client should access ::ni_get_min_frame_dim API through this pointer */ + PNICOPYFRAMEDATA niCopyFrameData; /** Client should access ::ni_copy_frame_data API through this pointer */ + PNIENCFRAMEBUFFERALLOC niEncFrameBufferAlloc; /** Client should access ::ni_enc_frame_buffer_alloc API through this pointer */ + PNISETDEMOROIMAP niSetDemoRoiMap; /** Client should access ::ni_set_demo_roi_map API through this pointer */ + PNIENCPREPRECONFDEMODATA niEncPrepReconfDemoData; /** Client should access ::ni_enc_prep_reconf_demo_data API through this pointer */ + PNIGOPPARAMSCHECKSET niGopParamsCheckSet; /** Client should access ::ni_gop_params_check_set API through this pointer */ + PNIGOPPARAMSCHECK niGopParamsCheck; /** Client should access ::ni_gop_params_check API through this pointer */ + PNIRECONFIGMAXFRAMESIZERATIO niReconfigMaxFrameSizeRatio; /** Client should access ::ni_reconfig_max_frame_size_ratio API through this pointer */ + PNIRECONFIGINTRAPRD niReconfigIntraprd; /** Client should access ::ni_reconfig_intraprd API through this pointer */ + PNIP2PXFER niP2PXfer; /** Client should access ::ni_p2p_xfer API through this pointer */ + PNICALCULATETOTALFRAMESIZE niCalculateTotalFrameSize; /** Client should access ::ni_calculate_total_frame_size API through this pointer */ + PNIRECONFIGSLICEARG niReconfigSliceArg; /** Client should access ::ni_reconfig_slice_arg API through this pointer */ } NETINT_LIBXCODER_API_FUNCTION_LIST; class NETINTLibxcoderAPI { @@ -286,16 +435,22 @@ class NETINTLibxcoderAPI { functionList->niDecRetrieveAuxData = reinterpret_cast(dlsym(lib,"ni_dec_retrieve_aux_data")); functionList->niEncPrepAuxData = reinterpret_cast(dlsym(lib,"ni_enc_prep_aux_data")); functionList->niEncCopyAuxData = reinterpret_cast(dlsym(lib,"ni_enc_copy_aux_data")); + functionList->niEncWriteFromYuvBuffer = reinterpret_cast(dlsym(lib,"ni_enc_write_from_yuv_buffer")); + functionList->niExtractCustomSei = reinterpret_cast(dlsym(lib,"ni_extract_custom_sei")); + functionList->niDecPacketParse = reinterpret_cast(dlsym(lib,"ni_dec_packet_parse")); + functionList->niExpandFrame = reinterpret_cast(dlsym(lib,"ni_expand_frame")); // // Function/symbol loading for ni_util.h // functionList->niGetHwYuv420PDim = reinterpret_cast(dlsym(lib,"ni_get_hw_yuv420p_dim")); functionList->niCopyHwYuv420P = reinterpret_cast(dlsym(lib,"ni_copy_hw_yuv420p")); + functionList->niCopyYuv444PTo420P = reinterpret_cast(dlsym(lib,"ni_copy_yuv_444p_to_420p")); functionList->niInsertEmulationPreventBytes = reinterpret_cast(dlsym(lib,"ni_insert_emulation_prevent_bytes")); functionList->niRemoveEmulationPreventBytes = reinterpret_cast(dlsym(lib,"ni_remove_emulation_prevent_bytes")); functionList->niGettimeofday = reinterpret_cast(dlsym(lib,"ni_gettimeofday")); functionList->niGettimeNs = reinterpret_cast(dlsym(lib,"ni_gettime_ns")); functionList->niUsleep = reinterpret_cast(dlsym(lib,"ni_usleep")); + functionList->niStrtok = reinterpret_cast(dlsym(lib,"ni_strtok")); functionList->niNetworkLayerConvertOutput = reinterpret_cast(dlsym(lib,"ni_network_layer_convert_output")); functionList->niAiNetworkLayerSize = reinterpret_cast(dlsym(lib,"ni_ai_network_layer_size")); functionList->niAiNetworkLayerDims = reinterpret_cast(dlsym(lib,"ni_ai_network_layer_dims")); @@ -306,7 +461,29 @@ class NETINTLibxcoderAPI { functionList->niCopyHwDescriptors = reinterpret_cast(dlsym(lib,"ni_copy_hw_descriptors")); functionList->niGetLibxcoderApiVer = reinterpret_cast(dlsym(lib,"ni_get_libxcoder_api_ver")); functionList->niGetCompatFwApiVer = reinterpret_cast(dlsym(lib,"ni_get_compat_fw_api_ver")); + functionList->niFmtFwApiVerStr = reinterpret_cast(dlsym(lib,"ni_fmt_fw_api_ver_str")); + functionList->niCmpFwApiVer = reinterpret_cast(dlsym(lib,"ni_cmp_fw_api_ver")); functionList->niGetLibxcoderReleaseVer = reinterpret_cast(dlsym(lib,"ni_get_libxcoder_release_ver")); + functionList->niGetRcTxt = reinterpret_cast(dlsym(lib,"ni_get_rc_txt")); + functionList->niParamGetKeyValue = reinterpret_cast(dlsym(lib,"ni_param_get_key_value")); + functionList->niRetrieveXcoderParams = reinterpret_cast(dlsym(lib,"ni_retrieve_xcoder_params")); + functionList->niRetrieveXcoderGop = reinterpret_cast(dlsym(lib,"ni_retrieve_xcoder_gop")); + functionList->niRetrieveDecoderParams = reinterpret_cast(dlsym(lib,"ni_retrieve_decoder_params")); + functionList->niPthreadMutexInit = reinterpret_cast(dlsym(lib,"ni_pthread_mutex_init")); + functionList->niPthreadMutexDestroy = reinterpret_cast(dlsym(lib,"ni_pthread_mutex_destroy")); + functionList->niPthreadMutexLock = reinterpret_cast(dlsym(lib,"ni_pthread_mutex_lock")); + functionList->niPthreadMutexUnlock = reinterpret_cast(dlsym(lib,"ni_pthread_mutex_unlock")); + functionList->niPthreadCreate = reinterpret_cast(dlsym(lib,"ni_pthread_create")); + functionList->niPthreadJoin = reinterpret_cast(dlsym(lib,"ni_pthread_join")); + functionList->niPthreadCondInit = reinterpret_cast(dlsym(lib,"ni_pthread_cond_init")); + functionList->niPthreadCondDestroy = reinterpret_cast(dlsym(lib,"ni_pthread_cond_destroy")); + functionList->niPthreadCondBroadcast = reinterpret_cast(dlsym(lib,"ni_pthread_cond_broadcast")); + functionList->niPthreadCondWait = reinterpret_cast(dlsym(lib,"ni_pthread_cond_wait")); + functionList->niPthreadCondSignal = reinterpret_cast(dlsym(lib,"ni_pthread_cond_signal")); + functionList->niPthreadCondTimedwait = reinterpret_cast(dlsym(lib,"ni_pthread_cond_timedwait")); + functionList->niPthreadSigmask = reinterpret_cast(dlsym(lib,"ni_pthread_sigmask")); + functionList->niPosixMemalign = reinterpret_cast(dlsym(lib,"ni_posix_memalign")); + functionList->niAiErrnoToStr = reinterpret_cast(dlsym(lib,"ni_ai_errno_to_str")); // // Function/symbol loading for ni_device_api.h // @@ -327,9 +504,18 @@ class NETINTLibxcoderAPI { functionList->niDeviceSessionWrite = reinterpret_cast(dlsym(lib,"ni_device_session_write")); functionList->niDeviceSessionRead = reinterpret_cast(dlsym(lib,"ni_device_session_read")); functionList->niDeviceSessionQuery = reinterpret_cast(dlsym(lib,"ni_device_session_query")); + functionList->niDeviceSessionQueryDetail = reinterpret_cast(dlsym(lib,"ni_device_session_query_detail")); + functionList->niDeviceSessionQueryDetailV1 = reinterpret_cast(dlsym(lib,"ni_device_session_query_detail_v1")); + functionList->niDeviceConfigNamespaceNum = reinterpret_cast(dlsym(lib,"ni_device_config_namespace_num")); + functionList->niDeviceConfigQos = reinterpret_cast(dlsym(lib,"ni_device_config_qos")); + functionList->niDeviceConfigQosOp = reinterpret_cast(dlsym(lib,"ni_device_config_qos_op")); functionList->niFrameBufferAlloc = reinterpret_cast(dlsym(lib,"ni_frame_buffer_alloc")); + functionList->niFrameBufferAllocDl = reinterpret_cast(dlsym(lib,"ni_frame_buffer_alloc_dl")); functionList->niDecoderFrameBufferAlloc = reinterpret_cast(dlsym(lib,"ni_decoder_frame_buffer_alloc")); functionList->niEncoderFrameBufferAlloc = reinterpret_cast(dlsym(lib,"ni_encoder_frame_buffer_alloc")); + functionList->niScalerDestFrameAlloc = reinterpret_cast(dlsym(lib,"ni_scaler_dest_frame_alloc")); + functionList->niScalerInputFrameAlloc = reinterpret_cast(dlsym(lib,"ni_scaler_input_frame_alloc")); + functionList->niScalerFramePoolAlloc = reinterpret_cast(dlsym(lib,"ni_scaler_frame_pool_alloc")); functionList->niFrameBufferAllocNv = reinterpret_cast(dlsym(lib,"ni_frame_buffer_alloc_nv")); functionList->niEncoderSwFrameBufferAlloc = reinterpret_cast(dlsym(lib,"ni_encoder_sw_frame_buffer_alloc")); functionList->niFrameBufferFree = reinterpret_cast(dlsym(lib,"ni_frame_buffer_free")); @@ -357,29 +543,66 @@ class NETINTLibxcoderAPI { functionList->niDeviceSessionHwup = reinterpret_cast(dlsym(lib,"ni_device_session_hwup")); functionList->niFrameBufferAllocHwenc = reinterpret_cast(dlsym(lib,"ni_frame_buffer_alloc_hwenc")); functionList->niHwframeBufferRecycle = reinterpret_cast(dlsym(lib,"ni_hwframe_buffer_recycle")); + functionList->niHwframeBufferRecycle2 = reinterpret_cast(dlsym(lib,"ni_hwframe_buffer_recycle2")); functionList->niScalerSetParams = reinterpret_cast(dlsym(lib,"ni_scaler_set_params")); functionList->niDeviceAllocFrame = reinterpret_cast(dlsym(lib,"ni_device_alloc_frame")); + functionList->niDeviceAllocDstFrame = reinterpret_cast(dlsym(lib,"ni_device_alloc_dst_frame")); + functionList->niDeviceCloneHwframe = reinterpret_cast(dlsym(lib,"ni_device_clone_hwframe")); functionList->niDeviceConfigFrame = reinterpret_cast(dlsym(lib,"ni_device_config_frame")); + functionList->niDeviceMultiConfigFrame = reinterpret_cast(dlsym(lib,"ni_device_multi_config_frame")); functionList->niFrameBufferAllocPixfmt = reinterpret_cast(dlsym(lib,"ni_frame_buffer_alloc_pixfmt")); functionList->niAiConfigNetworkBinary = reinterpret_cast(dlsym(lib,"ni_ai_config_network_binary")); functionList->niAiFrameBufferAlloc = reinterpret_cast(dlsym(lib,"ni_ai_frame_buffer_alloc")); functionList->niAiPacketBufferAlloc = reinterpret_cast(dlsym(lib,"ni_ai_packet_buffer_alloc")); functionList->niReconfigBitrate = reinterpret_cast(dlsym(lib,"ni_reconfig_bitrate")); + functionList->niReconfigVui = reinterpret_cast(dlsym(lib,"ni_reconfig_vui")); functionList->niForceIdrFrameType = reinterpret_cast(dlsym(lib,"ni_force_idr_frame_type")); functionList->niSetLtr = reinterpret_cast(dlsym(lib,"ni_set_ltr")); functionList->niSetLtrInterval = reinterpret_cast(dlsym(lib,"ni_set_ltr_interval")); functionList->niSetFrameRefInvalid = reinterpret_cast(dlsym(lib,"ni_set_frame_ref_invalid")); functionList->niReconfigFramerate = reinterpret_cast(dlsym(lib,"ni_reconfig_framerate")); + functionList->niReconfigMaxFrameSize = reinterpret_cast(dlsym(lib,"ni_reconfig_max_frame_size")); + functionList->niReconfigMinMaxQp = reinterpret_cast(dlsym(lib,"ni_reconfig_min_max_qp")); functionList->niDeviceSessionAcquire = reinterpret_cast(dlsym(lib,"ni_device_session_acquire")); functionList->niUploaderFrameBufferLock = reinterpret_cast(dlsym(lib,"ni_uploader_frame_buffer_lock")); functionList->niUploaderFrameBufferUnlock = reinterpret_cast(dlsym(lib,"ni_uploader_frame_buffer_unlock")); functionList->niUploaderP2PTestSend = reinterpret_cast(dlsym(lib,"ni_uploader_p2p_test_send")); functionList->niEncoderSetInputFrameFormat = reinterpret_cast(dlsym(lib,"ni_encoder_set_input_frame_format")); functionList->niUploaderSetFrameFormat = reinterpret_cast(dlsym(lib,"ni_uploader_set_frame_format")); + functionList->niScalerP2PFrameAcquire = reinterpret_cast(dlsym(lib,"ni_scaler_p2p_frame_acquire")); functionList->niHwframeP2PBufferRecycle = reinterpret_cast(dlsym(lib,"ni_hwframe_p2p_buffer_recycle")); functionList->niEncoderSessionReadStreamHeader = reinterpret_cast(dlsym(lib,"ni_encoder_session_read_stream_header")); functionList->niGetDmaBufFileDescriptor = reinterpret_cast(dlsym(lib,"ni_get_dma_buf_file_descriptor")); functionList->niDeviceSessionSequenceChange = reinterpret_cast(dlsym(lib,"ni_device_session_sequence_change")); + functionList->niScalerSetDrawboxParams = reinterpret_cast(dlsym(lib,"ni_scaler_set_drawbox_params")); + functionList->niScalerSetWatermarkParams = reinterpret_cast(dlsym(lib,"ni_scaler_set_watermark_params")); + functionList->niAiSessionReadMetrics = reinterpret_cast(dlsym(lib,"ni_ai_session_read_metrics")); + functionList->niQueryNvmeStatus = reinterpret_cast(dlsym(lib,"ni_query_nvme_status")); + functionList->niQueryFlFwVersions = reinterpret_cast(dlsym(lib,"ni_query_fl_fw_versions")); + functionList->niQueryVfNsId = reinterpret_cast(dlsym(lib,"ni_query_vf_ns_id")); + functionList->niQueryTemperature = reinterpret_cast(dlsym(lib,"ni_query_temperature")); + functionList->niQueryExtraInfo = reinterpret_cast(dlsym(lib,"ni_query_extra_info")); + functionList->niEncoderFrameZerocopyCheck = reinterpret_cast(dlsym(lib,"ni_encoder_frame_zerocopy_check")); + functionList->niEncoderFrameZerocopyBufferAlloc = reinterpret_cast(dlsym(lib,"ni_encoder_frame_zerocopy_buffer_alloc")); + functionList->niUploaderFrameZerocopyCheck = reinterpret_cast(dlsym(lib,"ni_uploader_frame_zerocopy_check")); + functionList->niReconfigCrf = reinterpret_cast(dlsym(lib,"ni_reconfig_crf")); + functionList->niReconfigCrf2 = reinterpret_cast(dlsym(lib,"ni_reconfig_crf2")); + functionList->niDeviceAllocAndGetFirmwareLogs = reinterpret_cast(dlsym(lib,"ni_device_alloc_and_get_firmware_logs")); + functionList->niReconfigVbvValue = reinterpret_cast(dlsym(lib,"ni_reconfig_vbv_value")); + functionList->niDeviceSessionUpdateFramepool = reinterpret_cast(dlsym(lib,"ni_device_session_update_framepool")); + functionList->niGetFrameDim = reinterpret_cast(dlsym(lib,"ni_get_frame_dim")); + functionList->niGetMinFrameDim = reinterpret_cast(dlsym(lib,"ni_get_min_frame_dim")); + functionList->niCopyFrameData = reinterpret_cast(dlsym(lib,"ni_copy_frame_data")); + functionList->niEncFrameBufferAlloc = reinterpret_cast(dlsym(lib,"ni_enc_frame_buffer_alloc")); + functionList->niSetDemoRoiMap = reinterpret_cast(dlsym(lib,"ni_set_demo_roi_map")); + functionList->niEncPrepReconfDemoData = reinterpret_cast(dlsym(lib,"ni_enc_prep_reconf_demo_data")); + functionList->niGopParamsCheckSet = reinterpret_cast(dlsym(lib,"ni_gop_params_check_set")); + functionList->niGopParamsCheck = reinterpret_cast(dlsym(lib,"ni_gop_params_check")); + functionList->niReconfigMaxFrameSizeRatio = reinterpret_cast(dlsym(lib,"ni_reconfig_max_frame_size_ratio")); + functionList->niReconfigIntraprd = reinterpret_cast(dlsym(lib,"ni_reconfig_intraprd")); + functionList->niP2PXfer = reinterpret_cast(dlsym(lib,"ni_p2p_xfer")); + functionList->niCalculateTotalFrameSize = reinterpret_cast(dlsym(lib,"ni_calculate_total_frame_size")); + functionList->niReconfigSliceArg = reinterpret_cast(dlsym(lib,"ni_reconfig_slice_arg")); } }; diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading_test.cpp b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading_test.cpp index c83cded1..4a07d499 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading_test.cpp +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_libxcoder_dynamic_loading_test.cpp @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** - * \file ni_libxcoder_dynamic_loading_test.c - * - * \brief Use ni_libxcoder_dynamic_loading.h to dynamically load libxcoder at - * runtime. Check all function pointers are mapped. Only for Linux. + * \file ni_libxcoder_dynamic_loading_test.cpp * + * \brief Application to test that ni_libxcoder_dynamic_loading.h successfully + * loads all its exported functions ******************************************************************************/ #include @@ -64,8 +63,8 @@ int main(int argc, char **argv) } printf("Dynamically loaded functionList\n"); - for (int i = 0; i < (sizeof(NETINT_LIBXCODER_API_FUNCTION_LIST) / \ - sizeof(void *)); i++) + for (int i = 0; i < (int)((sizeof(NETINT_LIBXCODER_API_FUNCTION_LIST) / \ + sizeof(void *))); i++) { if (((void *) *(((void **) &functionList) + i)) == NULL) { @@ -82,4 +81,4 @@ int main(int argc, char **argv) dlclose(handle); exit(failed_func_ptr_check); -} \ No newline at end of file +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.c index 0b69a556..6efa1a4c 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.c @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_log.c -* -* \brief Exported logging routines definition -* -*******************************************************************************/ + * \file ni_log.c + * + * \brief Logging definitions + ******************************************************************************/ #include #include @@ -37,11 +36,52 @@ #include #endif #include "ni_log.h" +#include "ni_defs.h" +#include "ni_device_api.h" +#include "ni_util.h" + static ni_log_level_t ni_log_level = NI_LOG_INFO; static void (*ni_log_callback)(int, const char*, va_list) = ni_log_default_callback; +#ifdef _WIN32 +static ni_pthread_mutex_t ni_log2_mutex; +static int ni_log2_mutex_initialized = 0; +INIT_ONCE g_InitOnce_ni_log2_mutex = INIT_ONCE_STATIC_INIT; +#else +static ni_pthread_mutex_t ni_log2_mutex = PTHREAD_MUTEX_INITIALIZER; +//pthread +#endif +static int ni_log2_print_with_mutex = 0; + +#define NI_LOG2_SESSION_ID_TIMESTAMP_FMT "[SID=%x, TS=" "%" PRIu64 "]" +#define NI_LOG2_TIMESTAMP_FMT "[TS=" "%" PRIu64 "]" +#define NI_LOG2_SESSION_ID_FMT "[SID=%x]" +#define NI_LOG2_E2EID_FMT "|%s|" +#define NI_LOG2_FMT_FMT "%s" +#define NI_LOG2_SPACE " " + +#define NI_LOG2_PRINT_BUFF_SIZE 512 + +#ifdef _ANDROID +#include + +static char ni_log_tag[128] = "libxcoder"; + +#define ALOGV(fmt, ...) \ + __android_log_vprint(ANDROID_LOG_VERBOSE, ni_log_tag, fmt, ##__VA_ARGS__) +#define ALOGD(fmt, ...) \ + __android_log_vprint(ANDROID_LOG_DEBUG, ni_log_tag, fmt, ##__VA_ARGS__) +#define ALOGI(fmt, ...) \ + __android_log_vprint(ANDROID_LOG_INFO, ni_log_tag, fmt, ##__VA_ARGS__) +#define ALOGW(fmt, ...) \ + __android_log_vprint(ANDROID_LOG_WARN, ni_log_tag, fmt, ##__VA_ARGS__) +#define ALOGE(fmt, ...) \ + __android_log_vprint(ANDROID_LOG_ERROR, ni_log_tag, fmt, ##__VA_ARGS__) +#endif + + /*!***************************************************************************** * \brief Get time for logs with microsecond timestamps * @@ -88,6 +128,8 @@ int32_t ni_log_gettimeofday(struct timeval *p_tp, struct timezone *p_tzp) * \param[in] vl variadric args list * * \return + * \note This function doesn't automatically append a newline to the end of + * the log message. ******************************************************************************/ void ni_log_default_callback(int level, const char* fmt, va_list vl) { @@ -99,22 +141,18 @@ void ni_log_default_callback(int level, const char* fmt, va_list vl) { struct timeval tv; ni_log_gettimeofday(&tv, NULL); -#ifdef _WIN32 - fprintf(stderr, "[%lld] ", (long long) (tv.tv_sec * 1000000LL + tv.tv_usec)); -#else fprintf(stderr, "[%" PRIu64 "] ", (uint64_t) (tv.tv_sec * 1000000LL + tv.tv_usec)); -#endif } #endif #endif #ifdef _ANDROID - if (level == NI_LOG_INFO) + if (level >= NI_LOG_DEBUG) + ALOGD(fmt, vl); + else if (level == NI_LOG_INFO) ALOGI(fmt, vl); - else if (level >= NI_LOG_ERROR) - ALOGE(fmt, vl); else - ALOGV(fmt, vl); + ALOGE(fmt, vl); #else vfprintf(stderr, fmt, vl); #endif @@ -250,4 +288,167 @@ ni_log_level_t arg_to_ni_log_level(const char *arg_str) } else { return NI_LOG_INVALID; } -} \ No newline at end of file +} + +#ifdef _ANDROID +/*!****************************************************************************** + * \brief Set ni_log_tag + * + * \param log tag + * + * \return + *******************************************************************************/ +void ni_log_set_log_tag(const char *log_tag) +{ + strcpy(ni_log_tag, log_tag); + ni_log_tag[strlen(log_tag)] = '\0'; +} +#endif + +uint64_t ni_log_get_utime() +{ + struct timeval tv; + ni_log_gettimeofday(&tv, NULL); + return (uint64_t) (tv.tv_sec * 1000000LL + tv.tv_usec); +} + +#ifdef _WIN32 +static BOOL CALLBACK ni_log2_init_mutex_once_callback(PINIT_ONCE InitOnce, + PVOID Parameter, + PVOID *Context) +{ + ni_pthread_mutex_init(&ni_log2_mutex); + ni_log2_mutex_initialized = 1; + return true; +} +#endif + +void ni_log2_with_mutex(int on) +{ +#ifdef _WIN32 + if(!ni_log2_mutex_initialized && on) + { + InitOnceExecuteOnce(&g_InitOnce_ni_log2_mutex, ni_log2_init_mutex_once_callback, NULL, NULL); + } +#endif + ni_log2_print_with_mutex = on; +} + +void ni_log2(const void *p_context, ni_log_level_t level, const char *fmt, ...) +{ + const ni_session_context_t *p_session_context = (const ni_session_context_t *)p_context; + + if(level > ni_log_level) + { + return; + } + + if(ni_log2_print_with_mutex) + { + ni_pthread_mutex_lock(&ni_log2_mutex); + + if(p_session_context && level == NI_LOG_ERROR) + { + ni_log(level, NI_LOG2_SESSION_ID_TIMESTAMP_FMT "" NI_LOG2_E2EID_FMT "" NI_LOG2_SPACE, + p_session_context->session_id, ni_log_get_utime(), p_session_context->E2EID); + } + else if(p_session_context) + { + ni_log(level, NI_LOG2_SESSION_ID_FMT "" NI_LOG2_E2EID_FMT "" NI_LOG2_SPACE, + p_session_context->session_id, p_session_context->E2EID); + } + else if (level == NI_LOG_ERROR) + { + ni_log(level, NI_LOG2_TIMESTAMP_FMT "" NI_LOG2_SPACE, + ni_log_get_utime()); + } + + va_list vl; + va_start(vl, fmt); + if (ni_log_callback) + { + ni_log_callback(level, fmt, vl); + } + va_end(vl); + + ni_pthread_mutex_unlock(&ni_log2_mutex); + } + else + { + if(!p_session_context && level != NI_LOG_ERROR) + { + va_list vl; + va_start(vl, fmt); + if (ni_log_callback) + { + ni_log_callback(level, fmt, vl); + } + va_end(vl); + + return; + } + + char printbuf[NI_LOG2_PRINT_BUFF_SIZE]; + // int used_size = 0; + // size_t free_size = NI_LOG2_PRINT_BUFF_SIZE; + int this_used_size = 0; + + if(p_session_context && level == NI_LOG_ERROR) + { + this_used_size = snprintf(printbuf, NI_LOG2_PRINT_BUFF_SIZE, + NI_LOG2_SESSION_ID_TIMESTAMP_FMT "" NI_LOG2_E2EID_FMT "" NI_LOG2_SPACE "" NI_LOG2_FMT_FMT, + p_session_context->session_id, ni_log_get_utime(), p_session_context->E2EID, fmt); + } + else if(p_session_context) + { + this_used_size = snprintf(printbuf, NI_LOG2_PRINT_BUFF_SIZE, + NI_LOG2_SESSION_ID_FMT "" NI_LOG2_E2EID_FMT "" NI_LOG2_SPACE "" NI_LOG2_FMT_FMT, + p_session_context->session_id, p_session_context->E2EID, fmt); + } + else if (level == NI_LOG_ERROR) + { + this_used_size = snprintf(printbuf, NI_LOG2_PRINT_BUFF_SIZE, + NI_LOG2_TIMESTAMP_FMT "" NI_LOG2_SPACE "" NI_LOG2_FMT_FMT, + ni_log_get_utime(), fmt); + } + + if(this_used_size < 0) + { + ni_log(NI_LOG_ERROR,"ni_log2: an error occurd in snprintf\n"); + + va_list vl; + va_start(vl, fmt); + if (ni_log_callback) + { + ni_log_callback(level, fmt, vl); + } + va_end(vl); + + return; + } + + if(this_used_size >= NI_LOG2_PRINT_BUFF_SIZE) + { + ni_log(NI_LOG_ERROR,"ni_log2: too many characters for output\n"); + + va_list vl; + va_start(vl, fmt); + if (ni_log_callback) + { + ni_log_callback(level, fmt, vl); + } + va_end(vl); + + return; + } + + va_list vl; + va_start(vl, fmt); + if (ni_log_callback) + { + ni_log_callback(level, printbuf, vl); + } + va_end(vl); + + } +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.h index 791f9a81..90e9ffb9 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_log.h @@ -20,15 +20,15 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_log.h -* -* \brief Exported logging routines definition -* -*******************************************************************************/ + * \file ni_log.h + * + * \brief Logging definitions + ******************************************************************************/ #pragma once #include +#include #ifdef LIBXCODER_OBJS_BUILD #include "../build/xcoder_auto_headers.h" @@ -48,25 +48,6 @@ #define LIB_API_LOG #endif -#ifdef _ANDROID - -#include - -#define LOG_TAG "libxcoder" - -#define ALOGV(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_VERBOSE, LOG_TAG, fmt, ##__VA_ARGS__) -#define ALOGD(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) -#define ALOGI(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__) -#define ALOGW(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, fmt, ##__VA_ARGS__) -#define ALOGE(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__) - -#endif - #ifdef __cplusplus extern "C" { #endif @@ -152,6 +133,48 @@ LIB_API_LOG ni_log_level_t ff_to_ni_log_level(int fflog_level); ******************************************************************************/ LIB_API_LOG ni_log_level_t arg_to_ni_log_level(const char *fflog_level); +/*!***************************************************************************** + * \brief Get time for logs with microsecond timestamps + * + * + * \return microsecond timestamp + ******************************************************************************/ +LIB_API_LOG uint64_t ni_log_get_utime(); + +/*!***************************************************************************** + * \brief print log message and additional information using ni_log_callback, + * \param[in] p_context a pointer to ni_session_context_t if p_context != NULL + * session_id/E2EID will be printed as extra information + * \param[in] level log level, if log_level == NI_LOG_ERROR timastamp will be + * printed as extra information + * \param[in] format printf format specifier + * \param[in] ... additional arguments + * + * \return + ******************************************************************************/ +LIB_API_LOG void ni_log2(const void *p_context, ni_log_level_t level, const char *fmt, ...); + +/*!***************************************************************************** + * \brief set whether to use a lock or not in ni_log2 + * + * \param[in] on whether to use a lock, + * 1-->use a lock, + * 0-->use extra buf(no lock) + * \return + ******************************************************************************/ +void ni_log2_with_mutex(int on); + +#ifdef _ANDROID +/*!****************************************************************************** + * \brief Set ni_log_tag + * + * \param log tag + * + * \return + *******************************************************************************/ +LIB_API_LOG void ni_log_set_log_tag(const char *log_tag); +#endif + #ifdef __cplusplus } #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.c index 7cbc8f63..ffc0b700 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.c @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_nvme.c -* -* \brief Private routines related to working with NI Quadra over NVME interface -* -*******************************************************************************/ + * \file ni_nvme.c + * + * \brief Private definitions for interfacing with NETINT video processing + * devices over NVMe + ******************************************************************************/ #include #include @@ -62,40 +62,44 @@ ni_retcode_t ni_nvme_check_error_code(int rc, int opcode, uint32_t xcoder_type, uint32_t hw_id, uint32_t *p_instance_id) { + const char* type_str = GET_XCODER_DEVICE_TYPE_STR(xcoder_type); + switch (rc) { - case NI_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE: - case NI_RETCODE_NVME_SC_RESOURCE_IS_EMPTY: - case NI_RETCODE_NVME_SC_RESOURCE_NOT_FOUND: - case NI_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED: - case NI_RETCODE_NVME_SC_REQUEST_IN_PROGRESS: - case NI_RETCODE_NVME_SC_INVALID_PARAMETER: - case NI_RETCODE_NVME_SC_VPU_RECOVERY: - case NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT: - case NI_RETCODE_NVME_SC_VPU_GENERAL_ERROR: + case NI_RETCODE_SUCCESS: + return NI_RETCODE_SUCCESS; + case NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT: + ni_log(NI_LOG_ERROR, + "Hardware %u %s experiencing insufficient resource (instance %u opcode %x)!\n", + hw_id, type_str, *p_instance_id, opcode); + return NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE; + case NI_RETCODE_NVME_SC_INVALID_PARAMETER: + ni_log(NI_LOG_ERROR, + "Hardware %u %s failed to open session due to invalid " + "combination of " + "parameter values given (instance %u opcode %x)!\n", + hw_id, type_str, *p_instance_id, opcode); + return NI_RETCODE_INVALID_PARAM; + case NI_RETCODE_NVME_SC_STREAM_ERROR: + ni_log(NI_LOG_ERROR, + "Hardware %u %s got stream error (instance %u opcode %x)!\n", + hw_id, type_str, *p_instance_id, opcode); + return NI_RETCODE_ERROR_STREAM_ERROR; + default: + if (xcoder_type == NI_DEVICE_TYPE_AI) + { + ni_log(NI_LOG_ERROR, "Error rc = %d, %s, op = %02x, %s %u.0x%x\n", + rc, ni_ai_errno_to_str(rc), opcode, + type_str, hw_id, *p_instance_id); + } else { ni_log(NI_LOG_ERROR, - "Error rc = 0x%x, op = %02x, %s %u.%u terminating?" - "\n", - rc, opcode, device_type_str[xcoder_type], hw_id, + "Error rc = 0x%x, op = %02x, %s %u.%u terminating?\n", rc, + opcode, type_str, hw_id, *p_instance_id); - - if (NI_RETCODE_NVME_SC_RESOURCE_IS_EMPTY == rc || - NI_RETCODE_NVME_SC_RESOURCE_NOT_FOUND == rc || - NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT == rc || - NI_RETCODE_NVME_SC_VPU_GENERAL_ERROR == rc) - { - return NI_RETCODE_FAILURE; - } - break; - } - default: - { - break; // nothing } + return NI_RETCODE_FAILURE; } - - return NI_RETCODE_SUCCESS; } #ifdef __linux__ @@ -202,7 +206,7 @@ int ni_nvme_enumerate_devices CHAR model_name[40] = {0}; ni_nvme_identity_t *p_ni_identity = NULL; - printf("Searching for NETINT NVMe devices ...\n\n"); + ni_log(NI_LOG_DEBUG, "Searching for NETINT NVMe devices ...\n\n"); if (ni_posix_memalign((void **)(&p_buffer), sysconf(_SC_PAGESIZE), data_len)) @@ -293,7 +297,7 @@ int ni_nvme_enumerate_devices if (p_buffer) { - free(p_buffer); + ni_aligned_free(p_buffer); } ni_log(NI_LOG_INFO, @@ -415,7 +419,6 @@ int32_t ni_nvme_send_io_cmd_thru_admin_queue(ni_nvme_admin_opcode_t opcode, { int32_t rc; ni_nvme_passthrough_cmd_t nvme_cmd = {0}; - int32_t *p_addr = NULL; nvme_cmd.opcode = opcode; nvme_cmd.nsid = ni_htonl(1); @@ -462,7 +465,7 @@ void ni_parse_lba(uint64_t lba) ni_log(NI_LOG_DEBUG, "encoder lba:0x%" PRIx64 "(4K-aligned), 0x%" PRIx64 "(512B-aligned), session ID:%u\n", - lba, (lba << 3), session_id); + lba, ((uint64_t)lba << 3), session_id); if (lba_low >= WR_OFFSET_IN_4K) { ni_log(NI_LOG_ERROR, "encoder send frame failed\n"); @@ -486,7 +489,7 @@ void ni_parse_lba(uint64_t lba) ni_log(NI_LOG_DEBUG, "decoder lba:0x%" PRIx64 "(4K-aligned), 0x%" PRIx64 "(512B-aligned), session ID:%u\n", - lba, (lba << 3), session_id); + lba, ((uint64_t)lba << 3), session_id); if (lba_low >= WR_OFFSET_IN_4K) { ni_log(NI_LOG_ERROR, "decoder send packet failed\n"); @@ -523,13 +526,20 @@ int32_t ni_nvme_send_read_cmd(ni_device_handle_t handle, { int32_t rc; uint64_t offset = (uint64_t)lba << LBA_BIT_OFFSET; + + if (!p_data) + { + ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameter: p_data=%p\n", __func__, p_data); + return NI_RETCODE_INVALID_PARAM; + } + #ifdef _WIN32 uint32_t offset_l = (uint32_t)(offset & 0xFFFFFFFF); DWORD offset_h = (DWORD)(offset >> 32); OVERLAPPED overlap; ni_log(NI_LOG_TRACE, - "%s: handle=%" PRIx64 ", lba=0x%x, len=%d,offset:0x%x,0x%x\n", - __func__, (int64_t)handle, (lba << 3), data_len, offset_l, offset_h); + "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d,offset:0x%x,0x%x\n", + __func__, (int64_t)handle, ((uint64_t)lba << 3), data_len, offset_l, offset_h); memset(&overlap, 0, sizeof(overlap)); overlap.Offset = offset_l; overlap.OffsetHigh = offset_h; @@ -542,19 +552,24 @@ int32_t ni_nvme_send_read_cmd(ni_device_handle_t handle, rc = NI_ERRNO; ni_log(NI_LOG_DEBUG, "%s() ReadFile handle=%" PRIx64 ", event_handle=" - "%" PRIx64 ", lba=0x%x, len=%d, rc=%d\n", - __func__, (int64_t)handle, (int64_t)event_handle, (lba << 3), + "%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n", + __func__, (int64_t)handle, (int64_t)event_handle, ((uint64_t)lba << 3), data_len, rc); ni_log(NI_LOG_ERROR, "ERROR %d: %s() failed\n", rc, __func__); rc = NI_RETCODE_ERROR_NVME_CMD_FAILED; } else { - ni_log(NI_LOG_DEBUG, "%s() wait success\n", __func__); rc = NI_RETCODE_SUCCESS; } #else - if (handle != 0 && p_data != NULL) + if (!handle || handle == NI_INVALID_DEVICE_HANDLE) { + //if we can make sure that all handles are initialized to NI_INVALID_DEVICE_HANDLE + //we can remove the condition !handle + ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameters: handle=%" PRId32 "\n", __func__, handle); + return NI_RETCODE_INVALID_PARAM; + } + if (((uintptr_t)p_data) % NI_MEM_PAGE_ALIGNMENT) { ni_log(NI_LOG_DEBUG, @@ -584,23 +599,19 @@ int32_t ni_nvme_send_read_cmd(ni_device_handle_t handle, } ni_log(NI_LOG_TRACE, "%s: handle=%" PRIx64 - ", offset 0x%lx, lba=0x%x, len=%d, rc=%d\n", - __func__, (int64_t)handle, offset, (lba << 3), data_len, rc); + ", offset 0x%lx, lba=0x%lx, len=%d, rc=%d\n", + __func__, (int64_t)handle, offset, ((uint64_t)lba << 3), data_len, rc); if (rc < 0 || rc != data_len) { ni_log(NI_LOG_ERROR, - "ERROR %d: %s failed, lba=0x%x, len=%u, rc=%d, error=%d\n", - NI_ERRNO, __func__, (lba << 3), data_len, rc, NI_ERRNO); + "ERROR %d: %s failed, lba=0x%lx, len=%u, rc=%d, error=%d\n", + NI_ERRNO, __func__, ((uint64_t)lba << 3), data_len, rc, NI_ERRNO); ni_parse_lba(lba); rc = NI_RETCODE_ERROR_NVME_CMD_FAILED; } else { rc = NI_RETCODE_SUCCESS; } - } else - { - rc = NI_RETCODE_ERROR_NVME_CMD_FAILED; - } #endif return rc; } @@ -621,6 +632,13 @@ int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle, { int32_t rc; uint64_t offset = (uint64_t)lba << LBA_BIT_OFFSET; + + if (!p_data) + { + ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameter: p_data=%p\n", __func__, p_data); + return NI_RETCODE_INVALID_PARAM; + } + #ifdef _WIN32 uint32_t offset_l = (uint32_t)(offset & 0xFFFFFFFF); DWORD offset_h = (DWORD)(offset >> 32); @@ -628,8 +646,8 @@ int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle, OVERLAPPED overlap; ni_log(NI_LOG_TRACE, - "%s: handle=%" PRIx64 ", lba=0x%x, len=%d,offset:0x%x,0x%x\n", - __func__, (int64_t)handle, (lba << 3), data_len, offset_l, offset_h); + "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d,offset:0x%x,0x%x\n", + __func__, (int64_t)handle, ((uint64_t)lba << 3), data_len, offset_l, offset_h); memset(&overlap, 0, sizeof(overlap)); overlap.Offset = offset_l; @@ -642,26 +660,27 @@ int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle, rc = NI_ERRNO; ni_log(NI_LOG_DEBUG, "%s() WriteFile handle=%" PRIx64 ", event_handle=" - "%" PRIx64 ", lba=0x%x, len=%d, rc=%d\n", - __func__, (int64_t)handle, (int64_t)event_handle, (lba << 3), + "%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n", + __func__, (int64_t)handle, (int64_t)event_handle, ((uint64_t)lba << 3), data_len, rc); ni_log(NI_LOG_ERROR, "ERROR %d: ni_nvme_send_write_cmd() failed\n", rc); rc = NI_RETCODE_ERROR_NVME_CMD_FAILED; } else { - ni_log(NI_LOG_DEBUG, - "%s() ReadFile success handle=%" PRIx64 ", event_handle=" - "%" PRIx64 ", lba=0x%x, len=%d, rc=%d\n", - __func__, (int64_t)handle, (int64_t)event_handle, (lba << 3), - data_len, rc); rc = NI_RETCODE_SUCCESS; } #else - if (handle != 0 && p_data != NULL) + if (!handle || handle == NI_INVALID_DEVICE_HANDLE) { + //if we can make sure that all handles are initialized to NI_INVALID_DEVICE_HANDLE + //we can remove the condition !handle + ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameters: handle=%" PRId32 "\n", __func__, handle); + return NI_RETCODE_INVALID_PARAM; + } + if (((uintptr_t)p_data) % NI_MEM_PAGE_ALIGNMENT) { - ni_log(NI_LOG_DEBUG, + ni_log(NI_LOG_ERROR, "%s: Buffer not %d aligned = %p! Copying to aligned memory " "and writing.\n", __func__, NI_MEM_PAGE_ALIGNMENT, p_data); @@ -685,23 +704,19 @@ int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle, rc = pwrite(handle, p_data, data_len, offset); } ni_log(NI_LOG_TRACE, - "%s: handle=%" PRIx64 ", lba=0x%x, len=%d, rc=%d\n", __func__, - (int64_t)handle, (lba << 3), data_len, rc); + "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n", __func__, + (int64_t)handle, ((uint64_t)lba << 3), data_len, rc); if ((rc < 0) || (rc != data_len)) { ni_log(NI_LOG_ERROR, - "ERROR %d: %s failed, lba=0x%x, len=%u, rc=%d, error=%d\n", - NI_ERRNO, __func__, (lba << 3), data_len, rc, NI_ERRNO); + "ERROR %d: %s failed, lba=0x%lx, len=%u, rc=%d, error=%d\n", + NI_ERRNO, __func__, ((uint64_t)lba << 3), data_len, rc, NI_ERRNO); ni_parse_lba(lba); rc = NI_RETCODE_ERROR_NVME_CMD_FAILED; } else { rc = NI_RETCODE_SUCCESS; } - } else - { - rc = NI_RETCODE_ERROR_NVME_CMD_FAILED; - } #endif return rc; } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.h index c5891b21..935e0eee 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_nvme.h @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_nvme.h -* -* \brief Definitions related to working with NI Quadra over NVME interface -* -*******************************************************************************/ + * \file ni_nvme.h + * + * \brief Private definitions for interfacing with NETINT video processing + * devices over NVMe + ******************************************************************************/ #pragma once @@ -222,7 +222,7 @@ typedef struct _ni_nvme_identity uint8_t fw_build_id[256]; uint8_t fw_repo_info_padding[2]; - uint8_t memory_cfg; // 0 == DR, 1 == SR + uint8_t memory_cfg; // 0 == DR, 1 == SR, 2 == SR(disable P2P), 3 == SR_4G // byte offset 469 (=468+1 due to alignment at hw0_max_video_width) // xcoder HW - version 2 (replaces/deprecates version 1) @@ -325,9 +325,11 @@ typedef enum _ni_nvme_admin_opcode nvme_admin_cmd_xcoder_recycle_buffer = 0xD7, nvme_admin_cmd_xcoder_init_framepool = 0xD8, nvme_admin_cmd_xcoder_identity = 0xD9, + nvme_admin_cmd_xcoder_general = 0xDA, + nvme_admin_cmd_xcoder_load = 0xDB, + nvme_admin_cmd_xcoder_p2p_send = 0xDC } ni_nvme_admin_opcode_t; - typedef enum _nvme_open_xcoder_subtype { nvme_open_xcoder_create_session = 0x0000, @@ -363,14 +365,21 @@ typedef enum _nvme_query_xcoder_session_subtype typedef enum _nvme_query_xcoder_instance_subtype { + nvme_query_xcoder_instance_read_ai_hw_output = 0x0000, + nvme_query_xcoder_instance_read_perf_metrics = 0x0001, nvme_query_xcoder_instance_get_status = 0x0002, + nvme_query_xcoder_instance_get_current_status = 0x0003, nvme_query_xcoder_instance_get_stream_info = 0x0004, + nvme_query_xcoder_instance_network_layer_size_v2 = 0x0004, nvme_query_xcoder_instance_get_end_of_output = 0x0005, + nvme_query_xcoder_instance_read_network_layer_v2 = 0x0005, + nvme_query_xcoder_instance_write_buf_size_by_ep = 0x0007, nvme_query_xcoder_instance_acquire_buf = 0x0008, nvme_query_xcoder_instance_read_buf_size = 0x0009, nvme_query_xcoder_instance_write_buf_size = 0x000a, nvme_query_xcoder_instance_upload_idx = 0x000b, nvme_query_xcoder_instance_network_layer_size = 0x000b, + nvme_query_xcoder_instance_read_output_buf_size = 0x00b, nvme_query_xcoder_instance_dec_place_holder = 0x000c, //config_set_write_length nvme_query_xcoder_instance_read_network_layer = 0x000c, @@ -382,12 +391,15 @@ typedef enum _nvme_query_xcoder_instance_subtype typedef enum _nvme_query_xcoder_general_subtype { nvme_query_xcoder_general_get_status = 0x0002, + nvme_query_xcoder_general_get_detail_info = 0x0007, + nvme_query_xcoder_general_get_detail_info_v1 = 0x0008, } nvme_query_xcoder_general_subtype_t; typedef enum _nvme_config_xcoder_subtype { nvme_config_xcoder_config_session = 0x0000, - nvme_config_xcoder_config_instance = 0x0001 + nvme_config_xcoder_config_instance = 0x0001, + nvme_config_xcoder_config_global = 0x0002, } nvme_config_xcoder_subtype_t; typedef enum _nvme_config_xcoder_config_session_subtype @@ -397,6 +409,9 @@ typedef enum _nvme_config_xcoder_config_session_subtype nvme_config_xcoder_config_session_write = 0x0002, nvme_config_xcoder_config_session_keep_alive_timeout = 0x0003, nvme_config_xcoder_config_session_sw_version = 0x0004, + nvme_config_xcoder_config_namespace_num = 0x0005, + nvme_config_xcoder_config_ddr_priority = 0x0006, + nvme_config_xcoder_config_frame_clone = 0x0007, } nvme_config_xcoder_config_session_subtype_t; typedef enum _nvme_config_xcoder_config_instance_subtype @@ -406,6 +421,7 @@ typedef enum _nvme_config_xcoder_config_instance_subtype nvme_config_xcoder_config_set_enc_params = 0x0005, nvme_config_xcoder_config_set_dec_params = 0x0005, nvme_config_xcoder_config_set_scaler_params = 0x0005, + nvme_config_xcoder_config_set_scaler_drawbox_params = 0x0006, nvme_config_xcoder_config_flush = 0x0007, nvme_config_xcoder_config_update_enc_params = 0x0008, nvme_config_xcoder_config_set_network_binary = 0x0008, @@ -414,9 +430,19 @@ typedef enum _nvme_config_xcoder_config_instance_subtype nvme_config_xcoder_config_alloc_frame = 0x000d, // scaler only nvme_config_xcoder_config_set_sequence_change = 0x000d, // encoder only nvme_config_xcoder_instance_read_buf_size_busy_place_holder = 0x000e, // admin type taken by busy query read + nvme_config_xcoder_config_set_scaler_watermark_params = 0x000e, nvme_config_xcoder_instance_write_buf_size_busy_place_holder = 0x000f, // admin type taken by busy query write } nvme_config_xcoder_config_instance_subtype_t; +typedef enum _nvme_xcoder_general_subtype +{ + nvme_xcoder_general_status_query = 2, + nvme_xcoder_general_versions_query = 3, + nvme_xcoder_general_nsvf_query = 4, + nvme_xcoder_general_temperature_query = 5, + nvme_xcoder_general_extra_info_query = 5, +} nvme_xcoder_general_subtype_t; + typedef struct _ni_nvme_write_complete_dw0_t { @@ -611,8 +637,21 @@ int32_t ni_nvme_send_io_pass_through_command(ni_device_handle_t fd, ni_nvme_pass ((sub)<>8)< @@ -46,6 +46,7 @@ // max YUV frame size #define MAX_YUV_FRAME_SIZE (7680 * 4320 * 3 / 2) +#define MAX_ABGR_FRAME_SIZE (7680 * 4320 * 4) #define POOL_SIZE 2 #define FILE_NAME_LEN 256 @@ -55,7 +56,7 @@ int enc_eos_sent = 0; uint32_t number_of_frames = 0; uint32_t number_of_packets = 0; -uint32_t data_left_size = 0; +uint64_t data_left_size = 0; int g_repeat = 1; struct timeval start_time; @@ -66,10 +67,13 @@ time_t start_timestamp = 0; time_t previous_timestamp = 0; time_t current_timestamp = 0; -unsigned int total_file_size = 0; +unsigned long total_file_size = 0; uint8_t *g_curr_cache_pos = NULL; uint8_t *g_yuv_frame[POOL_SIZE] = {NULL, NULL}; +uint8_t *g_rgba_frame[POOL_SIZE] = {NULL, NULL}; + +uint8_t g_rgb2yuv_csc = 0; /*!**************************************************************************** * \brief Exit on argument error @@ -99,8 +103,8 @@ int read_next_chunk_from_file(int fd, uint8_t *p_dst, uint32_t to_read) { uint8_t *tmp_dst = p_dst; ni_log(NI_LOG_DEBUG, - "read_next_chunk_from_file:p_dst %p len %u totalSize %u left %u\n", - tmp_dst, to_read, total_file_size, data_left_size); + "read_next_chunk_from_file:p_dst %p len %u totalSize %llu left %llu\n", + tmp_dst, to_read, (unsigned long long)total_file_size, (unsigned long long)data_left_size); int to_copy = to_read; unsigned long tmpFileSize = to_read; if (data_left_size == 0) @@ -143,7 +147,7 @@ int read_next_chunk_from_file(int fd, uint8_t *p_dst, uint32_t to_read) * \return 0 on success * < 0 on error ******************************************************************************/ -int load_input_file(const char *filename, unsigned int *bytes_read) +int load_input_file(const char *filename, unsigned long *bytes_read) { struct stat info; @@ -232,7 +236,7 @@ int p2p_upload_send_data(ni_session_context_t *p_upl_ctx, int fd, int Vsize; int total_size; - ni_log(NI_LOG_DEBUG, "===> p2p upload_send_data <===\n"); + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "===> p2p upload_send_data <===\n"); /* An 8-bit YUV420 planar frame occupies [(width x height x 3)/2] bytes */ frame_size = input_video_height * input_video_width * 3 / 2; @@ -241,7 +245,7 @@ int p2p_upload_send_data(ni_session_context_t *p_upl_ctx, int fd, if (chunk_size == 0) { - ni_log(NI_LOG_DEBUG, "p2p_upload_send_data: read chunk size 0, eos!\n"); + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "p2p_upload_send_data: read chunk size 0, eos!\n"); *input_exhausted = 1; } @@ -253,7 +257,7 @@ int p2p_upload_send_data(ni_session_context_t *p_upl_ctx, int fd, p_upl_ctx->bit_depth_factor, 0, dst_stride, dst_height); - ni_log(NI_LOG_DEBUG, "p_dst alloc linesize = %d/%d/%d src height=%d " + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "p_dst alloc linesize = %d/%d/%d src height=%d " "dst height aligned = %d/%d/%d \n", dst_stride[0], dst_stride[1], dst_stride[2], input_video_height, dst_height[0], dst_height[1], @@ -312,6 +316,94 @@ int p2p_upload_send_data(ni_session_context_t *p_upl_ctx, int fd, return 0; } +/*!**************************************************************************** + * \brief Reads RGBA data from input file then calls a special libxcoder API + * function to transfer the RGBA data into the hardware frame on + * the Quadra device. + * + * \param [in] p_upl_ctx pointer to upload session context + * [in] fd file descriptor of input file + * [in] p_rgba_frame address of pointer to RGBA data + * [in] p_in_frame pointer to hardware frame + * [in] input_video_width video width + * [in] input_video_height video height + * [out] bytes_sent updated byte count of total data read + * [out] input_exhausted set to 1 when we reach end-of-file + * + * \return 0 on success + * -1 on error + ******************************************************************************/ +int p2p_upload_rgba_send_data(ni_session_context_t *p_upl_ctx, int fd, + uint8_t **p_rgba_frame, ni_frame_t *p_in_frame, + int input_video_width, int input_video_height, + unsigned long *bytes_sent, int *input_exhausted) +{ + static uint8_t tmp_buf[MAX_ABGR_FRAME_SIZE]; + void *p_buffer; + uint8_t *p_src,*p_dst; + int linewidth; + int frame_size; + int chunk_size; + int total_size; + int row; + + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "===> p2p upload_rgba_send_data <===\n"); + + /* An 8-bit RGBA frame is in a packed raster (or linear) format */ + /* and occupies width * height * 4 bytes. */ + frame_size = input_video_width * input_video_height * 4; + + chunk_size = read_next_chunk_from_file(fd, tmp_buf, frame_size); + + if (chunk_size == 0) + { + ni_log2(p_upl_ctx, NI_LOG_DEBUG, "p2p_upload_rgba_send_data: eos!\n"); + *input_exhausted = 1; + } + + p_in_frame->video_width = input_video_width; + p_in_frame->video_height = input_video_height; + p_in_frame->extra_data_len = 0; + + linewidth = input_video_width * 4; + + // Round up to 4K + total_size = NI_VPU_ALIGN4096(frame_size); + + if (*p_rgba_frame == NULL) + { + if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), total_size)) + { + fprintf(stderr, "Can't alloc memory\n"); + return -1; + } + + *p_rgba_frame = p_buffer; + } + + p_src = tmp_buf; + p_dst = *p_rgba_frame; + + for (row = 0; row < input_video_height; row++) + { + memcpy(p_dst, p_src, linewidth); + p_src += linewidth; + p_dst += linewidth; + } + + if (ni_uploader_p2p_test_send(p_upl_ctx, *p_rgba_frame, total_size, + p_in_frame)) + { + fprintf(stderr, "Error: failed ni_uploader_p2p_test_send()\n"); + return -1; + } else + { + *bytes_sent = total_size; + } + + return 0; +} + /*!**************************************************************************** * \brief Prepare frames to simulate P2P transfers * @@ -329,8 +421,6 @@ int p2p_prepare_frames(ni_session_context_t *p_upl_ctx, int input_video_width, { int i; int ret = 0; - int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0, 0, 0, 0}; - int dst_height[NI_MAX_NUM_DATA_POINTERS] = {0, 0, 0, 0}; ni_frame_t *p_in_frame; // Allocate memory for two hardware frames @@ -343,10 +433,6 @@ int p2p_prepare_frames(ni_session_context_t *p_upl_ctx, int input_video_width, p_in_frame->force_key_frame = 0; p_in_frame->extra_data_len = 0; - ni_get_hw_yuv420p_dim(input_video_width, input_video_height, - p_upl_ctx->bit_depth_factor, 0, dst_stride, - dst_height); - // Allocate a hardware ni_frame structure for the encoder if (ni_frame_buffer_alloc_hwenc( p_in_frame, input_video_width, input_video_height, @@ -400,11 +486,11 @@ int encoder_encode_frame(ni_session_context_t *p_enc_ctx, int oneSent; ni_session_data_io_t in_data; - ni_log(NI_LOG_DEBUG, "===> encoder_encode_frame <===\n"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "===> encoder_encode_frame <===\n"); if (enc_eos_sent == 1) { - ni_log(NI_LOG_DEBUG, "encoder_encode_frame: ALL data (incl. eos) sent " + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_encode_frame: ALL data (incl. eos) sent " "already!\n"); return 0; } @@ -442,15 +528,15 @@ int encoder_encode_frame(ni_session_context_t *p_enc_ctx, } else if (oneSent == 0 && !p_enc_ctx->ready_to_close) { *need_to_resend = 1; - ni_log(NI_LOG_DEBUG, "NEEDED TO RESEND"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "NEEDED TO RESEND"); } else { *need_to_resend = 0; - ni_log(NI_LOG_DEBUG, "encoder_encode_frame: total sent data size=%u\n", + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_encode_frame: total sent data size=%u\n", p_in_frame->data_len[3]); - ni_log(NI_LOG_DEBUG, "encoder_encode_frame: success\n"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_encode_frame: success\n"); if (p_enc_ctx->ready_to_close) { @@ -488,18 +574,18 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, ni_packet_t *p_out_pkt = &(p_out_data->data.packet); static int received_stream_header = 0; - ni_log(NI_LOG_DEBUG, "===> encoder_receive_data <===\n"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "===> encoder_receive_data <===\n"); if (NI_INVALID_SESSION_ID == p_enc_ctx->session_id || NI_INVALID_DEVICE_HANDLE == p_enc_ctx->blk_io_handle) { - ni_log(NI_LOG_DEBUG, "encode session not opened yet, return\n"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encode session not opened yet, return\n"); return 0; } if (p_file == NULL) { - ni_log(NI_LOG_ERROR, "Bad file pointer, return\n"); + ni_log2(p_enc_ctx, NI_LOG_ERROR, "Bad file pointer, return\n"); return -1; } @@ -519,7 +605,7 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, /* Read the encoded stream header */ rc = ni_encoder_session_read_stream_header(p_enc_ctx, p_out_data); - if (rc > meta_size) + if (rc > 0) { /* Write out the stream header */ if (fwrite((uint8_t *)p_out_pkt->p_data + meta_size, @@ -567,7 +653,7 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, end_flag = p_out_pkt->end_of_stream; rx_size = rc; - ni_log(NI_LOG_DEBUG, "encoder_receive_data: received data size=%d\n", rx_size); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_receive_data: received data size=%d\n", rx_size); if (rx_size > meta_size) { @@ -582,17 +668,17 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, *total_bytes_received += rx_size - meta_size; number_of_packets++; - ni_log(NI_LOG_DEBUG, "Got: Packets= %u\n", number_of_packets); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "Got: Packets= %u\n", number_of_packets); } else if (rx_size != 0) { fprintf(stderr, "Error: received %d bytes, <= metadata size %d!\n", rx_size, meta_size); return -1; } else if (!end_flag && - ((ni_xcoder_params_t *)(p_enc_ctx->p_session_config)) - ->low_delay_mode) + (((ni_xcoder_params_t *)(p_enc_ctx->p_session_config)) + ->low_delay_mode)) { - ni_log(NI_LOG_DEBUG, "low delay mode and NO pkt, keep reading...\n"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "low delay mode and NO pkt, keep reading...\n"); goto receive_data; } @@ -617,7 +703,7 @@ int encoder_receive_data(ni_session_context_t *p_enc_ctx, return 2; } - ni_log(NI_LOG_DEBUG, "encoder_receive_data: success\n"); + ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_receive_data: success\n"); return 0; } @@ -659,12 +745,15 @@ int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format, p_enc_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE; p_enc_ctx->hw_id = iXcoderGUID; + if (g_rgb2yuv_csc) + p_enc_ctx->pixel_format = NI_PIX_FMT_ABGR; + ni_encoder_set_input_frame_format(p_enc_ctx, p_enc_params, width, height, 8, NI_FRAME_LITTLE_ENDIAN, 1); // Encoder will operate in P2P mode ret = ni_device_session_open(p_enc_ctx, NI_DEVICE_TYPE_ENCODER); - if (ret < 0) + if (ret != NI_RETCODE_SUCCESS) { fprintf(stderr, "Error: encoder open session failure\n"); } else @@ -689,6 +778,7 @@ int uploader_open_session(ni_session_context_t *p_upl_ctx, int *iXcoderGUID, int width, int height) { int ret = 0; + ni_pix_fmt_t frame_format; p_upl_ctx->session_id = NI_INVALID_SESSION_ID; @@ -699,12 +789,15 @@ int uploader_open_session(ni_session_context_t *p_upl_ctx, int *iXcoderGUID, // Assign the card id to specify the specific Quadra device p_upl_ctx->hw_id = *iXcoderGUID; + // Assign the pixel format we want to use + frame_format = g_rgb2yuv_csc ? NI_PIX_FMT_ABGR : NI_PIX_FMT_YUV420P; + // Set the input frame format of the upload session - ni_uploader_set_frame_format(p_upl_ctx, width, height, NI_PIX_FMT_YUV420P, + ni_uploader_set_frame_format(p_upl_ctx, width, height, frame_format, 1); ret = ni_device_session_open(p_upl_ctx, NI_DEVICE_TYPE_UPLOAD); - if (ret < 0) + if (ret != NI_RETCODE_SUCCESS) { fprintf(stderr, "Error: uploader_open_session failure!\n"); return ret; @@ -743,7 +836,7 @@ void print_usage(void) "Usage: xcoderp2p [options]\n" "\n" "options:\n" - "--------------------------------------------------------------------------------" + "--------------------------------------------------------------------------------\n" " -h | --help Show help.\n" " -v | --version Print version info.\n" " -l | --loglevel Set loglevel of libxcoder API.\n" @@ -761,8 +854,8 @@ void print_usage(void) " (eg. '1920x1080')\n" " -m | --mode Input to output codec processing mode in " "format:\n" - " INTYPE2OUTTYPE. [p2a, p2h]\n" - " Type notation: p=P2P, a=AVC, h=HEVC\n" + " INTYPE2OUTTYPE. [p2a, p2h, r2a, r2h]\n" + " Type notation: p=P2P, a=AVC, h=HEVC, r=ABGR\n" " -o | --output Output file path.\n", NI_XCODER_REVISION); } @@ -856,12 +949,15 @@ void parse_arguments(int argc, char *argv[], char *input_filename, for (i = 0; i < strlen(optarg); i++) optarg[i] = (char)tolower((unsigned char)optarg[i]); - if (strcmp(optarg, "p2a") != 0 && strcmp(optarg, "p2h") != 0) + if (strcmp(optarg, "p2a") != 0 && strcmp(optarg, "p2h") != 0 && + strcmp(optarg, "r2a") != 0 && strcmp(optarg, "r2h") != 0) arg_error_exit("-, | --mode", optarg); // determine codec sprintf(mode_description, "P2P + Encoding"); + g_rgb2yuv_csc = (optarg[0] == 'r') ? 1 : 0; + if (optarg[2] == 'a') { *dst_codec_format = NI_CODEC_FORMAT_H264; @@ -904,15 +1000,6 @@ void parse_arguments(int argc, char *argv[], char *input_filename, } } -/*!**************************************************************************** - * \brief main - * - * \param [in] argc argument count - * [in] argv argument vector of parameters - * - * \return 0 on success - * -1 on error - ******************************************************************************/ int main(int argc, char *argv[]) { static char input_filename[FILE_NAME_LEN]; @@ -1071,15 +1158,30 @@ int main(int argc, char *argv[]) goto end; } - /* send out a frame to do rendering */ - if (p2p_upload_send_data( - &upl_ctx, input_file_fd, &g_yuv_frame[render_index], - &p2p_frame[render_index], input_video_width, input_video_height, - &total_bytes_sent, &input_exhausted)) + if (g_rgb2yuv_csc) { - fprintf(stderr, "Error: upload frame error\n"); - close(input_file_fd); - return -1; + // upload an rgba frame to quadra + if (p2p_upload_rgba_send_data( + &upl_ctx, input_file_fd, &g_rgba_frame[render_index], + &p2p_frame[render_index], input_video_width, input_video_height, + &total_bytes_sent, &input_exhausted)) + { + fprintf(stderr, "Error: upload frame error\n"); + ni_device_session_close(&upl_ctx, 1, NI_DEVICE_TYPE_UPLOAD); + goto end; + } + } else + { + /* send out a frame to do rendering */ + if (p2p_upload_send_data( + &upl_ctx, input_file_fd, &g_yuv_frame[render_index], + &p2p_frame[render_index], input_video_width, input_video_height, + &total_bytes_sent, &input_exhausted)) + { + fprintf(stderr, "Error: upload frame error\n"); + close(input_file_fd); + return -1; + } } while (send_fin_flag == 0 || receive_fin_flag == 0) @@ -1112,14 +1214,29 @@ int main(int argc, char *argv[]) // Fill the frame buffer with YUV data while the previous frame is being encoded if (!input_exhausted && need_to_resend == 0) { - if (p2p_upload_send_data( - &upl_ctx, input_file_fd, &g_yuv_frame[render_index], - &p2p_frame[render_index], input_video_width, - input_video_height, &total_bytes_sent, &input_exhausted)) + if (g_rgb2yuv_csc) { - fprintf(stderr, "Error: upload frame error\n"); - close(input_file_fd); - return -1; + if (p2p_upload_rgba_send_data( + &upl_ctx, input_file_fd, &g_rgba_frame[render_index], + &p2p_frame[render_index], input_video_width, + input_video_height, &total_bytes_sent, &input_exhausted)) + { + fprintf(stderr, "Error: upload frame error\n"); + close(input_file_fd); + return -1; + } + } + else + { + if (p2p_upload_send_data( + &upl_ctx, input_file_fd, &g_yuv_frame[render_index], + &p2p_frame[render_index], input_video_width, + input_video_height, &total_bytes_sent, &input_exhausted)) + { + fprintf(stderr, "Error: upload frame error\n"); + close(input_file_fd); + return -1; + } } } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_release_info.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_release_info.h index c9e18d22..0a09ef1c 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_release_info.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_release_info.h @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_release_info.h -* -* \brief Release identification data generated at release time -* -*******************************************************************************/ + * \file ni_release_info.h + * + * \brief Release identification data generated at release time + ******************************************************************************/ -#define NI_SW_RELEASE_TIME "2022-08-05_11:04:57_-0700" -#define NI_SW_RELEASE_ID "Netint_Quadra_release_v4.0.0_RCB" +#define NI_SW_RELEASE_TIME "2024-06-19_10:59:13_-0700" +#define NI_SW_RELEASE_ID "Netint_Quadra_release_v4.9.2_RC2" diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.cpp b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.cpp index 9d4562f5..3cba9420 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.cpp +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.cpp @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_rsrc_api.c -* -* \brief Exported routines related to resource management of NI Quadra devices -* -*******************************************************************************/ + * \file ni_rsrc_api.cpp + * + * \brief Public definitions for managing NETINT video processing devices + ******************************************************************************/ #include #include @@ -40,29 +39,28 @@ #include #include #include /* For mode constants */ -#include -#include "setjmp.h" +#include +#endif + +#if __APPLE__ +#include #endif #include "ni_rsrc_api.h" #include "ni_rsrc_priv.h" #include "ni_util.h" +static const char *ni_codec_format_str[] = {"H.264", "H.265", "VP9", "JPEG", + "AV1"}; +static const char *ni_dec_name_str[] = {"h264_ni_quadra_dec", "h265_ni_quadra_dec", + "vp9_ni_quadra_dec", "jpeg_ni_quadra_dec"}; +static const char *ni_enc_name_str[] = {"h264_ni_quadra_enc", "h265_ni_quadra_enc", "empty", + "jpeg_ni_quadra_enc", "av1_ni_quadra_enc"}; -// Decoder/Encoder reference (resolution_width, resolution_height, framerate) table -ni_rsrc_device_video_ref_cap_t g_device_reference_table[2][2] = -{ - // decoder - { - {1920, 1080, 240}, // H264 - {1920, 1080, 240}, // H265 - }, - // encoder - { - {1920, 1080, 240}, // H264 - {1920, 1080, 240}, // H265 - } -}; +char **g_xcoder_refresh_dev_names = NULL; +int g_xcoder_refresh_dev_count = 0; +bool g_device_in_ctxt = false; +ni_device_handle_t g_dev_handle = NI_INVALID_DEVICE_HANDLE; // return true if string key is found in array of strings, false otherwise static bool is_str_in_str_array(const char key[], @@ -90,20 +88,26 @@ void print_device(ni_device_t *p_device) } ni_device_info_t *p_dev_info = NULL; - for (size_t xcoder_index_1 = 0; - xcoder_index_1 < p_device->xcoder_cnt[NI_DEVICE_TYPE_DECODER]; + for (int xcoder_index_1 = 0; + xcoder_index_1 < p_device->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; xcoder_index_1++) { - p_dev_info = &p_device->xcoders[NI_DEVICE_TYPE_DECODER][xcoder_index_1]; - ni_log(NI_LOG_INFO, "Device #%zu:\n", xcoder_index_1); + p_dev_info = &p_device->xcoders[NI_DEVICE_TYPE_ENCODER][xcoder_index_1]; + ni_log(NI_LOG_INFO, "Device #%d:\n", xcoder_index_1); ni_log(NI_LOG_INFO, " Serial number: %.*s\n", (int)sizeof(p_dev_info->serial_number), p_dev_info->serial_number); ni_log(NI_LOG_INFO, " Model number: %.*s\n", (int)sizeof(p_dev_info->model_number), p_dev_info->model_number); - ni_log(NI_LOG_INFO, " F/W rev: %.*s\n", - (int)sizeof(p_dev_info->fw_rev), p_dev_info->fw_rev); + ni_log(NI_LOG_INFO, " Last ran firmware loader version: %.8s\n", + p_dev_info->fl_ver_last_ran); + ni_log(NI_LOG_INFO, " NOR flash firmware loader version: %.8s\n", + p_dev_info->fl_ver_nor_flash); + ni_log(NI_LOG_INFO, " Current firmware revision: %.8s\n", + p_dev_info->fw_rev); + ni_log(NI_LOG_INFO, " NOR flash firmware revision: %.8s\n", + p_dev_info->fw_rev_nor_flash); ni_log(NI_LOG_INFO, " F/W & S/W compatibility: %s\n", p_dev_info->fw_ver_compat_warning ? "no, possible missing features" : "yes"); @@ -117,15 +121,14 @@ void print_device(ni_device_t *p_device) p_dev_info->fw_build_time); ni_log(NI_LOG_INFO, " F/W build id: %s\n",p_dev_info->fw_build_id); ni_log(NI_LOG_INFO, " DeviceID: %s\n", p_dev_info->dev_name); - ni_log(NI_LOG_INFO, " BlockDeviceID: %s\n", p_dev_info->blk_name); ni_log(NI_LOG_INFO, " PixelFormats: yuv420p, yuv420p10le, nv12, p010le" ", ni_quadra\n"); for (size_t dev_type = NI_DEVICE_TYPE_DECODER; dev_type != NI_DEVICE_TYPE_XCODER_MAX; dev_type++) { - for (size_t xcoder_index_2 = 0; - xcoder_index_2 < p_device->xcoder_cnt[NI_DEVICE_TYPE_DECODER]; + for (int xcoder_index_2 = 0; + xcoder_index_2 < p_device->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; xcoder_index_2++) { if (strcmp(p_dev_info->dev_name, @@ -160,35 +163,67 @@ ni_retcode_t ni_rsrc_refresh(int should_match_rev) char curr_dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = {0}; int curr_dev_count = 0; int i = 0; - ni_device_t saved_coders = {0}; + ni_device_t *saved_coders = NULL; + saved_coders = (ni_device_t *)malloc(sizeof(ni_device_t)); + if (!saved_coders) + { + ni_log(NI_LOG_ERROR, "ERROR %s() failed to malloc memory: %s\n", + __func__, strerror(NI_ERRNO)); + return NI_RETCODE_FAILURE; + } + memset(saved_coders, 0, sizeof(ni_device_t)); // retrieve saved info from resource pool at start up if (NI_RETCODE_SUCCESS == ni_rsrc_list_devices( - NI_DEVICE_TYPE_DECODER, - saved_coders.xcoders[NI_DEVICE_TYPE_DECODER], - &(saved_coders.xcoder_cnt[NI_DEVICE_TYPE_DECODER]))) + NI_DEVICE_TYPE_ENCODER, + saved_coders->xcoders[NI_DEVICE_TYPE_ENCODER], + &(saved_coders->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]))) { - for (i = 0; i < saved_coders.xcoder_cnt[NI_DEVICE_TYPE_DECODER]; + for (i = 0; i < saved_coders->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; i++) { strcpy(xcoder_dev_names[i], - saved_coders.xcoders[NI_DEVICE_TYPE_DECODER][i] + saved_coders->xcoders[NI_DEVICE_TYPE_ENCODER][i] .dev_name); } xcoder_dev_count = - saved_coders.xcoder_cnt[NI_DEVICE_TYPE_DECODER]; - ni_log(NI_LOG_INFO, - "%d devices retrieved from current pool at start up\n", + saved_coders->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; +#ifdef XCODER_311 + ni_log(NI_LOG_DEBUG,"%d devices retrieved from current pool at start up\n", + xcoder_dev_count); +#else + ni_log(NI_LOG_INFO,"%d devices retrieved from current pool at start up\n", xcoder_dev_count); +#endif + } else { ni_log(NI_LOG_ERROR, "Error retrieving from current pool at start " "up\n"); } + free(saved_coders); + + if (xcoder_dev_count > 0) + { + g_xcoder_refresh_dev_names = (char **)malloc(xcoder_dev_count * + sizeof(char *)); + for (i = 0; i < xcoder_dev_count; i++) + { + g_xcoder_refresh_dev_names[i] = (char *)malloc(NI_MAX_DEVICE_NAME_LEN); + strcpy(g_xcoder_refresh_dev_names[i], xcoder_dev_names[i]); + } + g_xcoder_refresh_dev_count = xcoder_dev_count; + } curr_dev_count = ni_rsrc_get_local_device_list(curr_dev_names, NI_MAX_DEVICE_CNT); + if (0 == curr_dev_count) + { + ni_log(NI_LOG_ERROR, "No devices found on the host\n"); + } + int devices_removed = 0; + int devices_added = 0; // remove from resource pool any device that is not available now for (i = 0; i < xcoder_dev_count; i++) { @@ -203,6 +238,7 @@ ni_retcode_t ni_rsrc_refresh(int should_match_rev) { ni_log(NI_LOG_INFO, "%s deleted successfully !\n", xcoder_dev_names[i]); + devices_removed++; } else { ni_log(NI_LOG_ERROR, "%s failed to delete !\n", @@ -222,6 +258,7 @@ ni_retcode_t ni_rsrc_refresh(int should_match_rev) if (NI_RETCODE_SUCCESS == ni_rsrc_add_device(curr_dev_names[i], should_match_rev)) { + devices_added++; ni_log(NI_LOG_INFO, "%s added successfully !\n", curr_dev_names[i]); } else { @@ -230,6 +267,26 @@ ni_retcode_t ni_rsrc_refresh(int should_match_rev) } } + if (devices_added != devices_removed) + { + ni_log(NI_LOG_ERROR, "Total devices added %d removed %d\n",devices_added, + devices_removed); + for (i = 0; i < xcoder_dev_count; i++) + { + ni_log(NI_LOG_ERROR, "Previous device %s\n", xcoder_dev_names[i]); + } + for (i = 0; i < curr_dev_count; i++) + { + ni_log(NI_LOG_ERROR, "Current device %s\n", curr_dev_names[i]); + } + } + if (g_xcoder_refresh_dev_names) { + for (i = 0; i < g_xcoder_refresh_dev_count; i++) + free(g_xcoder_refresh_dev_names[i]); + free(g_xcoder_refresh_dev_names); + g_xcoder_refresh_dev_names = NULL; + g_xcoder_refresh_dev_count = 0; + } return NI_RETCODE_SUCCESS; } @@ -251,10 +308,10 @@ int ni_rsrc_android_init() { if (service == NULL) { - service = INidec::getService(); + service = INidec::tryGetService(); if (service == nullptr) { - ni_log(NI_LOG_ERROR, "ni_rsrc_android_init error\n"); + ni_log(NI_LOG_ERROR, "Failed to get Netint service, maybe it's not launched\n"); return -2; } } @@ -274,7 +331,7 @@ int ni_rsrc_android_init() * \param[out] ni_devices List of device names identified as NETINT NVMe transcoders * \param[in] max_handles Max number of device names to return * - * \return Number if devices found if successfull operation completed + * \return Number of devices found if successful operation completed * 0 if no NETINT NVMe transcoder devices were found * NI_RETCODE_ERROR_MEM_ALOC if memory allocation failed *******************************************************************************/ @@ -390,290 +447,43 @@ ni_device_pool_t* ni_rsrc_get_device_pool(void) *******************************************************************************/ int ni_rsrc_init(int should_match_rev, int timeout_seconds) { -#define SLEEPLOOP 3 - /*! list all XCoder devices under /dev/.. */ - char dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = { 0 }; - int i = 0, j = 0, k = 0, xcoder_device_cnt = 0, fw_ver_compat_warning = 0; - int runtime = 0; - DWORD rc = 0; - uint32_t tmp_io_size; - ni_retcode_t retval = NI_RETCODE_SUCCESS; - ni_device_info_t device_info = { 0 }; - ni_device_info_t* p_device_info = NULL; - ni_device_queue_t* p_device_queue = NULL; - HANDLE lock = NULL; - HANDLE map_file_handle = NULL; - ni_device_capability_t device_capabilites = { 0 }; - ni_device_handle_t handle; - uint32_t xcoder_guid[NI_DEVICE_TYPE_XCODER_MAX] = {0}; - - map_file_handle = CreateFileMapping( - INVALID_HANDLE_VALUE, // use paging file - NULL, // default security - PAGE_READWRITE, // read/write access - 0, // maximum object size (high-order DWORD) - sizeof(ni_device_queue_t),// maximum object size (low-order DWORD) - CODERS_SHM_NAME // name of mapping object - ); - - if (NULL == map_file_handle) - { - rc = NI_ERRNO; - ni_log(NI_LOG_ERROR, "ERROR: CreateFileMapping returned: %d\n", rc); - return NI_RETCODE_FAILURE; - } - else - { - rc = NI_ERRNO; - if (ERROR_ALREADY_EXISTS == rc) - { - ni_log(NI_LOG_INFO, "NETINT resources have been initialized already, exiting ..\n"); - CloseHandle(map_file_handle); - return NI_RETCODE_SUCCESS; - } - else - { - ni_log(NI_LOG_INFO, "NETINT resources not initialized, starting initialization ..\n"); - } - } - - while (0 == xcoder_device_cnt) - { - xcoder_device_cnt = ni_rsrc_enumerate_devices(dev_names, NI_MAX_DEVICE_CNT); - - if (NI_RETCODE_ERROR_MEM_ALOC == xcoder_device_cnt) - { - ni_log(NI_LOG_FATAL, "FATAL: memory allocation failed\n"); - CloseHandle(map_file_handle); - return NI_RETCODE_FAILURE; - } - else if (0 == xcoder_device_cnt) - { - ni_log(NI_LOG_INFO, "NVMe Devices not ready, will retry again ...\n"); - if (g_xcoder_stop_process) - { - ni_log(NI_LOG_ERROR, "Requested to stop, exiting ...\n"); - CloseHandle(map_file_handle); - return NI_RETCODE_FAILURE; - } - runtime += SLEEPLOOP; - Sleep(SLEEPLOOP * 1000); - if (runtime >= timeout_seconds && timeout_seconds != 0) - { - ni_log(NI_LOG_ERROR, "Timeout reached at %d seconds! Failing\n", - runtime); - CloseHandle(map_file_handle); - return NI_RETCODE_FAILURE; - } - } - } - - /*! store the guid and number of coders in a shared memory too, - for later retrieval; the guid order is init'd based on value here, - and will be re-ordered based on resource distribution logic in - resource allocation functions */ - - - p_device_queue = (ni_device_queue_t*)MapViewOfFile( - map_file_handle, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - sizeof(ni_device_queue_t) - ); - - if (NULL == p_device_queue) - { - ni_log(NI_LOG_ERROR, "Could not map view of file, p_last error (%d).\n", - NI_ERRNO); - CloseHandle(map_file_handle); - return NI_RETCODE_FAILURE; - } - - lock = CreateMutex(NULL, FALSE, CODERS_LCK_NAME); - if (NULL == lock) - { - ni_log(NI_LOG_ERROR, "Init CreateMutex %s failed: %d\n", CODERS_LCK_NAME, - NI_ERRNO); - CloseHandle(map_file_handle); - return NI_RETCODE_FAILURE; - } - - if (WAIT_ABANDONED == WaitForSingleObject(lock, INFINITE)) - { - ni_log(NI_LOG_ERROR, "ERROR %d: failed to obtain mutex: %p\n", - NI_ERRNO, lock); - CloseHandle(map_file_handle); - return NI_RETCODE_FAILURE; - } - - // init the ni_device_queue_t - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - p_device_queue->xcoder_cnt[k] = 0; - for (i = 0; i < NI_MAX_DEVICE_CNT; i++) - { - p_device_queue->xcoders[k][i] = -1; - } - } - - for (i = 0; i < xcoder_device_cnt; i++) - { - - /*! retrieve decoder and encoder info and create shared memory - and named lock accordingly, using NVMe "Identify Controller" */ - /*! check whether Xcoder is supported and retrieve the xcoder info */ - int ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN, "%s", - dev_names[i]); - if (ret < 0) + char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = { 0 }; + char api_version[5]; + int number_of_devices = 0; + int runtime = 0; + while (0 == number_of_devices) { - return -1; - } - memset(&device_capabilites, 0, sizeof(ni_device_capability_t)); - - handle = ni_device_open(device_info.dev_name, &tmp_io_size); - if (NI_INVALID_DEVICE_HANDLE == handle) - { - continue; - } - - retval = ni_device_capability_query(handle, &device_capabilites); - if ((NI_RETCODE_SUCCESS == retval) && - (is_supported_xcoder(device_capabilites.device_is_xcoder)) && - (!should_match_rev || ni_is_fw_compatible(device_capabilites.fw_rev))) - { - fw_ver_compat_warning = 0; - if (ni_is_fw_compatible(device_capabilites.fw_rev) == 2) - { - ni_log(NI_LOG_INFO, "WARNING - Query %s FW version: %.*s is below the minimum support version for " - "this SW version. Some features may be missing.\n", - device_info.dev_name, (int) sizeof(device_capabilites.fw_rev), - device_capabilites.fw_rev); - fw_ver_compat_warning = 1; - } - int total_modules = device_capabilites.xcoder_devices_cnt; + number_of_devices = ni_rsrc_get_local_device_list(device_names, NI_MAX_DEVICE_CNT); - for (j = 0; j < total_modules; j++) - { - p_device_info = NULL; - memset(&device_info, 0, sizeof(ni_device_info_t)); - ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN, "%s", - dev_names[i]); - if (ret < 0) - { - return -1; - } - - ni_find_blk_name(device_info.dev_name, device_info.blk_name, - sizeof(device_info.blk_name)); - device_info.hw_id = device_capabilites.xcoder_devices[j].hw_id; - device_info.fw_ver_compat_warning = fw_ver_compat_warning; - memcpy(device_info.serial_number, device_capabilites.serial_number, - sizeof(device_info.serial_number)); - memcpy(device_info.model_number, device_capabilites.model_number, - sizeof(device_info.model_number)); - memcpy(device_info.fw_rev, device_capabilites.fw_rev, - sizeof(device_info.fw_rev)); - memcpy(device_info.fw_branch_name, device_capabilites.fw_branch_name, - sizeof(device_info.fw_branch_name) - 1); - memcpy(device_info.fw_commit_time, device_capabilites.fw_commit_time, - sizeof(device_info.fw_commit_time) - 1); - memcpy(device_info.fw_commit_hash, device_capabilites.fw_commit_hash, - sizeof(device_info.fw_commit_hash) - 1); - memcpy(device_info.fw_build_time, device_capabilites.fw_build_time, - sizeof(device_info.fw_build_time) - 1); - memcpy(device_info.fw_build_id, device_capabilites.fw_build_id, - sizeof(device_info.fw_build_id) - 1); - - device_info.max_fps_4k = - device_capabilites.xcoder_devices[j].max_4k_fps; - device_info.max_instance_cnt = device_capabilites.xcoder_devices[j].max_number_of_contexts; - device_info.device_type = (ni_device_type_t)device_capabilites.xcoder_devices[j].codec_type; - - int device_cnt_so_far = - p_device_queue->xcoder_cnt[device_info.device_type]; - int tmp_guid = -1; - - // check if entry has been created for this h/w (hw_id): - // if not, then create a new entry; otherwise just update it - for (k = 0; k < device_cnt_so_far; k++) - { - tmp_guid = p_device_queue->xcoders[device_info.device_type][k]; - ni_device_context_t *p_device_context = - ni_rsrc_get_device_context(device_info.device_type, tmp_guid); - if ((p_device_context) && - (strcmp(p_device_context->p_device_info->dev_name, - device_info.dev_name) == 0) && - (p_device_context->p_device_info->hw_id == device_info.hw_id)) - { - p_device_info = p_device_context->p_device_info; - break; - } - } - - ni_codec_t fmt = (ni_codec_t)device_capabilites.xcoder_devices[j].codec_format; - - if (p_device_info) + if (NI_RETCODE_ERROR_MEM_ALOC == number_of_devices) { - ni_log(NI_LOG_INFO, "%s h/w id %d update\n", - device_type_str[device_info.device_type], device_info.hw_id); - rc = ni_rsrc_fill_device_info( - p_device_info, fmt, device_info.device_type, - &device_capabilites.xcoder_devices[j]); + ni_log(NI_LOG_FATAL, "FATAL: memory allocation failed\n"); + return NI_RETCODE_FAILURE; } - else + else if (0 == number_of_devices) { - ni_log(NI_LOG_INFO, "%s h/w id %d create\n", - device_type_str[device_info.device_type], device_info.hw_id); - - p_device_info = &device_info; - - rc = ni_rsrc_fill_device_info( - p_device_info, fmt, device_info.device_type, - &device_capabilites.xcoder_devices[j]); - - if (NI_RETCODE_SUCCESS == rc) + ni_log(NI_LOG_INFO, "Quadra devices not ready\n"); + if (g_xcoder_stop_process) { - /*! add the h/w device_info entry */ - p_device_info->module_id = - xcoder_guid[device_info.device_type]++; - p_device_queue->xcoder_cnt[device_info.device_type] = - xcoder_guid[device_info.device_type]; - p_device_queue->xcoders[device_info.device_type] - [p_device_info->module_id] = - p_device_info->module_id; - ni_rsrc_get_one_device_info(&device_info); + ni_log(NI_LOG_ERROR, "User requested to stop checking\n"); + return NI_RETCODE_FAILURE; + } + runtime += 3; + Sleep(3 * 1000); + if (runtime >= timeout_seconds && timeout_seconds != 0) + { + ni_log(NI_LOG_ERROR, "Timeout reached at %d seconds! Failing\n", + runtime); + return NI_RETCODE_FAILURE; } } - } /*! for each device_info */ - } /*! if device supports xcoder */ - else - { - ni_log(NI_LOG_INFO, "Query %s rc %d NOT xcoder-support: %u, or mismatch " - "revision: %.*s; Not added\n", device_info.dev_name, retval, - device_capabilites.device_is_xcoder, - (int) sizeof(device_capabilites.fw_rev), - device_capabilites.fw_rev); } - ni_device_close(handle); - } /*! for each nvme device */ + ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + api_version); + ni_log(NI_LOG_INFO, "Compatible FW API version: %s\n", api_version); - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - p_device_queue->xcoder_cnt[k] = xcoder_guid[k]; - } - rc = NI_RETCODE_SUCCESS; - if (NULL != p_device_queue) - { - UnmapViewOfFile(p_device_queue); - } - if (NULL != lock) - { - ReleaseMutex(lock); - CloseHandle(lock); - } - return rc; + return ni_rsrc_init_priv(should_match_rev, number_of_devices, device_names); } @@ -794,40 +604,48 @@ ni_device_context_t* ni_rsrc_get_device_context(ni_device_type_t device_type, in } #elif __linux__ || __APPLE__ -jmp_buf shm_open_test_buf; - #if __APPLE__ #define DEV_NAME_PREFIX "rdisk" +#elif defined(XCODER_LINUX_VIRTIO_DRIVER_ENABLED) +#define DEV_NAME_PREFIX "vd" #else #define DEV_NAME_PREFIX "nvme" #endif /*!***************************************************************************** * \brief Scans system for all NVMe devices and returns the system device - * names to the user which were identified as NETINT transcoder deivices. - * Names are suitable for resource management api usage afterwards - * + * names to the user which were identified as NETINT transcoder + * devices. Names are suitable for resource management API usage + * afterwards * - * \param[out] ni_devices List of device names identified as NETINT NVMe - * transcoders - * \param[in] max_handles Max number of device names to return + * \param[out] ni_devices List of device names identified as NETINT NVMe + * transcoders + * \param[in] max_handles Max number of device names to return * - * \return Number if devices found if successfull operation completed - * 0 if no NETINT NVMe transcoder devices were found + * \return Number of devices found. 0 if unsucessful. ******************************************************************************/ -int ni_rsrc_get_local_device_list(char ni_devices[][NI_MAX_DEVICE_NAME_LEN], - int max_handles) +int ni_rsrc_get_local_device_list(char ni_devices[][NI_MAX_DEVICE_NAME_LEN], + int max_handles) { /* list all XCoder devices under /dev/.. */ +#ifdef _ANDROID +#define ANDROID_MAX_DIR_NUM 2 + int android_dir_num = 0; + const char* dir_name_array[ANDROID_MAX_DIR_NUM]; + dir_name_array[0] = "/dev"; + dir_name_array[1] = "/dev/block"; +#else const char* dir_name = "/dev"; - char dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]; - int i, num_dev = 0, xcoder_device_cnt = 0; +#endif + int i, xcoder_device_cnt = 0; DIR* FD; struct dirent* in_file; ni_device_info_t device_info; ni_device_capability_t device_capabilites; ni_device_handle_t dev_handle = NI_INVALID_DEVICE_HANDLE; ni_retcode_t rc; + uint32_t tmp_io_size; + g_device_in_ctxt = false; if ((ni_devices == NULL)||(max_handles == 0)) { @@ -835,76 +653,176 @@ int ni_rsrc_get_local_device_list(char ni_devices[][NI_MAX_DEVICE_NAME_LEN], return 0; } + int nvme_dev_cnt = 0; + char nvme_devices[200][NI_MAX_DEVICE_NAME_LEN]; + + regex_t regex; + // GNU ERE not support /d, use [0-9] or [[:digit:]] instead +#if __APPLE__ + const char *pattern = "^rdisk[0-9]+$"; +#elif defined(XCODER_LINUX_VIRTIO_DRIVER_ENABLED) + const char *pattern = "^vd[a-z]$"; +#else + const char *pattern = "^nvme[0-9]+(c[0-9]+)?n[0-9]+$"; +#endif + // Compile the regular expression + if(regcomp(®ex, pattern, REG_EXTENDED | REG_NOSUB)) { + ni_log(NI_LOG_ERROR, "Could not compile regex\n"); + return 0; + } + +#ifdef _ANDROID + //find XCoder devices in folders of dir_name_array until find in one folder + //or not find in any folders + while(xcoder_device_cnt == 0 && android_dir_num < ANDROID_MAX_DIR_NUM) + { + const char *dir_name = dir_name_array[android_dir_num]; + ++android_dir_num; + + nvme_dev_cnt = 0; + g_device_in_ctxt = false; + dev_handle = NI_INVALID_DEVICE_HANDLE; + // g_dev_handle = NI_INVALID_DEVICE_HANDLE; + size_t size_of_nvme_devices_x = sizeof(nvme_devices)/sizeof(nvme_devices[0]); + for(size_t dimx = 0; dimx < size_of_nvme_devices_x; ++dimx) + { + memset(nvme_devices[dimx], 0, sizeof(nvme_devices[0])); + } + //}//while brace below will end this +#endif + if (NULL == (FD = opendir(dir_name))) { + +#ifdef _ANDROID + ni_log(NI_LOG_INFO, "Failed to open directory %s\n", dir_name); + if(android_dir_num < ANDROID_MAX_DIR_NUM) + { + continue; + } + regfree(®ex); + return 0; +#else ni_log(NI_LOG_ERROR, "ERROR: failed to open directory %s\n", dir_name); + regfree(®ex); return 0; +#endif } /* collect all the available NVMe devices and sort */ while ((in_file = readdir(FD))) { - /*! skip current and parent directory */ - if (!strcmp(in_file->d_name, ".") || !strcmp(in_file->d_name, "..")) - { - continue; - } + /*! skip current and parent directory */ + if (!strcmp(in_file->d_name, ".") || !strcmp(in_file->d_name, "..")) + { + continue; + } - /* pick only those files with name nvmeX where X consists of 1-n - digits */ - size_t lenstr = strlen(in_file->d_name); - if (!strncmp(in_file->d_name, DEV_NAME_PREFIX, strlen(DEV_NAME_PREFIX))) - { - for (i = strlen(DEV_NAME_PREFIX); i < lenstr; i++) + /* pick only those files with name nvmeX where X consists of 1-n + digits */ + if (!strncmp(in_file->d_name, DEV_NAME_PREFIX, strlen(DEV_NAME_PREFIX))) { - if (!isdigit(in_file->d_name[i])) + if (nvme_dev_cnt < 200) { - goto read_next; + int write_len = snprintf(nvme_devices[nvme_dev_cnt], + NI_MAX_DEVICE_NAME_LEN - 6, "%s/%s", + dir_name, in_file->d_name); + if (write_len < 0 || write_len >= (NI_MAX_DEVICE_NAME_LEN - 6)) + { + ni_log(NI_LOG_ERROR, + "ERROR: failed to copy device %d name %s\n", + nvme_dev_cnt, in_file->d_name); + } + nvme_dev_cnt++; } - } + int skip_this = 0; + skip_this = regexec(®ex, in_file->d_name, 0, NULL, 0); + ni_log(NI_LOG_TRACE, "name: %s skip %d\n", in_file->d_name, skip_this); - strcpy(dev_names[num_dev], in_file->d_name); - num_dev++; - read_next: ; - } - } - closedir(FD); + if (!skip_this) + { + memset(&device_info, 0, sizeof(ni_device_info_t)); + if (snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN - 6, + "%s/%s", dir_name, in_file->d_name) < 0) + { + ni_log(NI_LOG_ERROR, + "ERROR: failed an snprintf() in " + "ni_rsrc_get_local_device_list()\n"); + continue; + } + strncpy(device_info.blk_name, device_info.dev_name, + NI_MAX_DEVICE_NAME_LEN); + memset(&device_capabilites, 0, sizeof(ni_device_capability_t)); - if (num_dev) - { - qsort(dev_names, num_dev, sizeof(dev_names[0]), ni_rsrc_strcmp); + g_device_in_ctxt = false; + for (int j = 0; j < g_xcoder_refresh_dev_count; j++) + { + if (0 == + strcmp(device_info.dev_name, + g_xcoder_refresh_dev_names[j])) + { + g_device_in_ctxt = true; + break; + } + } + if (NI_RETCODE_SUCCESS != ni_check_dev_name(device_info.dev_name)) + { + continue; + } + dev_handle = ni_device_open(device_info.dev_name, &tmp_io_size); - uint32_t tmp_io_size; - for (i = 0; i < num_dev; i++) - { - memset(&device_info, 0, sizeof(ni_device_info_t)); - int ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN - 6, - "/dev/%s", dev_names[i]); - if (ret < 0) + if (NI_INVALID_DEVICE_HANDLE != dev_handle) + { + g_dev_handle = dev_handle; + rc = ni_device_capability_query(dev_handle, + &device_capabilites); + if (NI_RETCODE_SUCCESS == rc) + { + if (is_supported_xcoder( + device_capabilites.device_is_xcoder)) + { + ni_devices[xcoder_device_cnt][0] = '\0'; + strcat(ni_devices[xcoder_device_cnt], + device_info.dev_name); + xcoder_device_cnt++; + } + } + g_dev_handle = NI_INVALID_DEVICE_HANDLE; + + ni_device_close(dev_handle); + } + } + } + if ((NI_MAX_DEVICE_CNT <= xcoder_device_cnt) || + (max_handles <= xcoder_device_cnt)) { - return -1; + ni_log(NI_LOG_ERROR, + "Disregarding some Netint devices on system over " + "limit of NI_MAX_DEVICE_CNT(%d) or max_handles(%d)\n", + NI_MAX_DEVICE_CNT, max_handles); + break; } - memset(&device_capabilites, 0, sizeof(ni_device_capability_t)); + } + closedir(FD); - ni_find_blk_name(device_info.dev_name, device_info.blk_name, sizeof(device_info.blk_name)); - dev_handle = ni_device_open(device_info.blk_name, &tmp_io_size); +#ifdef _ANDROID + }//while brace +#endif - if (NI_INVALID_DEVICE_HANDLE != dev_handle) + regfree(®ex); + + qsort(ni_devices, xcoder_device_cnt, (size_t)NI_MAX_DEVICE_NAME_LEN, + ni_rsrc_strcmp); + if (0 == xcoder_device_cnt) + { + ni_log(NI_LOG_INFO, "Found %d NVMe devices on system, none of them xcoder\n", nvme_dev_cnt); + for (i = 0; i < nvme_dev_cnt; i++) { - rc = ni_device_capability_query(dev_handle,&device_capabilites); - if (NI_RETCODE_SUCCESS == rc) - { - if (is_supported_xcoder(device_capabilites.device_is_xcoder)) - { - ni_devices[xcoder_device_cnt][0] = '\0'; - strcat(ni_devices[xcoder_device_cnt], device_info.dev_name); - xcoder_device_cnt++; - } - } - ni_device_close(dev_handle); + ni_log(NI_LOG_INFO, "NVMe device %d: %s\n", i, nvme_devices[i]); } - } } + g_device_in_ctxt = false; + g_dev_handle = NI_INVALID_DEVICE_HANDLE; return xcoder_device_cnt; } @@ -918,7 +836,7 @@ int ni_rsrc_get_local_device_list(char ni_devices[][NI_MAX_DEVICE_NAME_LEN], *******************************************************************************/ ni_device_pool_t* ni_rsrc_get_device_pool(void) { - int shm_fd = 0; + int shm_fd = -1; ni_device_queue_t* p_device_queue = NULL; ni_lock_handle_t lock; ni_device_pool_t* p_device_pool = NULL; @@ -944,7 +862,24 @@ ni_device_pool_t* ni_rsrc_get_device_pool(void) strerror(NI_ERRNO)); return NULL; } - lockf(lock, F_LOCK, 0); + + int retry_cnt = 0; + //use non blocking F_TLOCK in case broken instance has indefinitely locked it + while (lockf(lock, F_TLOCK, 0) != 0) + { + retry_cnt++; + ni_usleep(LOCK_WAIT); //10ms + if (retry_cnt >= 900) //9s + { + ni_log(NI_LOG_ERROR, "ERROR %s() lockf() CODERS_LCK_NAME: %s\n", + __func__, strerror(NI_ERRNO)); + ni_log(NI_LOG_ERROR, "ERROR %s() If persists, stop traffic and run rm /dev/shm/NI_*\n", + __func__); + close(lock); + return NULL; + } + } + #ifdef _ANDROID /*! return if init has already been done */ @@ -975,14 +910,15 @@ ni_device_pool_t* ni_rsrc_get_device_pool(void) ni_log(NI_LOG_ERROR, "service->GetAppFlag ret failed ..\n"); LRETURN; } - if (shm_fd <= 0) + if (shm_fd < 0) { - shm_fd = ashmem_create_region(CODERS_SHM_NAME, sizeof(ni_device_queue_t)); - if (shm_fd >= 0) + int fd = ashmem_create_region(CODERS_SHM_NAME, sizeof(ni_device_queue_t)); + if (fd >= 0) { native_handle_t *handle = native_handle_create(1, 0); - handle->data[0] = shm_fd; + handle->data[0] = fd; service->SetAppFlag(param, handle); + shm_fd = dup(fd); ni_log(NI_LOG_ERROR, "Create shm fd %d\n", shm_fd); } } @@ -1020,217 +956,153 @@ ni_device_pool_t* ni_rsrc_get_device_pool(void) } END: + lockf(lock, F_ULOCK, 0); - lockf(lock, F_ULOCK, 0); + if (NULL == p_device_pool) + { + close(lock); + } - if (NULL == p_device_pool) - { - close(lock); - } -#ifndef _ANDROID + if (shm_fd >= 0) + { close(shm_fd); -#endif + } - return p_device_pool; + return p_device_pool; } -#ifndef _ANDROID - /*!****************************************************************************** - * \brief This function handles SIGBUS signal, it restores the stack and - * jumps back. - * - * \param[in] sig Signal to be handled - * - * \return - * none + * \brief Initialize and create all resources required to work with NETINT NVMe + * transcoder devices. This is a high level API function which is used + * mostly with user application like FFMpeg that relies on those resources. + * In case of custom application integration, revised functionality might + * be necessary utilizing corresponding API functions. * - *******************************************************************************/ -static void handle_sigbus(int sig) -{ - siglongjmp(shm_open_test_buf, sig); -} - -static void rm_shm_files() -{ - // remove shm files - // Q058279 verifies that these dont exist - int temp_ret = system("rm -f " LOCK_DIR "/NI_SHM_CODERS"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_LCK_CODERS"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_RETRY_LCK_DECODERS"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_RETRY_LCK_SCALERS"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_RETRY_LCK_ENCODERS"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_RETRY_LCK_AI"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_lck_*"); - (void)temp_ret; - temp_ret = system("rm -f " LOCK_DIR "/NI_shm_*"); - (void)temp_ret; -} - -/*!****************************************************************************** - * \brief This function sets up a SIGBUS handler, opens the the file and - * does a test. If the read results in SIGBUS the handler - * cleans up the LOCK_DIR + * \param[in] should_match_rev 0: transcoder firmware revision matching the + * library's version is NOT required for placing + * the transcoder into resource pool; 1: otherwise + * timeout_seconds 0: No timeout amount, loop until init success + * or fail; else: timeout will fail init once reached * * \return - * file descriptor on success + * NI_RETCODE_SUCCESS on success * NI_RETCODE_FAILURE on failure * *******************************************************************************/ -static int shm_open_and_test() +int ni_rsrc_init(int should_match_rev, int timeout_seconds) { - struct sigaction new_act, old_act; - bool pool_locked = false; - int cleanup = 0; - // save the old handler - sigaction(SIGINT, NULL, &old_act); - - new_act.sa_handler = &handle_sigbus; - new_act.sa_flags = SA_NODEFER; - sigemptyset(&new_act.sa_mask); - // assign the new handler - sigaction(SIGBUS, &new_act, NULL); - - int shm_fd = shm_open(CODERS_SHM_NAME, O_RDWR, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (shm_fd < 0) - { - // restore the old handler - sigaction(SIGBUS, &old_act, NULL); - return shm_fd; - } - ni_device_pool_t *p_device_pool = NULL; - p_device_pool = ni_rsrc_get_device_pool(); - if (NULL == p_device_pool) + char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]; + char api_version[5]; + int number_of_devices; + int runtime; + + runtime = 0; + while (1) { - // restore the old handler - sigaction(SIGBUS, &old_act, NULL); - return NI_RETCODE_FAILURE; + number_of_devices = ni_rsrc_get_local_device_list(device_names, + NI_MAX_DEVICE_CNT); + if (number_of_devices > 0) + { + break; + } + else + { + ni_log(NI_LOG_INFO, "Quadra devices not ready\n"); + if (g_xcoder_stop_process) + { + ni_log(NI_LOG_ERROR, "User requested to stop checking\n"); + return 1; + } + + sleep(3); + runtime += 3; + if (runtime > timeout_seconds) + { + ni_log(NI_LOG_ERROR, + "Timeout exceeded/reached after %u seconds!\n", + runtime); + return 1; + } + } } - lockf(p_device_pool->lock, F_LOCK, 0); - pool_locked = true; + ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + api_version); + ni_log(NI_LOG_INFO, "Compatible FW API version: %s\n", api_version); - ni_device_queue_t *p_device_queue = NULL; - p_device_queue = p_device_pool->p_device_queue; - - // test the file and sig handle - if (0 == (cleanup = sigsetjmp(shm_open_test_buf, 0))) - { - //volatile to escape optimization, without this there were some hangs - //when reading the following field later - volatile int count = 0; - count = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_DECODER]; - cleanup |= count == 0 ? 1 : 0; - ni_log(NI_LOG_DEBUG, "DEBUG: Decoder cnt = %d/*\n", count); - - count = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; - cleanup |= count == 0 ? 1 : 0; - ni_log(NI_LOG_DEBUG, "DEBUG: Encoder cnt = %d/*\n", count); - - count = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_SCALER]; - cleanup |= count == 0 ? 1 : 0; - ni_log(NI_LOG_DEBUG, "DEBUG: Scaler cnt = %d/*\n", count); - - count = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_AI]; - cleanup |= count == 0 ? 1 : 0; - ni_log(NI_LOG_DEBUG, "DEBUG: AI cnt = %d/*\n", count); - - count = p_device_queue->xcoders[NI_DEVICE_TYPE_AI][NI_MAX_DEVICE_CNT-1]; - (void)count; - } - if (1 == cleanup) - { - ni_log(NI_LOG_ERROR, "ERROR: Caught a SIGBUS or invalid device count! Removing files in %s/*\n", - LOCK_DIR); - lockf(p_device_pool->lock, F_ULOCK, 0); - pool_locked = false; - close(shm_fd); - rm_shm_files(); - - // call again to set errno - shm_fd = shm_open(CODERS_SHM_NAME, O_RDWR, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - } - // restore the old handler - sigaction(SIGBUS, &old_act, NULL); - - if (true == pool_locked) - { - lockf(p_device_pool->lock, F_ULOCK, 0); - } - ni_rsrc_free_device_pool(p_device_pool); - - return shm_fd; + return ni_rsrc_init_priv(should_match_rev, number_of_devices, device_names); } -#endif /*!****************************************************************************** - * \brief Initialize and create all resources required to work with NETINT NVMe - * transcoder devices. This is a high level API function which is used - * mostly with user application like FFMpeg that relies on those resources. - * In case of custom application integration, revised functionality might - * be necessary utilizing corresponding API functions. - * - * \param[in] should_match_rev 0: transcoder firmware revision matching the - * library's version is NOT required for placing - * the transcoder into resource pool; 1: otherwise - * timeout_seconds 0: No timeout amount, loop until init success - * or fail; else: timeout will fail init once reached - * - * \return - * NI_RETCODE_SUCCESS on success - * NI_RETCODE_FAILURE on failure - * - *******************************************************************************/ -int ni_rsrc_init(int should_match_rev, int timeout_seconds) +* \brief Allocates and returns a pointer to ni_device_context_t struct +* based on provided device_type and guid. +* To be used for load update and codec query. +* + * \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER + * \param[in] guid GUID of the encoder or decoder device +* +* \return pointer to ni_device_context_t if found, NULL otherwise +* +* Note: The returned ni_device_context_t content is not supposed to be used by +* caller directly: should only be passed to API in the subsequent +* calls; also after its use, the context should be released by +* calling ni_rsrc_free_device_context. +*******************************************************************************/ +ni_device_context_t* ni_rsrc_get_device_context(ni_device_type_t device_type, int guid) { -#define SLEEPLOOP 3 - /*! list all XCoder devices under /dev/.. */ - const char* dir_name = "/dev"; - char dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = {0}; - int i, j, k, num_dev = 0, xcoder_device_cnt = 0, fw_ver_compat_warning = 0; - int ret = 0; - int runtime = 0; - DIR* FD; - struct dirent* in_file; - ni_device_info_t device_info; - ni_device_queue_t* p_device_queue; - ni_lock_handle_t lock = NI_INVALID_DEVICE_HANDLE; - ni_lock_handle_t lockxc = NI_INVALID_DEVICE_HANDLE; - ni_device_handle_t dev_handle = NI_INVALID_DEVICE_HANDLE; - ni_device_capability_t device_capabilites; - ni_retcode_t rc; - uint32_t xcoder_guid[NI_DEVICE_TYPE_XCODER_MAX] = {0}; + /*! get names of shared mem and lock by GUID */ + int shm_fd = -1; + int lock; + char shm_name[32] = { 0 }; + char lck_name[32] = { 0 }; + ni_device_context_t *p_device_context = NULL; + ni_device_info_t *p_device_queue = NULL; + + ni_rsrc_get_shm_name(device_type, guid, shm_name, sizeof(shm_name)); + ni_rsrc_get_lock_name(device_type, guid, lck_name, sizeof(lck_name)); - /*! return if init has already been done */ #ifdef _ANDROID - ret = ni_rsrc_android_init(); + lock = + open(lck_name, O_CREAT | O_RDWR | O_CLOEXEC, S_IRWXU | S_IRWXG | S_IRWXO); +#else + lock = + open(lck_name, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +#endif + if (lock < 1) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() open() %s: %s\n", __func__, lck_name, + strerror(NI_ERRNO)); + return NULL; + } - if (0 != access(LOCK_DIR, 0)) + int retry_cnt = 0; + //use non blocking F_TLOCK in case broken instance has indefinitely locked it + while (lockf(lock, F_TLOCK, 0) != 0) { - if (0 != mkdir(LOCK_DIR, 777)) - { - ni_log(NI_LOG_ERROR, "ERROR: Could not create the %s directory", - LOCK_DIR); - return 1; - } + retry_cnt++; + ni_usleep(LOCK_WAIT); //10ms + if (retry_cnt >= 900) //10s + { + ni_log(NI_LOG_ERROR, "ERROR %s() lockf() %s: %s\n", __func__, + lck_name, strerror(NI_ERRNO)); + ni_log( + NI_LOG_ERROR, + "ERROR %s() If persists, stop traffic and run rm /dev/shm/NI_*\n", + __func__); + close(lock); + return NULL; + } } +#ifdef _ANDROID + int ret = ni_rsrc_android_init(); if (service == NULL) { - ni_log(NI_LOG_ERROR, "ni_rsrc_init 000 Error service ..\n"); - return NI_RETCODE_FAILURE; + ni_log(NI_LOG_ERROR, "ni_rsrc_get_device_context Error service ..\n"); + return NULL; } - int32_t shm_fd = 0; - string param = CODERS_SHM_NAME; + string param = shm_name; Return retvalue = service->GetAppFlag(param, [&](int32_t ret, hidl_handle handle) { ni_log(NI_LOG_INFO, "GetAppFlag: ret %d\n", ret); @@ -1244,794 +1116,292 @@ int ni_rsrc_init(int should_match_rev, int timeout_seconds) NI_ERRNO); } }); + if (!retvalue.isOk()) { ni_log(NI_LOG_ERROR, "service->GetAppFlag ret failed ..\n"); - return NI_RETCODE_FAILURE; + LRETURN; } - if (shm_fd <= 0) + + if (shm_fd < 0) { - shm_fd = ashmem_create_region(CODERS_SHM_NAME, sizeof(ni_device_queue_t)); - if (shm_fd >= 0) + int fd = ashmem_create_region(shm_name, sizeof(ni_device_info_t)); + if (fd >= 0) { native_handle_t *handle = native_handle_create(1, 0); - handle->data[0] = shm_fd; + handle->data[0] = fd; service->SetAppFlag(param, handle); + shm_fd = dup(fd); ni_log(NI_LOG_ERROR, "Create shm fd %d\n", shm_fd); } } #else - int shm_fd = shm_open_and_test(); - if (shm_fd >= 0) + shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +#endif + if (shm_fd < 0) { - ni_log(NI_LOG_INFO, "NI resource init'd already ..\n"); - close(shm_fd); - return 0; + ni_log(NI_LOG_ERROR, "ERROR %s() shm_open() %s: %s\n", __func__, shm_name, + strerror(NI_ERRNO)); + LRETURN; } - else + + p_device_queue = (ni_device_info_t *)mmap(0, sizeof(ni_device_info_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + if (MAP_FAILED == p_device_queue) { - if (ENOENT == NI_ERRNO) - { - ni_log(NI_LOG_INFO, "NI resource not init'd, continue ..\n"); - } - else - { - ni_log(NI_LOG_ERROR, "ERROR: cannot access NI resources: %s\n", - strerror(NI_ERRNO)); - return 1; - } + ni_log(NI_LOG_ERROR, "ERROR %s() mmap() ni_device_info_t: %s\n", __func__, + strerror(NI_ERRNO)); + LRETURN; } -#endif -read_dev_files: - num_dev = 0; - - if (NULL == (FD = opendir(dir_name))) + p_device_context = (ni_device_context_t *)malloc(sizeof(ni_device_context_t)); + if (!p_device_context) { - ni_log(NI_LOG_ERROR, "ERROR: failed to open directory %s\n", dir_name); - return 1; + ni_log(NI_LOG_ERROR, "ERROR %s() malloc() ni_device_context_t: %s\n", + __func__, strerror(NI_ERRNO)); + munmap((void *)p_device_queue, sizeof(ni_device_info_t)); + LRETURN; } - /*! collect all the available NVMe devices and sort */ - - while ((in_file = readdir(FD))) - { - /*! skip current and parent directory */ - if (!strcmp(in_file->d_name, ".") || !strcmp(in_file->d_name, "..")) - { - continue; - } + strncpy(p_device_context->shm_name, shm_name, sizeof(p_device_context->shm_name)); + p_device_context->lock = lock; + p_device_context->p_device_info = p_device_queue; - /*! pick only those files with name nvmeX where X consists of 1-n digits */ - size_t lenstr = strlen(in_file->d_name); - if (!strncmp(in_file->d_name, DEV_NAME_PREFIX, strlen(DEV_NAME_PREFIX))) - { - for (i = strlen(DEV_NAME_PREFIX); i < lenstr; i++) - { - if (!isdigit(in_file->d_name[i])) - { - goto read_next; - } - } +END: + lockf(lock, F_ULOCK, 0); - ni_log(NI_LOG_INFO, "Reading device file: %s\n", in_file->d_name); - strcpy(dev_names[num_dev], in_file->d_name); - num_dev++; - read_next:; - } - } - closedir(FD); - if (num_dev == 0) + if (shm_fd >= 0) { - ni_log(NI_LOG_INFO, "NVMe Devices not ready, wait ..\n"); - if (g_xcoder_stop_process) - { - ni_log(NI_LOG_ERROR, "Requested to stop ..\n"); - return 1; - } - - runtime += SLEEPLOOP; - sleep(SLEEPLOOP); - if (runtime >= timeout_seconds && timeout_seconds != 0) - { - ni_log(NI_LOG_ERROR, "Timeout reached at %d seconds! Failing\n", - runtime); - return 1; - } - goto read_dev_files; + close(shm_fd); } - qsort(dev_names, num_dev, sizeof(dev_names[0]), ni_rsrc_strcmp); + return p_device_context; +} +#endif - /*! go through the NVMe devices to check if there is any Xcoders with supported FW */ - ni_log(NI_LOG_INFO, "Compatible FW API ver: %c%c\n", - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], - NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX]); - xcoder_device_cnt = 0; - uint32_t tmp_io_size; - for (i = 0; i < num_dev; i++) +/*!****************************************************************************** + * \brief Free previously allocated device context + * + * \param p_device_context Pointer to previously allocated device context + * + * \return None + *******************************************************************************/ +void ni_rsrc_free_device_context(ni_device_context_t *p_device_context) +{ + if (p_device_context) { - memset(&device_info, 0, sizeof(ni_device_info_t)); - ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN - 6, "/dev/%s", - dev_names[i]); - if (ret < 0) - { - return -1; - } - memset(&device_capabilites, 0, sizeof(ni_device_capability_t)); - - ni_find_blk_name(device_info.dev_name, device_info.blk_name, sizeof(device_info.blk_name)); - ni_log(NI_LOG_INFO, "Block name %s\n", device_info.blk_name); - dev_handle = ni_device_open(device_info.blk_name, &tmp_io_size); +#ifdef _WIN32 + UnmapViewOfFile(p_device_context->p_device_info); + ReleaseMutex(p_device_context->lock); +#elif __linux__ || __APPLE__ + close(p_device_context->lock); + munmap((void *)p_device_context->p_device_info, sizeof(ni_device_info_t)); +#endif + free(p_device_context); + } +} - if (NI_INVALID_DEVICE_HANDLE != dev_handle) - { - rc = ni_device_capability_query(dev_handle, &device_capabilites); - if (NI_RETCODE_SUCCESS == rc) - { - if (is_supported_xcoder(device_capabilites.device_is_xcoder) && - (!should_match_rev || - ni_is_fw_compatible(device_capabilites.fw_rev))) - { - ni_log(NI_LOG_INFO, "%d. %s num_hw: %d\n", i + 1, device_info.dev_name, - device_capabilites.hw_elements_cnt); - xcoder_device_cnt++; - } else - { - ni_log(NI_LOG_INFO, "Device %s not added as it is not a supported " - "xcoder %u, or has incompatible FW rev: %.*s\n", - device_info.dev_name, device_capabilites.device_is_xcoder, - (int) sizeof(device_capabilites.fw_rev), - device_capabilites.fw_rev); - } - } +/*!****************************************************************************** +* \brief List device(s) based on device type with full information +* including s/w instances on the system. +* +* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +* \param[out] p_device The device information returned. +* \param[out] p_device_count The number of ni_device_info_t structs returned. +* +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_FAILURE +* +* Note: Caller is responsible for allocating memory for "p_device". +*******************************************************************************/ +ni_retcode_t ni_rsrc_list_devices(ni_device_type_t device_type, + ni_device_info_t *p_device_info, int * p_device_count) +{ + int i, count; + ni_device_queue_t *p_device_queue = NULL; + ni_device_pool_t *p_device_pool = NULL; + ni_device_context_t *p_device_context = NULL; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + bool b_release_pool_mtx = false; - ni_device_close(dev_handle); - } + if ( (NULL == p_device_info) || (NULL == p_device_count) ) + { + retval = NI_RETCODE_FAILURE; + LRETURN; } - if (0 == xcoder_device_cnt) + p_device_pool = ni_rsrc_get_device_pool(); + if (NULL == p_device_pool) { - ni_log(NI_LOG_INFO, "NVMe Devices supporting XCoder not ready, wait ..\n"); - if (g_xcoder_stop_process) - { - ni_log(NI_LOG_ERROR, "Requested to stop ..\n"); - return 1; - } - runtime += SLEEPLOOP; - sleep(SLEEPLOOP); - ni_log(NI_LOG_INFO, "runtime at %d seconds! Timeout at %d \n", runtime, timeout_seconds); - if (runtime >= timeout_seconds && timeout_seconds != 0) - { - ni_log(NI_LOG_ERROR, "Timeout reached at %d seconds! Failing\n", - runtime); - return 1; - } - - goto read_dev_files; + retval = NI_RETCODE_FAILURE; + LRETURN; } - /*! store the guid and number of coders in a shared memory too, - for later retrieval; the guid order is init'd based on value here, - and will be re-ordered based on resource distribution logic in - resource allocation functions */ - ni_log(NI_LOG_INFO, "Creating shm_name: %s lck_name: %s\n", - CODERS_SHM_NAME, CODERS_LCK_NAME); - -#ifdef _ANDROID - ret = ni_rsrc_android_init(); - if (service == NULL) +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) { - ni_log(NI_LOG_ERROR, "ni_rsrc_init 111 Error service ..\n"); - return NI_RETCODE_FAILURE; + ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_list_devices() failed to obtain " + "mutex: %p\n", p_device_pool->lock); + retval = NI_RETCODE_FAILURE; + LRETURN; } +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_LOCK, 0); +#endif - param = CODERS_SHM_NAME; - retvalue = service->GetAppFlag(param, [&](int32_t ret, hidl_handle handle) { - ni_log(NI_LOG_INFO, "GetAppFlag: ret %d\n", ret); - if (ret > 0) - { - shm_fd = dup(handle->data[0]); - ni_log(NI_LOG_INFO, "vendor:GetAppFlag shm_fd:%d\n", shm_fd); - } else - { - ni_log(NI_LOG_ERROR, "Error %d: shm_get shm_fd ..\n", - NI_ERRNO); - } - }); + b_release_pool_mtx = true; - if (!retvalue.isOk()) - { - ni_log(NI_LOG_ERROR, "service->GetAppFlag ret failed ..\n"); - return NI_RETCODE_FAILURE; - } + p_device_queue = p_device_pool->p_device_queue; + count = p_device_queue->xcoder_cnt[device_type]; - if (shm_fd <= 0) + *p_device_count=0; + for (i = 0; i < count; i++) { - shm_fd = ashmem_create_region(CODERS_SHM_NAME, sizeof(ni_device_queue_t)); - if (shm_fd >= 0) + int guid = -1; + guid = p_device_queue->xcoders[device_type][i]; + p_device_context = ni_rsrc_get_device_context(device_type, guid); + if (p_device_context) + { +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex { - native_handle_t *handle = native_handle_create(1, 0); - handle->data[0] = shm_fd; - service->SetAppFlag(param, handle); - ni_log(NI_LOG_ERROR, "Create shm fd %d\n", shm_fd); + ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_list_devices() failed to obtain " + "mutex: %p\n", p_device_context->lock); + ReleaseMutex(p_device_pool->lock); + retval = NI_RETCODE_FAILURE; + LRETURN; } - } -#else - shm_fd = shm_open(CODERS_SHM_NAME, O_CREAT | O_RDWR, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + memcpy(&p_device_info[i], p_device_context->p_device_info, sizeof(ni_device_info_t)); + ReleaseMutex(p_device_context->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_context->lock, F_LOCK, 0); + memcpy(&p_device_info[i], p_device_context->p_device_info, sizeof(ni_device_info_t)); + lockf(p_device_context->lock, F_ULOCK, 0); #endif - if (shm_fd < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s() shm_open() CODERS_SHM_NAME: %s\n", - __func__, strerror(NI_ERRNO)); - return 1; - } + ni_rsrc_free_device_context(p_device_context); -#ifndef _ANDROID - if (ftruncate(shm_fd, sizeof(ni_device_queue_t)) < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s() ftruncate() shm_fd: %s\n", __func__, - strerror(NI_ERRNO)); - close(shm_fd); - return 1; + (*p_device_count)++; + } + else + { + ni_log(NI_LOG_ERROR, "ERROR: cannot find decoder guid: %d\n", guid); + } } -#endif - p_device_queue = (ni_device_queue_t*)mmap(0, sizeof(ni_device_queue_t), PROT_READ | PROT_WRITE, - MAP_SHARED, shm_fd, 0); - if (MAP_FAILED == p_device_queue) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() mmap() ni_device_queue_t: %s\n", __func__, - strerror(NI_ERRNO)); - close(shm_fd); - return 1; - } +END: -#ifndef _ANDROID - close(shm_fd); + if (b_release_pool_mtx) + { +#ifdef _WIN32 + ReleaseMutex(p_device_pool->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_ULOCK, 0); #endif + } - /*! create the lock */ - lock = open(CODERS_LCK_NAME, O_RDWR | O_CREAT | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (lock < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s() open() CODERS_LCK_NAME: %s\n", __func__, - strerror(NI_ERRNO)); - munmap(p_device_queue, sizeof(ni_device_queue_t)); - return 1; - } + ni_rsrc_free_device_pool(p_device_pool); - // init the ni_device_queue_t - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - /*! create the lock for xcoder*/ - lockxc = open(XCODERS_RETRY_LCK_NAME[k], O_RDWR | O_CREAT | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (lockxc < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s() open() XCODERS_RETRY_LCK_NAME[%d]: " - "%s\n", __func__, k, strerror(NI_ERRNO)); - munmap(p_device_queue, sizeof(ni_device_queue_t)); - return 1; - } + return retval; +} - p_device_queue->xcoder_cnt[k] = 0; - for (i = 0; i < NI_MAX_DEVICE_CNT; i++) - { - p_device_queue->xcoders[k][i] = -1; - } - } +/*!****************************************************************************** +* \brief List all devices with full information including s/w instances +* on the system. - for (i = 0; i < num_dev; i++) - { - ni_log(NI_LOG_INFO, "%d. %s\n", i, dev_names[i]); +* \param[out] p_device The device information returned. +* +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_FAILURE +* +* Note: Caller is responsible for allocating memory for "p_device". +*******************************************************************************/ +ni_retcode_t ni_rsrc_list_all_devices(ni_device_t *p_device) +{ + int k = 0; + ni_retcode_t retval = NI_RETCODE_SUCCESS; - /*! retrieve decoder and encoder info and create shared memory - and named lock accordingly, using NVMe "Identify Controller" */ - /*! check whether Xcoder is supported and retrieve the xcoder info */ - ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN - 6, "/dev/%s", - dev_names[i]); - if (ret < 0) + if (NULL == p_device) { - return -1; + retval = NI_RETCODE_INVALID_PARAM; + LRETURN; } - memset(&device_capabilites, 0, sizeof(ni_device_capability_t)); - ni_find_blk_name(device_info.dev_name, device_info.blk_name, sizeof(device_info.blk_name)); - dev_handle = ni_device_open(device_info.blk_name, &tmp_io_size); - - if (NI_INVALID_DEVICE_HANDLE != dev_handle) + for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) { - rc = ni_device_capability_query(dev_handle, &device_capabilites); - if ((NI_RETCODE_SUCCESS == rc) && - (is_supported_xcoder(device_capabilites.device_is_xcoder)) && - (!should_match_rev || ni_is_fw_compatible(device_capabilites.fw_rev))) - { - fw_ver_compat_warning = 0; - if (ni_is_fw_compatible(device_capabilites.fw_rev) == 2) + retval = ni_rsrc_list_devices((ni_device_type_t)k, p_device->xcoders[k], + &(p_device->xcoder_cnt[k])); + if (NI_RETCODE_FAILURE == retval) { - ni_log(NI_LOG_INFO, "WARNING - Query %s %s FW version: %.*s is below " - "the minimum support version for this SW version. Some " - "features may be missing.\n", device_info.dev_name, - device_info.blk_name, (int) sizeof(device_capabilites.fw_rev), - device_capabilites.fw_rev); - fw_ver_compat_warning = 1; + ni_log(NI_LOG_ERROR, "ERROR: could not retrieve info for %d type " + "devices\n", k); + LRETURN; } - - int total_modules = device_capabilites.xcoder_devices_cnt; - - ni_device_info_t* p_device_info = NULL; - - for (j = 0; j < total_modules; j++) - { - p_device_info = NULL; - - memset(&device_info, 0, sizeof(ni_device_info_t)); - ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN - 6, - "/dev/%s", dev_names[i]); - if (ret < 0) - { - return -1; - } - ni_find_blk_name(device_info.dev_name, device_info.blk_name, sizeof(device_info.blk_name)); - - device_info.hw_id = device_capabilites.xcoder_devices[j].hw_id; - device_info.fw_ver_compat_warning = fw_ver_compat_warning; - memcpy(device_info.serial_number, device_capabilites.serial_number, - sizeof(device_info.serial_number)); - memcpy(device_info.model_number, device_capabilites.model_number, - sizeof(device_info.model_number)); - memcpy(device_info.fw_rev, device_capabilites.fw_rev, - sizeof(device_info.fw_rev)); - memcpy(device_info.fw_branch_name, device_capabilites.fw_branch_name, - sizeof(device_info.fw_branch_name) - 1); - memcpy(device_info.fw_commit_time, device_capabilites.fw_commit_time, - sizeof(device_info.fw_commit_time) - 1); - memcpy(device_info.fw_commit_hash, device_capabilites.fw_commit_hash, - sizeof(device_info.fw_commit_hash) - 1); - memcpy(device_info.fw_build_time, device_capabilites.fw_build_time, - sizeof(device_info.fw_build_time) - 1); - memcpy(device_info.fw_build_id, device_capabilites.fw_build_id, - sizeof(device_info.fw_build_id) - 1); - - device_info.max_fps_4k = - device_capabilites.xcoder_devices[j].max_4k_fps; - device_info.max_instance_cnt = device_capabilites.xcoder_devices[j].max_number_of_contexts; - device_info.device_type = (ni_device_type_t)device_capabilites.xcoder_devices[j].codec_type; - - int device_cnt_so_far = - p_device_queue->xcoder_cnt[device_info.device_type]; - int tmp_guid = -1; - // check if entry has been created for this h/w (hw_id): - // if not, then create a new entry; otherwise just update it - for (k = 0; k < device_cnt_so_far; k++) - { - tmp_guid = p_device_queue->xcoders[device_info.device_type][k]; - ni_device_context_t *p_device_context = - ni_rsrc_get_device_context(device_info.device_type, tmp_guid); - if (p_device_context && - strcmp(p_device_context->p_device_info->dev_name, - device_info.dev_name) == 0 && - p_device_context->p_device_info->hw_id == device_info.hw_id) - { - p_device_info = p_device_context->p_device_info; - break; - } - ni_rsrc_free_device_context(p_device_context); - } - - ni_codec_t fmt = (ni_codec_t)device_capabilites.xcoder_devices[j].codec_format; - - if (p_device_info) - { - ni_log(NI_LOG_INFO, "%s h/w id %d update\n", - device_type_str[device_info.device_type], - device_info.hw_id); - ni_rsrc_fill_device_info(p_device_info, fmt, - device_info.device_type, - &device_capabilites.xcoder_devices[j]); - } - else - { - ni_log(NI_LOG_INFO, "%s h/w id %d create\n", - device_type_str[device_info.device_type], - device_info.hw_id); - p_device_info = &device_info; - - rc = ni_rsrc_fill_device_info( - p_device_info, fmt, device_info.device_type, - &device_capabilites.xcoder_devices[j]); - - if (rc == 0) - { - /*! add the h/w device_info entry */ - p_device_info->module_id = - xcoder_guid[device_info.device_type]++; - p_device_queue->xcoder_cnt[device_info.device_type] = - xcoder_guid[device_info.device_type]; - p_device_queue->xcoders[device_info.device_type] - [p_device_info->module_id] = - p_device_info->module_id; - ni_rsrc_get_one_device_info(&device_info); - } - } - - } /*! for each device_info module */ - } /*! if device supports xcoder */ - else - { - ni_log(NI_LOG_INFO, "Device %s not added as %u is not a supported " - "xcoder, or has incompatible FW rev: %.*s\n", - device_info.dev_name, device_capabilites.device_is_xcoder, - (int) sizeof(device_capabilites.fw_rev), - device_capabilites.fw_rev); - } - - ni_device_close(dev_handle); } - } /*! for each nvme device */ - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - p_device_queue->xcoder_cnt[k] = xcoder_guid[k]; - } - return 0; +END: + + return retval; } /*!****************************************************************************** -* \brief Allocates and returns a pointer to ni_device_context_t struct -* based on provided device_type and guid. -* To be used for load update and codec query. -* - * \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER - * \param[in] guid GUID of the encoder or decoder device +* \brief Grabs information for every initialized and uninitialized +* device. + +* \param list_uninitialized Flag to determine if uninitialized devices +* should be grabbed. * -* \return pointer to ni_device_context_t if found, NULL otherwise +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_FAILURE * -* Note: The returned ni_device_context_t content is not supposed to be used by -* caller directly: should only be passed to API in the subsequent -* calls; also after its use, the context should be released by -* calling ni_rsrc_free_device_context. +* Note: Caller is responsible for allocating memory for "p_device". *******************************************************************************/ -ni_device_context_t* ni_rsrc_get_device_context(ni_device_type_t device_type, int guid) +ni_retcode_t ni_rsrc_list_all_devices2(ni_device_t* p_device, bool list_uninitialized) { - /*! get names of shared mem and lock by GUID */ - int shm_fd = 0; - int lock; - char shm_name[32] = { 0 }; - char lck_name[32] = { 0 }; - ni_device_context_t *p_device_context = NULL; - ni_device_info_t *p_device_queue = NULL; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + if (!p_device) + { + retval = NI_RETCODE_INVALID_PARAM; + return retval; + } - ni_rsrc_get_shm_name(device_type, guid, shm_name, sizeof(shm_name)); - ni_rsrc_get_lock_name(device_type, guid, lck_name, sizeof(lck_name)); + /* Grab initialized devices. */ -#ifdef _ANDROID - lock = - open(lck_name, O_CREAT | O_RDWR | O_CLOEXEC, S_IRWXU | S_IRWXG | S_IRWXO); -#else - lock = - open(lck_name, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); -#endif - if (lock < 1) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() open() %s: %s\n", __func__, lck_name, - strerror(NI_ERRNO)); - return NULL; - } + ni_log_level_t log_level = ni_log_get_level(); - lockf(lock, F_LOCK, 0); + if (list_uninitialized) + { + ni_log_set_level(NI_LOG_NONE); + } -#ifdef _ANDROID - int ret = ni_rsrc_android_init(); - if (service == NULL) - { - ni_log(NI_LOG_ERROR, "ni_rsrc_get_device_context Error service ..\n"); - return NULL; - } + ni_rsrc_list_all_devices(p_device); - string param = shm_name; - Return retvalue = - service->GetAppFlag(param, [&](int32_t ret, hidl_handle handle) { - ni_log(NI_LOG_INFO, "GetAppFlag: ret %d\n", ret); - if (ret > 0) - { - shm_fd = dup(handle->data[0]); - ni_log(NI_LOG_INFO, "vendor:GetAppFlag shm_fd:%d\n", shm_fd); - } else - { - ni_log(NI_LOG_ERROR, "Error %d: shm_get shm_fd ..\n", - NI_ERRNO); - } - }); + if (!list_uninitialized) + { + return retval; + } - if (!retvalue.isOk()) - { - ni_log(NI_LOG_ERROR, "service->GetAppFlag ret failed ..\n"); - LRETURN; - } + ni_log_set_level(log_level); - if (shm_fd <= 0) - { - shm_fd = ashmem_create_region(shm_name, sizeof(ni_device_info_t)); - if (shm_fd >= 0) - { - native_handle_t *handle = native_handle_create(1, 0); - handle->data[0] = shm_fd; - service->SetAppFlag(param, handle); - ni_log(NI_LOG_ERROR, "Create shm fd %d\n", shm_fd); - } - } -#else - shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); -#endif - if (shm_fd < 0) - { - ni_log(NI_LOG_ERROR, "ERROR %s() shm_open() %s: %s\n", __func__, shm_name, - strerror(NI_ERRNO)); - LRETURN; - } + /* Store device names of initialized devices. */ - p_device_queue = (ni_device_info_t *)mmap(0, sizeof(ni_device_info_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (MAP_FAILED == p_device_queue) - { - ni_log(NI_LOG_ERROR, "ERROR %s() mmap() ni_device_info_t: %s\n", __func__, - strerror(NI_ERRNO)); - LRETURN; - } + ni_device_info_t *p_dev_info; + char initialized_dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = {0}; - p_device_context = (ni_device_context_t *)malloc(sizeof(ni_device_context_t)); - if (!p_device_context) - { - ni_log(NI_LOG_ERROR, "ERROR %s() malloc() ni_device_context_t: %s\n", - __func__, strerror(NI_ERRNO)); - munmap((void *)p_device_queue, sizeof(ni_device_info_t)); - LRETURN; - } + for (int dev_index = 0; + dev_index < p_device->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; dev_index++) + { + p_dev_info = &p_device->xcoders[NI_DEVICE_TYPE_ENCODER][dev_index]; + strcpy(initialized_dev_names[dev_index], p_dev_info->dev_name); + } - strncpy(p_device_context->shm_name, shm_name, sizeof(shm_name)); - p_device_context->lock = lock; - p_device_context->p_device_info = p_device_queue; - -END: - - lockf(lock, F_ULOCK, 0); - -#ifndef _ANDROID - close(shm_fd); -#endif - - return p_device_context; -} -#endif - -/*!****************************************************************************** - * \brief Free previously allocated device context - * - * \param p_device_context Pointer to previously allocated device context - * - * \return None - *******************************************************************************/ -void ni_rsrc_free_device_context(ni_device_context_t *p_device_context) -{ - if (p_device_context) - { -#ifdef _WIN32 - UnmapViewOfFile(p_device_context->p_device_info); - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - close(p_device_context->lock); - munmap((void *)p_device_context->p_device_info, sizeof(ni_device_info_t)); -#endif - free(p_device_context); - } -} - -/*!****************************************************************************** -* \brief List device(s) based on device type with full information -* including s/w instances on the system. -* -* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[out] p_device The device information returned. -* \param[out] p_device_count The number of ni_device_info_t structs returned. -* -* \return -* NI_RETCODE_SUCCESS -* NI_RETCODE_FAILURE -* -* Note: Caller is responsible for allocating memory for "p_device". -*******************************************************************************/ -ni_retcode_t ni_rsrc_list_devices(ni_device_type_t device_type, - ni_device_info_t *p_device_info, int * p_device_count) -{ - int i, count; - ni_device_queue_t *p_device_queue = NULL; - ni_device_pool_t *p_device_pool = NULL; - ni_device_context_t *p_device_context = NULL; - ni_retcode_t retval = NI_RETCODE_SUCCESS; - bool b_release_pool_mtx = false; - - if ( (NULL == p_device_info) || (NULL == p_device_count) ) - { - retval = NI_RETCODE_FAILURE; - LRETURN; - } - - p_device_pool = ni_rsrc_get_device_pool(); - if (NULL == p_device_pool) - { - retval = NI_RETCODE_FAILURE; - LRETURN; - } - -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) - { - ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_list_devices() failed to obtain " - "mutex: %p\n", p_device_pool->lock); - retval = NI_RETCODE_FAILURE; - LRETURN; - } -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_LOCK, 0); -#endif - - b_release_pool_mtx = true; - - p_device_queue = p_device_pool->p_device_queue; - count = p_device_queue->xcoder_cnt[device_type]; - - *p_device_count=0; - for (i = 0; i < count; i++) - { - int guid = -1; - guid = p_device_queue->xcoders[device_type][i]; - p_device_context = ni_rsrc_get_device_context(device_type, guid); - if (p_device_context) - { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_list_devices() failed to obtain " - "mutex: %p\n", p_device_context->lock); - ReleaseMutex(p_device_pool->lock); - retval = NI_RETCODE_FAILURE; - LRETURN; - } - - memcpy(&p_device_info[i], p_device_context->p_device_info, sizeof(ni_device_info_t)); - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); - memcpy(&p_device_info[i], p_device_context->p_device_info, sizeof(ni_device_info_t)); - lockf(p_device_context->lock, F_ULOCK, 0); -#endif - - ni_rsrc_free_device_context(p_device_context); - - (*p_device_count)++; - } - else - { - ni_log(NI_LOG_ERROR, "ERROR: cannot find decoder guid: %d\n", guid); - } - } - -END: - - if (b_release_pool_mtx) - { -#ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_ULOCK, 0); -#endif - } - - ni_rsrc_free_device_pool(p_device_pool); - - return retval; -} - -/*!****************************************************************************** -* \brief List all devices with full information including s/w instances -* on the system. - -* \param[out] p_device The device information returned. -* -* \return -* NI_RETCODE_SUCCESS -* NI_RETCODE_INVALID_PARAM -* NI_RETCODE_FAILURE -* -* Note: Caller is responsible for allocating memory for "p_device". -*******************************************************************************/ -ni_retcode_t ni_rsrc_list_all_devices(ni_device_t *p_device) -{ - int k = 0; - ni_retcode_t retval = NI_RETCODE_SUCCESS; - - if (NULL == p_device) - { - retval = NI_RETCODE_INVALID_PARAM; - LRETURN; - } - - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - retval = ni_rsrc_list_devices((ni_device_type_t)k, p_device->xcoders[k], - &(p_device->xcoder_cnt[k])); - if (NI_RETCODE_FAILURE == retval) - { - ni_log(NI_LOG_ERROR, "ERROR: could not retrieve info for %d type " - "devices\n", k); - LRETURN; - } - } - -END: - - return retval; -} - -/*!****************************************************************************** -* \brief Grabs information for every initialized and uninitialized -* device. - -* \param list_uninitialized Flag to determine if uninitialized devices -* should be grabbed. -* -* \return -* NI_RETCODE_SUCCESS -* NI_RETCODE_INVALID_PARAM -* NI_RETCODE_FAILURE -* -* Note: Caller is responsible for allocating memory for "p_device". -*******************************************************************************/ -LIB_API ni_retcode_t ni_rsrc_list_all_devices2(ni_device_t* p_device, bool list_uninitialized) -{ - ni_retcode_t retval = NI_RETCODE_SUCCESS; - if (!p_device) - { - retval = NI_RETCODE_INVALID_PARAM; - return retval; - } - - /* Grab initialized devices. */ - - ni_log_level_t log_level = ni_log_get_level(); - - if (list_uninitialized) - { - ni_log_set_level(NI_LOG_NONE); - } - - ni_rsrc_list_all_devices(p_device); - - if (!list_uninitialized) - { - return retval; - } - - ni_log_set_level(log_level); - - /* Store device names of initialized devices. */ - - ni_device_info_t *p_dev_info; - char initialized_dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = {0}; - - for (int dev_index = 0; - dev_index < p_device->xcoder_cnt[NI_DEVICE_TYPE_DECODER]; dev_index++) - { - p_dev_info = &p_device->xcoders[NI_DEVICE_TYPE_DECODER][dev_index]; - strcpy(initialized_dev_names[dev_index], p_dev_info->dev_name); - } - - /* Retrieve uninitialized devices. */ + /* Retrieve uninitialized devices. */ char dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = {0}; int dev_count = ni_rsrc_get_local_device_list(dev_names, NI_MAX_DEVICE_CNT); @@ -2039,7 +1409,6 @@ LIB_API ni_retcode_t ni_rsrc_list_all_devices2(ni_device_t* p_device, bool list_ uint32_t tmp_io_size; ni_device_capability_t capability; ni_device_handle_t fd; - ni_device_info_t dev_info; for (int dev_index = 0; dev_index < dev_count; dev_index++) { @@ -2049,24 +1418,11 @@ LIB_API ni_retcode_t ni_rsrc_list_all_devices2(ni_device_t* p_device, bool list_ continue; } - memset(&dev_info, 0, sizeof(ni_device_info_t)); - - strcpy(dev_info.dev_name, dev_names[dev_index]); - - retval = ni_find_blk_name(dev_info.dev_name, dev_info.blk_name, - sizeof(dev_info.blk_name)); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, "Failed to find block device ID for %s\n", - dev_info.dev_name); - return retval; - } - - fd = ni_device_open(dev_info.blk_name, &tmp_io_size); + fd = ni_device_open(dev_names[dev_index], &tmp_io_size); if (NI_INVALID_DEVICE_HANDLE == fd) { ni_log(NI_LOG_ERROR, "Failed to open device: %s\n", - dev_info.dev_name); + dev_names[dev_index]); return NI_RETCODE_FAILURE; } @@ -2075,7 +1431,7 @@ LIB_API ni_retcode_t ni_rsrc_list_all_devices2(ni_device_t* p_device, bool list_ { ni_device_close(fd); ni_log(NI_LOG_ERROR, "Failed to query device capability: %s\n", - dev_info.dev_name); + dev_names[dev_index]); return retval; } @@ -2104,13 +1460,14 @@ LIB_API ni_retcode_t ni_rsrc_list_all_devices2(ni_device_t* p_device, bool list_ sizeof(capability.fw_build_time)); memcpy(p_dev_info->fw_build_id, capability.fw_build_id, sizeof(capability.fw_build_id)); - memcpy(p_dev_info->dev_name, dev_info.dev_name, - sizeof(dev_info.dev_name)); - memcpy(p_dev_info->blk_name, dev_info.blk_name, - sizeof(dev_info.blk_name)); + strcpy(p_dev_info->dev_name, dev_names[dev_index]); + memcpy(p_dev_info->blk_name, p_dev_info->dev_name, + sizeof(p_dev_info->dev_name)); p_dev_info->device_type = (ni_device_type_t)dev_type; p_dev_info->module_id = -1; /* special value to indicate device is not initialized */ + + ni_query_fl_fw_versions(fd, p_dev_info); } ni_device_close(fd); @@ -2130,7 +1487,7 @@ void ni_rsrc_print_device_info(const ni_device_info_t *p_device_info) } else { ni_log(NI_LOG_INFO, " %s #%d\n", - device_type_str[p_device_info->device_type], + GET_XCODER_DEVICE_TYPE_STR(p_device_info->device_type), p_device_info->module_id); ni_log(NI_LOG_INFO, " H/W ID: %d\n", p_device_info->hw_id); ni_log(NI_LOG_INFO, " MaxNumInstances: %d\n", @@ -2141,7 +1498,8 @@ void ni_rsrc_print_device_info(const ni_device_info_t *p_device_info) ni_log(NI_LOG_INFO, " Capabilities:\n"); ni_log(NI_LOG_INFO, " Operations: Crop (ni_quadra_crop), Scale (ni_quadra_scale), Pad " - "(ni_quadra_pad), Overlay (ni_quadra_overlay)\n"); + "(ni_quadra_pad), Overlay (ni_quadra_overlay)\n" + " Drawbox (ni_quadra_drawbox), Rotate (ni_quadra_rotate), XStack (ni_quadra_xstack)\n"); } else if (NI_DEVICE_TYPE_AI == p_device_info->device_type) { ni_log(NI_LOG_INFO, " Capabilities:\n"); @@ -2189,1569 +1547,2622 @@ void ni_rsrc_print_device_info(const ni_device_info_t *p_device_info) } } } -} - -/*!***************************************************************************** -* \brief Print detailed capability information of all devices -* on the system. +} + +/*!***************************************************************************** +* \brief Print detailed capability information of all devices +* on the system. + +* \param none +* +* \return none +* +*******************************************************************************/ +void ni_rsrc_print_all_devices_capability(void) +{ + ni_device_t *device = NULL; + device = (ni_device_t *)malloc(sizeof(ni_device_t)); + if (!device) + { + ni_log(NI_LOG_ERROR, "ERROR %s() failed to malloc memory: %s\n", + __func__, strerror(NI_ERRNO)); + return; + } + memset(device, 0, sizeof(ni_device_t)); + + if (NI_RETCODE_SUCCESS != ni_rsrc_list_all_devices(device)) + { + free(device); + return; + } + + print_device(device); + free(device); +} + +/*!***************************************************************************** +* \brief Prints detailed capability information for all initialized +* devices and general information about uninitialized devices. + +* \param list_uninitialized Flag to determine if uninitialized devices +* should be grabbed. +* +* \return none +* +*******************************************************************************/ +void ni_rsrc_print_all_devices_capability2(bool list_uninitialized) +{ + ni_device_t *device = NULL; + device = (ni_device_t *)malloc(sizeof(ni_device_t)); + if (!device) + { + ni_log(NI_LOG_ERROR, "ERROR %s() failed to malloc memory: %s\n", + __func__, strerror(NI_ERRNO)); + return; + } + memset(device, 0, sizeof(ni_device_t)); + + if (NI_RETCODE_SUCCESS != ni_rsrc_list_all_devices2(device, list_uninitialized)) + { + free(device); + return; + } + + print_device(device); + free(device); +} + +/*!****************************************************************************** +* \brief Query a specific device with detailed information on the system + +* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +* \param[in] guid unique device(decoder or encoder) id +* +* \return +* pointer to ni_device_info_t if found +* NULL otherwise +* +* Note: Caller is responsible for releasing memory that was allocated for the +* returned pointer +*******************************************************************************/ +ni_device_info_t *ni_rsrc_get_device_info(ni_device_type_t device_type, int guid) +{ + ni_device_info_t *p_device_info = NULL; + ni_device_context_t* p_device_context = NULL; + + p_device_context = ni_rsrc_get_device_context(device_type, guid); + if (NULL == p_device_context) + { + LRETURN; + } + + p_device_info = (ni_device_info_t *)malloc(sizeof(ni_device_info_t)); + if (NULL == p_device_info) + { + LRETURN; + } + +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex + { + ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_get_device_info() failed to obtain " + "mutex: %p\n", p_device_context->lock); + free(p_device_info); + LRETURN; + } + + memcpy(p_device_info, p_device_context->p_device_info, sizeof(ni_device_info_t)); + ReleaseMutex(p_device_context->lock); +#elif __linux + lockf(p_device_context->lock, F_LOCK, 0); + + memcpy(p_device_info, p_device_context->p_device_info, sizeof(ni_device_info_t)); + + lockf(p_device_context->lock, F_ULOCK, 0); +#endif + +END: + + ni_rsrc_free_device_context(p_device_context); + + return p_device_info; +} + +/*!**************************************************************************** +* \brief Get GUID of the device by block device name and type +* +* \param[in] blk_name device's block name +* \param[in] type device type +* +* \return device GUID (>= 0) if found, NI_RETCODE_FAILURE (-1) otherwise +*******************************************************************************/ +int ni_rsrc_get_device_by_block_name(const char *blk_name, + ni_device_type_t device_type) +{ + int i; + int guid = NI_RETCODE_FAILURE, tmp_id; + ni_device_pool_t *p_device_pool = NULL; + ni_device_context_t *p_device_context = NULL; + int num_coders = 0; + + //uploader shares instance with encoder + if(device_type == NI_DEVICE_TYPE_UPLOAD) + { + device_type = NI_DEVICE_TYPE_ENCODER; + } + + p_device_pool = ni_rsrc_get_device_pool(); + if (!p_device_pool) + { + ni_log(NI_LOG_ERROR, "ERROR: cannot get p_device_pool\n"); + return guid; + } + +#ifdef _WIN32 + // no time-out interval (we got the mutex) + if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) + { + ni_log(NI_LOG_ERROR, "ERROR: %s failed to obtain mutex: %p\n", + __FUNCTION__, p_device_pool->lock); + ni_rsrc_free_device_pool(p_device_pool); + return NI_RETCODE_FAILURE; + } +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_LOCK, 0); +#endif + + num_coders = p_device_pool->p_device_queue->xcoder_cnt[device_type]; + + for (i = 0; i < num_coders; i++) + { + tmp_id = p_device_pool->p_device_queue->xcoders[device_type][i]; + p_device_context = ni_rsrc_get_device_context(device_type, tmp_id); + + if (p_device_context && + 0 == strcmp(p_device_context->p_device_info->dev_name, blk_name)) + { + guid = p_device_context->p_device_info->module_id; + ni_rsrc_free_device_context(p_device_context); + break; + } + + ni_rsrc_free_device_context(p_device_context); + } + +#ifdef _WIN32 + ReleaseMutex(p_device_pool->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_ULOCK, 0); +#endif + + ni_rsrc_free_device_pool(p_device_pool); + + ni_log(NI_LOG_DEBUG, "%s %s got guid: %d\n", __FUNCTION__, blk_name, guid); + + return guid; +} + +/*!***************************************************************************** +* \brief Update the load value and s/w instances info of a specific decoder or +* encoder. This is used by resource management daemon to update periodically. +* +* \param[in] p_ctxt The device context returned by ni_rsrc_get_device_context +* \param[in] p_load The latest load value to update +* \param[in] sw_instance_cnt Number of s/w instances +* \param[in] sw_instance_info Info of s/w instances +* +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_FAILURE +*******************************************************************************/ +int ni_rsrc_update_device_load(ni_device_context_t *p_device_context, int load, + int sw_instance_cnt, const ni_sw_instance_info_t sw_instance_info[]) +{ + int i; + if (!p_device_context || !sw_instance_info) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() invalid input pointers\n", __func__); + return NI_RETCODE_FAILURE; + } + +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex + { + ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", + __func__, p_device_context->lock); + return NI_RETCODE_FAILURE; + } +#elif __linux__ || __APPLE__ + lockf(p_device_context->lock, F_LOCK, 0); +#endif + + p_device_context->p_device_info->load = load; + p_device_context->p_device_info->active_num_inst = sw_instance_cnt; + for (i = 0; i < sw_instance_cnt; i++) + { + p_device_context->p_device_info->sw_instance[i] = sw_instance_info[i]; + } + +#ifdef _WIN32 + ReleaseMutex(p_device_context->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_context->lock, F_ULOCK, 0); +#endif + + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** +* \brief Allocate resources for decoding/encoding, by designating explicitly +* the device to use. do not track the load on the host side +* +* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +* \param[in] guid unique device (decoder or encoder) module id +* \return pointer to ni_device_context_t if found, NULL otherwise +* +* Note: only need to specify the device type and guid and codec type +* +* +* Note: the returned ni_device_context_t content is not supposed to be used by +* caller directly: should only be passed to API in the subsequent +* calls; also after its use, the context should be released by +* calling ni_rsrc_free_device_context. +*******************************************************************************/ +ni_device_context_t *ni_rsrc_allocate_simple_direct +( + ni_device_type_t device_type, + int guid +) +{ + ni_device_context_t *p_device_context = ni_rsrc_get_device_context(device_type, guid); + + return p_device_context; +} + + +/*!***************************************************************************** +* \brief Release resources allocated for decoding/encoding. +* function This *must* be called at the end of transcoding +* with previously assigned load value by allocate* functions. +* +* \param[in/out] p_ctxt the device context +* \param[in] load the load value returned by allocate* functions +* +* \return None +*******************************************************************************/ +void ni_rsrc_release_resource(ni_device_context_t *p_device_context, + uint64_t load) +{ + +#if 1 + (void) p_device_context; + (void) load; + return; + +#else + if (!p_device_context) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() invalid input pointers\n", __func__); + return; + } + +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex + { + ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", + __func__, p_device_context->lock); + } +#elif __linux__ || __APPLE__ + lockf(p_device_context->lock, F_LOCK, 0); +#endif + + if (p_device_context->p_device_info->xcode_load_pixel < load) + { + ni_log(NI_LOG_INFO, "Warning: releasing resource load %lu > current load %lu\n", load, + p_device_context->p_device_info->xcode_load_pixel); + } + else + { + p_device_context->p_device_info->xcode_load_pixel -= load; + // Remove as the value is getting from the FW + // p_device_context->p_device_info->model_load = (int)((double)(p_device_context->p_device_info->xcode_load_pixel) * 100 / total_cap); +#if __linux__ || __APPLE__ + if (msync((void *)p_device_context->p_device_info, sizeof(ni_device_info_t), MS_SYNC | MS_INVALIDATE)) + { + ni_log(NI_LOG_ERROR, "ERROR %s() msync() p_device_context->" + "p_device_info: %s\n", __func__, strerror(NI_ERRNO)); + } +#endif + } + +#ifdef _WIN32 + ReleaseMutex(p_device_context->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_context->lock, F_ULOCK, 0); +#endif + +#endif +} + +/*!***************************************************************************** +* \brief check the NetInt h/w device in resource pool on the host. +* +* \param[in] guid the global unique device index in resource pool +* device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +* +* \return +* NI_RETCODE_SUCCESS +*******************************************************************************/ +int ni_rsrc_check_hw_available(int guid, ni_device_type_t device_type) +{ + ni_device_pool_t *p_device_pool = NULL; + ni_device_context_t *p_device_ctx = NULL; + ni_session_context_t session_ctx = {0}; + ni_xcoder_params_t api_param = {0}; + uint32_t max_nvme_io_size = 0; + bool b_release_pool_mtx = false; + ni_retcode_t retval = NI_RETCODE_SUCCESS; + int retry_cnt = 0; + + if (guid < 0) + { + ni_log(NI_LOG_ERROR, "ERROR invalid guid:%d\n", guid); + return NI_RETCODE_INVALID_PARAM; + } + + if (!IS_XCODER_DEVICE_TYPE(device_type)) + { + ni_log(NI_LOG_ERROR, "ERROR: Unknown device type:%d\n", device_type); + return NI_RETCODE_INVALID_PARAM; + } + + ni_device_session_context_init(&session_ctx); + session_ctx.keep_alive_timeout = NI_DEFAULT_KEEP_ALIVE_TIMEOUT; + session_ctx.src_bit_depth = 8; + session_ctx.hw_id = guid; + + if (NI_DEVICE_TYPE_DECODER == device_type) + { + if (ni_decoder_init_default_params(&api_param, 30, 1, NI_MIN_BITRATE, + XCODER_MIN_ENC_PIC_WIDTH, + XCODER_MIN_ENC_PIC_HEIGHT) < 0) + { + ni_log(NI_LOG_ERROR, "ERROR: set decoder default params error\n"); + return NI_RETCODE_INVALID_PARAM; + } + } else if (NI_DEVICE_TYPE_ENCODER == device_type) + { + if (ni_encoder_init_default_params( + &api_param, 30, 1, NI_MIN_BITRATE, XCODER_MIN_ENC_PIC_WIDTH, + XCODER_MIN_ENC_PIC_HEIGHT, NI_CODEC_FORMAT_H264) < 0) + { + ni_log(NI_LOG_ERROR, "ERROR: set encoder default params error\n"); + return NI_RETCODE_INVALID_PARAM; + } + } else if (NI_DEVICE_TYPE_SCALER == device_type) + { + session_ctx.device_type = NI_DEVICE_TYPE_SCALER; + session_ctx.scaler_operation = NI_SCALER_OPCODE_SCALE; + } else + { + session_ctx.device_type = NI_DEVICE_TYPE_AI; + } + session_ctx.p_session_config = &api_param; + + p_device_pool = ni_rsrc_get_device_pool(); + if (!p_device_pool) + { + ni_log(NI_LOG_ERROR, "ERROR: get device poll failed\n"); + retval = NI_RETCODE_ERROR_GET_DEVICE_POOL; + LRETURN; + } + +#ifdef _WIN32 + if (WAIT_ABANDONED == + WaitForSingleObject(p_device_pool->lock, + INFINITE)) // no time-out interval) + { + ni_log(NI_LOG_INFO, + "ERROR: ni_rsrc_list_devices() failed to obtain mutex: %p\n", + p_device_pool->lock); + retval = NI_RETCODE_FAILURE; + LRETURN; + } +#elif __linux__ + lockf(p_device_pool->lock, F_LOCK, 0); +#endif + b_release_pool_mtx = true; + + // get device context + p_device_ctx = ni_rsrc_get_device_context(device_type, guid); + if (p_device_ctx) + { + session_ctx.device_handle = ni_device_open( + p_device_ctx->p_device_info->dev_name, &max_nvme_io_size); + session_ctx.blk_io_handle = session_ctx.device_handle; + if (NI_INVALID_DEVICE_HANDLE == session_ctx.device_handle) + { + ni_log(NI_LOG_ERROR, "open device failed: %d\n", errno); + retval = NI_RETCODE_ERROR_INVALID_HANDLE; + } else + { +#ifdef _WIN32 + session_ctx.event_handle = ni_create_event(); + if (NI_INVALID_EVENT_HANDLE == session_ctx.event_handle) + { + ni_log(NI_LOG_INFO, "Error create envent:%d\n", GetLastError()); + retval = NI_RETCODE_FAILURE; + LRETURN; + } +#endif + retval = ni_device_session_query(&session_ctx, device_type); + if (NI_RETCODE_SUCCESS != retval) + { + ni_log(NI_LOG_ERROR, + "guid %d. %s is not avaiable, type: %d, retval:%d\n", + guid, p_device_ctx->p_device_info->dev_name, + device_type, retval); + retval = NI_RETCODE_FAILURE; + } else + { + while (1) + { + retry_cnt++; + retval = ni_device_session_open(&session_ctx, device_type); + ni_device_session_close(&session_ctx, 0, device_type); + if (retval == NI_RETCODE_SUCCESS) + { + ni_log(NI_LOG_INFO, "guid %d. %s is avaiable\n", + guid, p_device_ctx->p_device_info->dev_name); + break; + } else if ( + retry_cnt < 10 && + retval == + NI_RETCODE_ERROR_VPU_RECOVERY) // max 2 seconds + { + ni_log(NI_LOG_INFO, + "vpu recovery happened on guid %d. %s, retry " + "cnt:%d\n", + guid, p_device_ctx->p_device_info->dev_name, + retry_cnt); +#ifndef _WIN32 + ni_usleep(200000); // 200 ms +#endif + continue; + } else + { + ni_log(NI_LOG_ERROR, + "session open error guid %d. %s, type: %d, " + "retval:%d\n", + guid, p_device_ctx->p_device_info->dev_name, + device_type, retval); + retval = NI_RETCODE_FAILURE; + break; + } + } + } + } + } else + { + ni_log(NI_LOG_ERROR, + "Error get device resource: guid %d, device_ctx %p\n", guid, + p_device_ctx); + retval = NI_RETCODE_FAILURE; + } -* \param none -* -* \return none -* -*******************************************************************************/ -LIB_API void ni_rsrc_print_all_devices_capability(void) -{ - ni_device_t device = {0}; +END: - if (NI_RETCODE_SUCCESS != ni_rsrc_list_all_devices(&device)) + if (b_release_pool_mtx) { - return; +#ifdef _WIN32 + ReleaseMutex(p_device_pool->lock); +#elif __linux__ + lockf(p_device_pool->lock, F_ULOCK, 0); +#endif } - print_device(&device); + ni_close_event(session_ctx.event_handle); + ni_device_close(session_ctx.device_handle); + + ni_rsrc_free_device_context(p_device_ctx); + ni_device_session_context_clear(&session_ctx); + ni_rsrc_free_device_pool(p_device_pool); + + return retval; } /*!***************************************************************************** -* \brief Prints detailed capability information for all initialized -* devices and general information about uninitialized devices. - -* \param list_uninitialized Flag to determine if uninitialized devices -* should be grabbed. +* \brief Remove an NetInt h/w device from resource pool on the host. * -* \return none +* \param[in] p_dev the NVMe device name * +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_FAILURE *******************************************************************************/ -LIB_API void ni_rsrc_print_all_devices_capability2(bool list_uninitialized) +int ni_rsrc_remove_device(const char* dev) { - ni_device_t device = {0}; +#if __linux__ || __APPLE__ +#ifndef _ANDROID + char lck_name[32]; +#endif +#endif + int return_value = NI_RETCODE_SUCCESS; + int32_t guid; + int32_t guids[NI_MAX_DEVICE_CNT]; + unsigned int guid_index_i, guid_index_j, ui_device_type; +#ifdef _WIN32 + DWORD rValue; +#endif + ni_device_context_t *p_device_context; + ni_device_pool_t *p_device_pool = NULL; + ni_device_queue_t *p_device_queue; + ni_device_type_t device_type; - if (NI_RETCODE_SUCCESS != ni_rsrc_list_all_devices2(&device, list_uninitialized)) + if (!dev) { - return; + ni_log(NI_LOG_ERROR, "ERROR: %s() dev is NULL\n", __FUNCTION__); + return_value = NI_RETCODE_INVALID_PARAM; + LRETURN; } - print_device(&device); -} - -/*!****************************************************************************** -* \brief Query a specific device with detailed information on the system + p_device_pool = ni_rsrc_get_device_pool(); + if (!p_device_pool) + { + return_value = NI_RETCODE_FAILURE; + LRETURN; + } -* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[in] guid unique device(decoder or encoder) id -* -* \return -* pointer to ni_device_info_t if found -* NULL otherwise -* -* Note: Caller is responsible for releasing memory that was allocated for the -* returned pointer -*******************************************************************************/ -ni_device_info_t *ni_rsrc_get_device_info(ni_device_type_t device_type, int guid) -{ - ni_device_info_t *p_device_info = NULL; - ni_device_context_t* p_device_context = NULL; +#ifdef _WIN32 + rValue = WaitForSingleObject(p_device_pool->lock, INFINITE); + if (rValue != WAIT_OBJECT_0) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s() Failed to obtain mutex %p\n", + __FUNCTION__, + p_device_pool->lock); + return_value = NI_RETCODE_FAILURE; + LRETURN; + } +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_LOCK, 0); +#endif - p_device_context = ni_rsrc_get_device_context(device_type, guid); - if (NULL == p_device_context) - { - LRETURN; - } + p_device_queue = p_device_pool->p_device_queue; + for (guid_index_i = 0; guid_index_i < NI_MAX_DEVICE_CNT; guid_index_i++) + { + for (ui_device_type = NI_DEVICE_TYPE_DECODER; + ui_device_type < NI_DEVICE_TYPE_XCODER_MAX; + ui_device_type++) + { + guid = p_device_queue->xcoders[ui_device_type][guid_index_i]; + if (guid == -1) + { + continue; + } + device_type = (ni_device_type_t)ui_device_type; + p_device_context = ni_rsrc_get_device_context(device_type, guid); + if (!p_device_context) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s() Failed to obtain device context for " + "%s with GUID %u! Undefined behavior!\n", + GET_XCODER_DEVICE_TYPE_STR(device_type), + guid); + return_value = NI_RETCODE_FAILURE; + continue; + } - p_device_info = (ni_device_info_t *)malloc(sizeof(ni_device_info_t)); - if (NULL == p_device_info) - { - LRETURN; - } + if (strncmp(dev, + p_device_context->p_device_info->dev_name, + NI_MAX_DEVICE_NAME_LEN) != 0) + { + continue; + } #ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_get_device_info() failed to obtain " - "mutex: %p\n", p_device_context->lock); - free(p_device_info); - LRETURN; - } + CloseHandle(p_device_context->lock); +#elif __linux__ || __APPLE__ +#ifndef _ANDROID + if (!shm_unlink(p_device_context->shm_name)) + { + ni_log(NI_LOG_INFO, + "%s %s %s deleted\n", + dev, + GET_XCODER_DEVICE_TYPE_STR(device_type), + p_device_context->shm_name); + } + else + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): %s %s %s failed to delete %s\n", + __FUNCTION__, + dev, + GET_XCODER_DEVICE_TYPE_STR(device_type), + p_device_context->shm_name, + strerror(NI_ERRNO)); + return_value = NI_RETCODE_FAILURE; + } +#endif +#endif - memcpy(p_device_info, p_device_context->p_device_info, sizeof(ni_device_info_t)); - ReleaseMutex(p_device_context->lock); -#elif __linux - lockf(p_device_context->lock, F_LOCK, 0); + ni_rsrc_free_device_context(p_device_context); - memcpy(p_device_info, p_device_context->p_device_info, sizeof(ni_device_info_t)); +#if __linux__ || __APPLE__ +#ifndef _ANDROID + ni_rsrc_get_lock_name(device_type, guid, lck_name, 32); + if (!unlink(lck_name)) + { + ni_log(NI_LOG_INFO, + "%s %s %s deleted\n", + dev, + GET_XCODER_DEVICE_TYPE_STR(device_type), + lck_name); + } + else + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): %s %s %s failed to delete %s\n", + __FUNCTION__, + dev, + GET_XCODER_DEVICE_TYPE_STR(device_type), + lck_name, + strerror(NI_ERRNO)); + return_value = NI_RETCODE_FAILURE; + } +#endif +#endif - lockf(p_device_context->lock, F_ULOCK, 0); + if (return_value != NI_RETCODE_SUCCESS) + { + continue; + } + + p_device_queue->xcoders[ui_device_type][guid_index_i] = -1; + p_device_queue->xcoder_cnt[ui_device_type]--; + } + } + + // Take p_device_queue->xcoder_cnt[ui_device_type] to contain the value 2. + // p_device_queue->xcoders[ui_device_type] could be [0, -1, 2, ...] + // p_device_queue->xcoders[ui_device_type] should be [0, 2, -1, ...] + for (ui_device_type = NI_DEVICE_TYPE_DECODER; + ui_device_type < NI_DEVICE_TYPE_XCODER_MAX; + ui_device_type++) + { + memset(guids, -1, sizeof(guids)); + guid_index_j = 0; + for (guid_index_i = 0; guid_index_i < NI_MAX_DEVICE_CNT; guid_index_i++) + { + guid = p_device_queue->xcoders[ui_device_type][guid_index_i]; + if (guid != -1) + { + guids[guid_index_j] = guid; + guid_index_j++; + if (guid_index_j == p_device_queue->xcoder_cnt[ui_device_type]) + { + break; + } + } + } + memcpy(p_device_queue->xcoders[ui_device_type], guids, sizeof(guids)); + } + +#if __linux__ || __APPLE__ +#ifndef _ANDROID + if (!msync((void *)p_device_queue, + sizeof(ni_device_queue_t), + MS_SYNC|MS_INVALIDATE)) + { + ni_log(NI_LOG_INFO, "%s deleted\n", dev); + } + else + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): msync() failed to delete %s: %s\n", + __FUNCTION__, + dev, + strerror(NI_ERRNO)); + return_value = NI_RETCODE_FAILURE; + } +#endif #endif -END: +#ifdef _WIN32 + ReleaseMutex(p_device_pool->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_ULOCK, 0); +#endif - ni_rsrc_free_device_context(p_device_context); +end: + ni_rsrc_free_device_pool(p_device_pool); - return p_device_info; + return return_value; } -/*!**************************************************************************** - -* \brief Get the least used device that can handle decoding or encoding -* a video stream of certain resolution/frame-rate/codec. +/*!***************************************************************************** +* \brief Remove all NetInt h/w devices from resource pool on the host. * -* \param[in] width width of video resolution -* \param[in] height height of video resolution -* \param[in] frame_rate video stream frame rate -* \param[in] codec EN_H264 or EN_H265 -* \param[in] type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[out] info detailed device information. If is non-NULL, the -* device info is stored in the memory pointed to by it. +* \param none * -* \return device GUID (>= 0) if found , -1 otherwise +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_FAILURE *******************************************************************************/ -int ni_rsrc_get_available_device(int width, int height, int frame_rate, - ni_codec_t codec, ni_device_type_t device_type, - ni_device_info_t *p_device_info) +int ni_rsrc_remove_all_devices(void) { - int i, rc; - int guid = -1; - uint32_t num_sw_instances = 0; - ni_device_pool_t *p_device_pool = NULL; - ni_device_info_t *p_dev_info = NULL; - ni_device_context_t *p_device_context = NULL; - ni_session_context_t p_session_context = {0}; - ni_device_info_t dev_info = { 0 }; - int num_coders = 0; - int least_model_load = 0; - - // query all the coders of device_type and update their status, and find the - // device_info with the least load and least number of instances. - p_device_pool = ni_rsrc_get_device_pool(); - if (!p_device_pool) - { - ni_log(NI_LOG_ERROR, "ERROR: cannot get p_device_pool\n"); - return NI_RETCODE_FAILURE; - } + char xcoder_dev_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN] = {0}; + int xcoder_dev_count = 0; + int i = 0; + ni_device_t *saved_coders = NULL; + saved_coders = (ni_device_t *)malloc(sizeof(ni_device_t)); + if (!saved_coders) + { + ni_log(NI_LOG_ERROR, "ERROR %s() failed to malloc memory: %s\n", + __func__, strerror(NI_ERRNO)); + return NI_RETCODE_FAILURE; + } + memset(saved_coders, 0, sizeof(ni_device_t)); -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_get_available_device() failed to " - "obtain mutex: %p\n", p_device_pool->lock); - ni_rsrc_free_device_pool(p_device_pool); - return NI_RETCODE_FAILURE; - } -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_LOCK, 0); + // retrieve saved info from resource pool at start up + if (NI_RETCODE_SUCCESS == + ni_rsrc_list_devices( + NI_DEVICE_TYPE_ENCODER, + saved_coders->xcoders[NI_DEVICE_TYPE_ENCODER], + &(saved_coders->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]))) + { + for (i = 0; i < saved_coders->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; + i++) + { + strcpy(xcoder_dev_names[i], + saved_coders->xcoders[NI_DEVICE_TYPE_ENCODER][i] + .dev_name); + ni_log(NI_LOG_INFO, "device %d %s retrieved\n", i, + xcoder_dev_names[i]); + } + xcoder_dev_count = + saved_coders->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; +#ifdef XCODER_311 + ni_log(NI_LOG_DEBUG, + "%d devices retrieved from current pool at start up\n", + xcoder_dev_count); +#else + ni_log(NI_LOG_INFO, + "%d devices retrieved from current pool at start up\n", + xcoder_dev_count); #endif + } else + { + ni_log(NI_LOG_ERROR, "Error retrieving from current pool at start " + "up\n"); + } + free(saved_coders); + + // remove from resource pool all devices + for (i = 0; i < xcoder_dev_count; i++) + { + ni_log(NI_LOG_INFO, "removing device %d %s !\n", i, + xcoder_dev_names[i]); + if (NI_RETCODE_SUCCESS == + ni_rsrc_remove_device(xcoder_dev_names[i])) + { + ni_log(NI_LOG_INFO, "%s deleted successfully !\n", + xcoder_dev_names[i]); + } else + { + ni_log(NI_LOG_ERROR, "%s failed to delete !\n", + xcoder_dev_names[i]); + } + } - num_coders = p_device_pool->p_device_queue->xcoder_cnt[device_type]; +#if __linux__ || __APPLE__ +#ifndef _ANDROID + if (0 == shm_unlink(CODERS_SHM_NAME)) + { + ni_log(NI_LOG_INFO, "%s deleted.\n", CODERS_SHM_NAME); + } + else + { + ni_log(NI_LOG_ERROR, "%s failed to delete !\n", CODERS_SHM_NAME); + } - int tmp_id; - for (i = 0; i < num_coders; i++) - { - tmp_id = p_device_pool->p_device_queue->xcoders[device_type][i]; - p_device_context = ni_rsrc_get_device_context(device_type, tmp_id); + for (i = 0; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + if (0 == unlink(XCODERS_RETRY_LCK_NAME[i])) + { + ni_log(NI_LOG_INFO, "%d %s deleted.\n", + i, XCODERS_RETRY_LCK_NAME[i]); + } + else + { + ni_log(NI_LOG_ERROR, "%d %s failed to delete !\n", + i, XCODERS_RETRY_LCK_NAME[i]); + } + } - p_session_context.blk_io_handle = - ni_device_open(p_device_context->p_device_info->blk_name, - &p_session_context.max_nvme_io_size); - p_session_context.device_handle = p_session_context.blk_io_handle; + if (0 == unlink(CODERS_LCK_NAME)) + { + ni_log(NI_LOG_INFO, "%s deleted.\n", CODERS_LCK_NAME); + } + else + { + ni_log(NI_LOG_ERROR, "%s failed to delete !\n", CODERS_LCK_NAME); + } +#endif +#endif - if (NI_INVALID_DEVICE_HANDLE == p_session_context.device_handle) - { - ni_log(NI_LOG_ERROR, "ERROR %s() ni_device_open() %s: %s\n", - __func__, p_device_context->p_device_info->blk_name, - strerror(NI_ERRNO)); - ni_rsrc_free_device_context(p_device_context); - continue; - } + return NI_RETCODE_SUCCESS; +} - p_session_context.hw_id = p_device_context->p_device_info->hw_id; +/*!***************************************************************************** +* \brief Add an NetInt h/w device into resource pool on the host. +* +* \param[in] p_dev Device name represented as C string. ex "/dev/nvme0" +* \param[in] should_match_rev 0: transcoder firmware revision matching the +* library's version is NOT required for placing +* the transcoder into resource pool; 1: otherwise +* +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_INVALID_PARAM +* NI_RETCODE_FAILURE +*******************************************************************************/ +int ni_rsrc_add_device(const char* dev, int should_match_rev) +{ + uint32_t i, existing_number_of_devices; - rc = ni_device_session_query(&p_session_context, device_type); + ni_device_type_t device_type; + ni_device_context_t *device_context; + ni_device_pool_t *device_pool; + ni_device_queue_t *device_queue; + ni_retcode_t retcode; - if (NI_INVALID_DEVICE_HANDLE != p_session_context.device_handle) + if (!dev) { - ni_device_close(p_session_context.device_handle); + ni_log(NI_LOG_ERROR, "ERROR: %s(): dev is NULL\n", __FUNCTION__); + return NI_RETCODE_INVALID_PARAM; } - if (NI_RETCODE_SUCCESS != rc) + device_pool = ni_rsrc_get_device_pool(); + if (!device_pool) { - ni_log(NI_LOG_ERROR, "ERROR: query %s %s.%d\n", device_type_str[device_type], - p_device_context->p_device_info->dev_name, - p_device_context->p_device_info->hw_id); - ni_rsrc_free_device_context(p_device_context); - continue; + return NI_RETCODE_SUCCESS; } #ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex + if (WAIT_ABANDONED == WaitForSingleObject(device_pool->lock, INFINITE)) { - ni_log(NI_LOG_ERROR, "ERROR: ni_rsrc_get_available_device() failed to obtain mutex: %p\n", p_device_context->lock); - //ni_rsrc_free_device_pool(p_device_pool); - //return -1; + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Failed to obtain lock %p\n", + __FUNCTION__, + device_pool->lock); + return NI_RETCODE_FAILURE; } #elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); + lockf(device_pool->lock, F_LOCK, 0); #endif - ni_rsrc_update_record(p_device_context, &p_session_context); - - p_dev_info = p_device_context->p_device_info; - - // here we select the best load - // for decoder/encoder: check the model_load - // for hwuploader: check directly hwupload count in query result - if (NI_DEVICE_TYPE_UPLOAD == device_type) - { - if (i == 0 || p_session_context.load_query.active_hwuploaders < num_sw_instances) - { - guid = tmp_id; - num_sw_instances = p_session_context.load_query.active_hwuploaders; - memcpy(&dev_info, p_dev_info, sizeof(ni_device_info_t)); - } - } else if (i == 0 || p_dev_info->model_load < least_model_load || - (p_dev_info->model_load == least_model_load && - p_dev_info->active_num_inst < num_sw_instances)) - { - guid = tmp_id; - least_model_load = p_dev_info->model_load; - num_sw_instances = p_dev_info->active_num_inst; - memcpy(&dev_info, p_dev_info, sizeof(ni_device_info_t)); - } + retcode = NI_RETCODE_SUCCESS; -#ifdef _WIN32 - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_ULOCK, 0); -#endif - ni_rsrc_free_device_context(p_device_context); - } + device_type = NI_DEVICE_TYPE_ENCODER; + device_queue = device_pool->p_device_queue; + existing_number_of_devices = device_queue->xcoder_cnt[device_type]; - // scaler and AI load handling will be considered in the future - if (guid >= 0) - { - // calculate the load this stream will generate based on its resolution and - // fps required - p_device_context = ni_rsrc_get_device_context(device_type, guid); - ni_rsrc_device_video_ref_cap_t refCap = g_device_reference_table[device_type][codec]; - if (refCap.fps == 0) + if (existing_number_of_devices == NI_MAX_DEVICE_CNT) { - guid = -1; - } else if (IS_XCODER_DEVICE_TYPE(device_type)) - { - unsigned long total_cap = refCap.width * refCap.height * refCap.fps; - unsigned long xcode_cap = width * height * frame_rate; - if (xcode_cap + p_device_context->p_device_info->xcode_load_pixel > total_cap) - { - ni_log(NI_LOG_INFO, "Warning xcode cap: %lu (%.1f) + current load %lu (%.1f) " - "> total %lu (1) ..\n", - xcode_cap, (float)xcode_cap / (float)total_cap, - p_device_context->p_device_info->xcode_load_pixel, - (float)p_device_context->p_device_info->xcode_load_pixel / - (float)total_cap, - total_cap); - guid = -1; - } + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Limit of NI_MAX_DEVICE_CNT(%d) existing Quadra " + "devices previously reached. Not adding %s.\n", + __FUNCTION__, + NI_MAX_DEVICE_CNT, + dev); + retcode = NI_RETCODE_FAILURE; + LRETURN; } - else + + for (i = 0; i < existing_number_of_devices; i++) { - float fRef = (float)(refCap.width * refCap.height * refCap.fps); - float fLoad = (float)(width * height * frame_rate * 100); - if ((fLoad / fRef) > 100.0) + device_context = + ni_rsrc_get_device_context(device_type, + device_queue->xcoders[device_type][i]); + if (device_context && !strncmp(device_context->p_device_info->dev_name, + dev, + NI_MAX_DEVICE_NAME_LEN)) { - guid = -1; + retcode = NI_RETCODE_FAILURE; + ni_log(NI_LOG_ERROR, + "ERROR: %s(): %s already exists in resource pool\n", + __FUNCTION__, + dev); + ni_rsrc_free_device_context(device_context); + LRETURN; } + ni_rsrc_free_device_context(device_context); + } + + if (!add_to_shared_memory(dev, + true, + should_match_rev, + device_queue)) + { + retcode = NI_RETCODE_FAILURE; } - ni_rsrc_free_device_context(p_device_context); - } +end: #ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); + ReleaseMutex(device_pool->lock); #elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_ULOCK, 0); + lockf(device_pool->lock, F_ULOCK, 0); #endif - - ni_rsrc_free_device_pool(p_device_pool); - - ni_log(NI_LOG_INFO, "Get %s for %dx%d fps %d : %d %s.%d\n", - IS_XCODER_DEVICE_TYPE(device_type) ? device_type_str[device_type] : - "UNKNOWN DEVICE", - width, height, frame_rate, guid, - guid == -1 ? "NULL" : dev_info.dev_name, - guid == -1 ? -1 : dev_info.hw_id); - - //Copy to user only if the pointer is not NULL - if ( (p_device_info) && (guid >= 0) ) - { - memcpy(p_device_info, &dev_info, sizeof(ni_device_info_t)); - } - - return guid; + return retcode; } /*!***************************************************************************** -* \brief Update the load value and s/w instances info of a specific decoder or -* encoder. This is used by resource management daemon to update periodically. +* \brief Free all resources taken by the device pool * -* \param[in] p_ctxt The device context returned by ni_rsrc_get_device_context -* \param[in] p_load The latest load value to update -* \param[in] sw_instance_cnt Number of s/w instances -* \param[in] sw_instance_info Info of s/w instances +* \param[in] p_device_pool Poiner to a device pool struct * -* \return -* NI_RETCODE_SUCCESS -* NI_RETCODE_FAILURE +* \return None *******************************************************************************/ -int ni_rsrc_update_device_load(ni_device_context_t *p_device_context, int load, - int sw_instance_cnt, const ni_sw_instance_info_t sw_instance_info[]) +void ni_rsrc_free_device_pool(ni_device_pool_t* p_device_pool) { - int i; - if (!p_device_context || !sw_instance_info) + if (p_device_pool) { - ni_log(NI_LOG_ERROR, "ERROR: %s() invalid input pointers\n", __func__); - return NI_RETCODE_FAILURE; - } - + if (NI_INVALID_LOCK_HANDLE != p_device_pool->lock) + { #ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_context->lock); - return NI_RETCODE_FAILURE; - } + CloseHandle(p_device_pool->lock); #elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); + close(p_device_pool->lock); #endif - - p_device_context->p_device_info->load = load; - p_device_context->p_device_info->active_num_inst = sw_instance_cnt; - for (i = 0; i < sw_instance_cnt; i++) - { - p_device_context->p_device_info->sw_instance[i] = sw_instance_info[i]; - } - + } #ifdef _WIN32 - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_ULOCK, 0); + UnmapViewOfFile(p_device_pool->p_device_queue); +#else + munmap(p_device_pool->p_device_queue, sizeof(ni_device_queue_t)); #endif - return NI_RETCODE_SUCCESS; + free(p_device_pool); + } } -/*!****************************************************************************** - * \brief +/*!***************************************************************************** + * \brief lock a file lock and open a session on a device * - * \param + * \param device_type + * \param lock * - * \return + * \return None *******************************************************************************/ -/*! this function must be called inside the protected region by p_device_pool - if query, checking, allocation and update should be done atomically */ -static void ni_rsrc_move_device_to_end_of_pool(ni_device_type_t type, int guid, - ni_device_pool_t *p_device_pool) +int ni_rsrc_lock_and_open(int device_type, ni_lock_handle_t* lock) { - int *coders; - int i, count; - ni_log(NI_LOG_INFO, "Moving %s %d to queue end ..\n", device_type_str[type], guid); - - coders = p_device_pool->p_device_queue->xcoders[type]; - count = p_device_pool->p_device_queue->xcoder_cnt[type]; + int count = 0; + int status = NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; +#ifdef _WIN32 + *lock = CreateMutex(NULL, FALSE, XCODERS_RETRY_LCK_NAME[device_type]); - i = 0; - while (i < count) + if (NULL == *lock) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() CreateMutex() %s failed: %s\n", + __func__, XCODERS_RETRY_LCK_NAME[device_type], + strerror(NI_ERRNO)); + return NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; + } +#else + do { - if (coders[i] == guid) + if (count>=1) { - ni_log(NI_LOG_INFO, "Found id %d at pos: %d\n", guid, i); - break; + //sleep 10ms if the file lock is locked by other FFmpeg process + ni_usleep(LOCK_WAIT); } - else + // Here we try to open the file lock, retry if it failed + *lock = + open(XCODERS_RETRY_LCK_NAME[device_type], O_RDWR | O_CREAT | O_CLOEXEC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (*lock < 0) { - i++; + count++; + if (count > MAX_LOCK_RETRY) + { + ni_log(NI_LOG_ERROR, "Can not lock down the file lock after 6s"); + return NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; + } } } - if (i < count) + while (*lock < 0); +#endif + // Now the lock is free so we lock it down + count = 0; + do { - /*! move all the coders after i forward one position and put i at the - end */ - while (i < count - 1) + //sleep 10ms if the file lock is locked by other FFmpeg process + if (count>=1) + { + //sleep 10ms if the file lock is locked by other FFmpeg process + ni_usleep(LOCK_WAIT); + } +#ifdef _WIN32 + DWORD ret = WaitForSingleObject(*lock, 1); // time-out 1ms + if (WAIT_OBJECT_0 == ret) + { + status = NI_RETCODE_SUCCESS; + } else if (WAIT_TIMEOUT != ret) + { + ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %s\n", + __func__, strerror(NI_ERRNO)); + } +#else + status = lockf(*lock, F_LOCK, 0); +#endif + if (status != 0) { - coders[i] = coders[i + 1]; - i++; + count++; + if (count > MAX_LOCK_RETRY) + { + ni_log(NI_LOG_ERROR, "Can not put down the lock after 6s"); + return NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; + } } - coders[count - 1] = guid; } + while (status != 0); + + return NI_RETCODE_SUCCESS; } /*!***************************************************************************** -* \brief Allocate resources for decoding/encoding, based on the provided rule -* -* \param[in] type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[in] rule allocation rule -* \param[in] codec EN_H264 or EN_H265 -* \param[in] width width of video resolution -* \param[in] height height of video resolution -* \param[in] frame_rate video stream frame rate -* \param[out] p_load the p_load that will be generated by this encoding -* task. Returned *only* for encoder for now. + * \brief unlock a file lock + * + * \param device_type + * \param lock + * + * \return None + *******************************************************************************/ +int ni_rsrc_unlock(int device_type, ni_lock_handle_t lock) +{ + if (lock == NI_INVALID_LOCK_HANDLE) + { + return NI_RETCODE_FAILURE; + } + + int count = 0; + ni_lock_handle_t status = NI_INVALID_LOCK_HANDLE; + do + { + if (count >= 1) + { + ni_usleep(LOCK_WAIT); + } +#ifdef _WIN32 + if (ReleaseMutex(lock)) + { + status = (ni_lock_handle_t)(0); + } +#else + status = lockf(lock, F_ULOCK, 0); +#endif + count++; + if (count > MAX_LOCK_RETRY) + { + ni_log(NI_LOG_ERROR, "Can not unlock the lock after 6s"); + return NI_RETCODE_ERROR_UNLOCK_DEVICE; + } + } while (status != (ni_lock_handle_t)(0)); + +#ifdef _WIN32 + CloseHandle(lock); +#else + close(lock); +#endif //_WIN32 defined + return NI_RETCODE_SUCCESS; +} + +/*!***************************************************************************** +* \brief check if device FW revision is compatible with SW API * -* \return pointer to ni_device_context_t if found, NULL otherwise +* \param fw_rev * -* Note: codec, width, height, fps need to be supplied for NI_DEVICE_TYPE_ENCODER only, -* they are ignored otherwize. -* Note: the returned ni_device_context_t content is not supposed to be used by -* caller directly: should only be passed to API in the subsequent -* calls; also after its use, the context should be released by -* calling ni_rsrc_free_device_context. +* \return 1 for full compatibility, 2 for partial, 0 for none *******************************************************************************/ -ni_device_context_t *ni_rsrc_allocate_auto -( - ni_device_type_t device_type, - ni_alloc_rule_t rule, - ni_codec_t codec, - int width, int height, - int frame_rate, - unsigned long* p_load -) +int ni_rsrc_is_fw_compat(uint8_t fw_rev[8]) +{ + return ni_is_fw_compatible(fw_rev); +} + +static int int_cmp(const void *a, const void *b) +{ + const int *ia = (const int *)a; + const int *ib = (const int *)b; + return (*ia == *ib) ? 0 : ((*ia > *ib) ? 1 : -1); + /* integer comparison: returns negative if b > a , 0 if a == b,and positive if a > b */ +} + +static int ni_hw_device_info_quadra_threshold_param_t_compare(const void *pl, const void *pr) { - ni_device_pool_t *p_device_pool = NULL; - ni_device_info_t *p_device_info = NULL; - ni_device_context_t *p_device_context = NULL; - ni_session_context_t p_session_context = { 0 }; - int *coders = NULL; - int i, count, rc; - int guid = -1; - int load = 0; - uint32_t num_sw_instances = 0; - int least_model_load = 0; - unsigned long job_mload = 0; - - /*! retrieve the record and based on the allocation rule specified, find the - least loaded or least number of s/w instances among the coders */ - p_device_pool = ni_rsrc_get_device_pool(); - if (p_device_pool) - { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) //we got the mutex + const ni_hw_device_info_quadra_threshold_param_t *ll = (const ni_hw_device_info_quadra_threshold_param_t *)pl; + const ni_hw_device_info_quadra_threshold_param_t *rr = (const ni_hw_device_info_quadra_threshold_param_t *)pr; + if(!ll || !rr) { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", __func__, p_device_pool->lock); + return 0; } -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_LOCK, 0); -#endif + return (ll->device_type == rr->device_type) ? 0 : ((ll->device_type > rr->device_type) ? 1 : -1); +} - coders = p_device_pool->p_device_queue->xcoders[device_type]; - count = p_device_pool->p_device_queue->xcoder_cnt[device_type]; - i = 0; - while (i < count) +/*!********************************************************************************************* +* \brief Calculate decoder load used in ni_check_hw_info() +* The computing method is from firmware for 770. +* This function is used for ni_check_hw_info() +* +* \param decoder_param +* +* \return task decoder load +***********************************************************************************************/ +static int check_hw_info_decoder_need_load(ni_hw_device_info_quadra_decoder_param_t *decoder_param) +{ + int factor_8_10 = 1; + uint32_t resolution = decoder_param->h * decoder_param->w; + if(decoder_param->bit_8_10 == 10) { - /*! get the individual device_info info and check the load/num-of-instances */ - p_device_context = ni_rsrc_get_device_context(device_type, coders[i]); - - // p_first retrieve status from f/w and update storage - - p_session_context.blk_io_handle = ni_device_open(p_device_context->p_device_info->blk_name, &p_session_context.max_nvme_io_size); - p_session_context.device_handle = p_session_context.blk_io_handle; - - if (NI_INVALID_DEVICE_HANDLE == p_session_context.device_handle) - { - ni_log(NI_LOG_ERROR, "ERROR %s() ni_device_open() %s: %s\n", - __func__, p_device_context->p_device_info->blk_name, - strerror(NI_ERRNO)); - ni_rsrc_free_device_context(p_device_context); - i++; - continue; - } - - p_session_context.hw_id = p_device_context->p_device_info->hw_id; - rc = ni_device_session_query(&p_session_context, device_type); - - ni_device_close(p_session_context.device_handle); - - if (NI_RETCODE_SUCCESS != rc) - { - ni_log(NI_LOG_ERROR, "ERROR: query %s %s.%d\n", - device_type_str[device_type], - p_device_context->p_device_info->dev_name, - p_device_context->p_device_info->hw_id); - ni_rsrc_free_device_context(p_device_context); - i++; - continue; - } + factor_8_10 = 2; + } + return resolution >= 1920*1080 ? + (int)(((uint64_t)(resolution)*(uint64_t)(decoder_param->fps)*(uint64_t)(factor_8_10)*100)/1440/1920/1080) : + (int)((uint64_t)(resolution)*(uint64_t)(decoder_param->fps)*(uint64_t)(factor_8_10)*100/2880/1280/720); +} -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_context->lock); - } -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); -#endif - ni_rsrc_update_record(p_device_context, &p_session_context); +/*!************************************************************************************** +* \brief Calculate encoder load used in ni_check_hw_info() +* The computing method is from firmware->ModelLoadSet +* This function is used for ni_check_hw_info() +* +* \param encoder_param +* +* \return task encoder load +****************************************************************************************/ +static int check_hw_info_encoder_need_load(ni_hw_device_info_quadra_encoder_param_t *encoder_param) +{ + double factor = 1.0; + double factor_codec = 1.0; + double factor_rdoq = 1.0; + double factor_rdoLevel = 1.0; + double factor_lookahead = 1.0; + double factor_8_10_bit = 1.0; + double factor_720p = 1.0; - p_device_info = p_device_context->p_device_info; - if (i == 0) - { - guid = coders[i]; - load = p_device_info->load; - least_model_load = p_device_info->model_load; - num_sw_instances = p_device_info->active_num_inst; - } + int resolution = (int)(encoder_param->w * encoder_param->h); - ni_log(NI_LOG_INFO, "Coder [%d]: %d , load: %d (%d), activ_inst: %d , max_inst %d\n", - i, coders[i], p_device_info->load, p_device_info->model_load, p_device_info->active_num_inst, - p_device_info->max_instance_cnt); - switch (rule) - { - case EN_ALLOC_LEAST_INSTANCE: + if(encoder_param->code_format == 3)//STD_JPGE + { + factor_codec = 0.67; + } + else{ + if((encoder_param->code_format == 0 || encoder_param->code_format == 1) && + encoder_param->ui8enableRdoQuant)//264 or 265 { - if (p_device_info->active_num_inst < num_sw_instances) - { - guid = coders[i]; - num_sw_instances = p_device_info->active_num_inst; - } - break; + factor_rdoq = 1.32; } - case EN_ALLOC_LEAST_LOAD: - default: + if((encoder_param->code_format == 1 || encoder_param->code_format ==2) && + encoder_param->rdoLevel > 1) { - if (NI_DEVICE_TYPE_ENCODER == device_type) - { - if (p_device_info->model_load < least_model_load) - { - guid = coders[i]; - least_model_load = p_device_info->model_load; - } - } - else if (p_device_info->load < load) - { - guid = coders[i]; - load = p_device_info->load; - } - break; + factor_rdoLevel = (encoder_param->rdoLevel == 2) ? 1.91 : 3.28; } - } - -#ifdef _WIN32 - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_ULOCK, 0); -#endif - ni_rsrc_free_device_context(p_device_context); - i++; - } - if (guid >= 0) - { - p_device_context = ni_rsrc_get_device_context(device_type, guid); - if (NI_DEVICE_TYPE_ENCODER == device_type) - { - ni_rsrc_device_video_ref_cap_t refCap = g_device_reference_table[device_type][codec]; - unsigned long total_cap = refCap.width * refCap.height * refCap.fps; - if (total_cap == 0) + if(encoder_param->lookaheadDepth != 0) { - ni_log(NI_LOG_ERROR, "ERROR: guid %d capacity is 0\n", guid); - ni_rsrc_free_device_context(p_device_context); - p_device_context = NULL; - LRETURN; + factor_lookahead = (double)(encoder_param->lookaheadDepth * 0.0014 + 1.012); } - else - { - job_mload = width * height * frame_rate; + } + + if(encoder_param->bit_8_10 == 10) + { + factor_8_10_bit = 2; + } + + factor_720p = 1.125;//consider h and w + factor = factor_codec * factor_8_10_bit * factor_rdoq * factor_rdoLevel + * factor_lookahead * factor_720p; + + //ENC_TOTAL_BIT_VOLUME_1_SEC (3840 * 2160 * 60ULL) + //PERF_MODEL_LOAD_PERCENT = ((ENC_TOTAL_BIT_VOLUME_1_SEC / 100) * ENCODER_MULTICORE_NUM) + //encoedr_need_load = sample_model_load/PERF_MODEL_LOAD_PERCENT + return uint32_t( + ((uint32_t)((uint32_t)factor*encoder_param->fps * resolution)) / + ((3840 * 2160 * 60ULL) / 100 * 4)); +} -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_context->lock); - } -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); -#endif - p_device_context->p_device_info->xcode_load_pixel += job_mload; - // Remove as the value is getting from the FW - //p_device_context->p_device_info->model_load = (int)((double)(p_device_context->p_device_info->xcode_load_pixel) * 100 / total_cap); -#ifdef _WIN32 - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - if (msync((void *)p_device_context->p_device_info, sizeof(ni_device_info_t), - MS_SYNC | MS_INVALIDATE)) - { - ni_log(NI_LOG_ERROR, "ERROR %s() msync() %s: %s\n", __func__, - p_device_context->p_device_info, strerror(NI_ERRNO)); - } - lockf(p_device_context->lock, F_ULOCK, 0); -#endif - } - } +/*!***************************************************************************** +* \brief Calculate shared memeory uasge buffer scale +* The computing method is from MemUsageCalculation_SR +* This function is used for ni_check_hw_info() +* +* \param h +* \param w +* \param bit_8_10 +* \param rgba +* +* \return task shared memeory uasge buffer scale +********************************************************************************/ +static int check_hw_info_shared_mem_calculate_b_scale(int h,int w,int bit_8_10,int rgba) +{ + const int stride = 128; + int estimated_yuv_size = rgba ? + w * h * 4 : + bit_8_10 == 8 ? + ( ((w + stride - 1)/stride)*stride + ((w/2 + stride - 1)/stride)*stride ) * h: + ( ((w * 2 + stride - 1)/stride)*stride + ((w + stride - 1)/stride)*stride ) * h; + const int b_unit = 1601536;//Bin_Unit_Size + int b_scale = (estimated_yuv_size + b_unit -1) / b_unit; + return b_scale; +} - ni_rsrc_move_device_to_end_of_pool(device_type, guid, p_device_pool); - } - else +/*!***************************************************************************** +* \brief Calculate encoder shared memory usage +* The computing method is from MemUsageCalculation_SR +* This function is used for ni_check_hw_info() +* +* \param encoder_param +* +* \return task encoder shared memeory uasge +********************************************************************************/ +static int check_hw_info_encoder_shared_mem_usage(const ni_hw_device_info_quadra_encoder_param_t *encoder_param) +{ + // const int p_1080 = 2073600; + // const int p_1440 = 3686400; + // const int p_4k = 8294400; + + if(!encoder_param) { - ni_log(NI_LOG_ERROR, "ERROR: %s() cannot find guid\n", __func__); - p_device_context = NULL; + return 0; } - END: -#ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_ULOCK, 0); -#endif - ni_rsrc_free_device_pool(p_device_pool); - } + //cppcheck do not allow this + // const int v32_ofCores = 0; + + // int encoder_shared_mem_usage = 0; + + // int v32_ofCores_calculate = ((v32_ofCores>0)?v32_ofCores:1)-1; + //cppcheck do not allow this + + const int v32_ofCores_calculate = 0; + + int b_counts = (int)(v32_ofCores_calculate + + ((encoder_param->lookaheadDepth > 0) ? encoder_param->lookaheadDepth + 8/2 + v32_ofCores_calculate : 0 )+ + 8 + + (encoder_param->uploader ? 1 : 0) * 3 + + 1) * 1; + int b_scale = check_hw_info_shared_mem_calculate_b_scale(encoder_param->h, encoder_param->w, + encoder_param->bit_8_10, encoder_param->rgba); + return b_scale * b_counts; - if (p_load) - { - *p_load = job_mload; - } - return p_device_context; } /*!***************************************************************************** -* \brief Allocate resources for decoding/encoding, by designating explicitly -* the device to use. +* \brief Calculate decoder shared memory usage +* The computing method is from MemUsageCalculation_SR +* This function is used for ni_check_hw_info() * -* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[in] guid unique device (decoder or encoder) module id -* \param[in] codec EN_H264 or EN_H265 -* \param[in] width width of video resolution -* \param[in] height height of video resolution -* \param[in] frame_rate video stream frame rate -* \param[out] p_load the load that will be generated by this encoding -* task. Returned *only* for encoder for now. +* \param decoder_param +* \param estimated_max_dpb * -* \return pointer to ni_device_context_t if found, NULL otherwise +* \return task decoder shared memeory uasge +********************************************************************************/ +static int check_hw_info_decoder_shared_mem_usage(const ni_hw_device_info_quadra_decoder_param_t *decoder_param,int estimated_max_dpb) +{ + // const int p_1080 = 2073600; + // const int p_1440 = 3686400; + // const int p_4k = 8294400; + + if(!decoder_param) + { + return 0; + } + const int hw_frame = decoder_param->hw_frame; + + const int v30_xlsx = 0; + int b_counts = 1 * (v30_xlsx + + (hw_frame ? 0 : 1)*3 + + estimated_max_dpb); + int b_scale = check_hw_info_shared_mem_calculate_b_scale(decoder_param->h, decoder_param->w, + decoder_param->bit_8_10, decoder_param->rgba); + return b_scale * b_counts; +} + +/*!***************************************************************************** +* \brief Calculate scaler shared memory usage +* The computing method is from MemUsageCalculation_SR +* This function is used for ni_check_hw_info() * -* Note: codec, width, height, fps need to be supplied by encoder; they -* are ignored for decoder. +* \param scaler_param +* \param estimated_max_dpb * -* Note: the returned ni_device_context_t content is not supposed to be used by -* caller directly: should only be passed to API in the subsequent -* calls; also after its use, the context should be released by -* calling ni_rsrc_free_device_context. -*******************************************************************************/ -ni_device_context_t *ni_rsrc_allocate_direct -( - ni_device_type_t device_type, - int guid, - ni_codec_t codec, - int width, - int height, - int frame_rate, - unsigned long* p_load -) +* \return task scaler shared memeory uasge +********************************************************************************/ +static int check_hw_info_scaler_shared_mem_usage(const ni_hw_device_info_quadra_scaler_param_t *scaler_param,int estimated_max_dpb) { - ni_device_pool_t *p_device_pool = NULL; - unsigned long job_mload = 0; + // const int p_1080 = 2073600; + // const int p_1440 = 3686400; + // const int p_4k = 8294400; - ni_device_context_t *p_device_context = ni_rsrc_get_device_context(device_type, guid); - if (p_device_context) - { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex + + if(!scaler_param) { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_context->lock); + return 0; } -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); -#endif + // const int hw_frame = 1; + //cppcheck do not allow this + + const int v30_xlsx = 0; + int b_counts = 1 * (v30_xlsx + + 0/* (hw_frame ? 0 : 1)*3 */ + + estimated_max_dpb); + int b_scale = check_hw_info_shared_mem_calculate_b_scale(scaler_param->h, scaler_param->w, + scaler_param->bit_8_10, scaler_param->rgba); + return b_scale * b_counts; +} + + +/*!************************************************************************************************* +* \brief Remove unsupported card in ni_check_hw_info() by memroy +* This function is used for ni_check_hw_info() +* +* \param[in] card_remove +* \param[in] ni_card_info +* \param[in] card_num +* \param[in] coder_param +* \param[in] mode mode == 0->decoder, mode == 1->encoder, mode == 2->scaler, mode > 3->all +* +* \return NONE +****************************************************************************************************/ +static void check_hw_info_remove_card_with_memory(int *card_remove, const ni_hw_device_info_quadra_t *ni_card_info, int card_num, const ni_hw_device_info_quadra_coder_param_t *coder_param,int mode) +{ + const int total = 2456;//buffer count summary + int task_mem_usage = 0; + int task_mem_precentage = 0; + int i; - /*! call libxcoder to allocate a s/w instance on the specified - h/w device_info; this might not be necessary as the actual allocation of - s/w instance happens when decoding/encoding starts in the codec */ - /*! update modelled load for encoder */ - if (NI_DEVICE_TYPE_ENCODER == device_type) + if(!ni_card_info) { - ni_rsrc_device_video_ref_cap_t refCap = g_device_reference_table[device_type][codec]; - unsigned long total_cap = refCap.width * refCap.height * refCap.fps; - if (total_cap > 0) - { - job_mload = width * height * frame_rate; - p_device_context->p_device_info->xcode_load_pixel += job_mload; - // Remove as the value is getting from the FW - //p_device_context->p_device_info->model_load = (int)((double)(p_device_context->p_device_info->xcode_load_pixel) * 100 / total_cap); -#if __linux__ || __APPLE__ - if (msync((void *)p_device_context->p_device_info, sizeof(ni_device_info_t), - MS_SYNC | MS_INVALIDATE)) + ni_log(NI_LOG_ERROR, "card_info is NULL mark all cards as removed\n"); + for(i = 0; i < card_num; ++i) { - ni_log(NI_LOG_ERROR, "ERROR %s() msync() p_device_context->" - "p_device_info: %s\n", __func__, strerror(NI_ERRNO)); + card_remove[i] = 1; } -#endif - } + return; } -#ifdef _WIN32 - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_ULOCK, 0); -#endif + if(mode == 0) + { + task_mem_usage = check_hw_info_decoder_shared_mem_usage(coder_param->decoder_param,16); + } + else if(mode == 1) + { + task_mem_usage = check_hw_info_encoder_shared_mem_usage(coder_param->encoder_param); + } + else if(mode == 2) + { + task_mem_usage = check_hw_info_scaler_shared_mem_usage(coder_param->scaler_param,16); + } + else if(mode > 3) + { + int decoder_shared_mem_usage = check_hw_info_decoder_shared_mem_usage(coder_param->decoder_param,16); + int encoder_shared_mem_usage = check_hw_info_encoder_shared_mem_usage(coder_param->encoder_param); + int scaler_shared_mem_usage = check_hw_info_scaler_shared_mem_usage(coder_param->scaler_param,16); + task_mem_usage = decoder_shared_mem_usage + ((encoder_shared_mem_usage > scaler_shared_mem_usage) ? + encoder_shared_mem_usage : scaler_shared_mem_usage); + } + else + { + ni_log(NI_LOG_ERROR, "parameter:mode is out of range\n"); + task_mem_usage = check_hw_info_decoder_shared_mem_usage(coder_param->decoder_param,16) + + check_hw_info_encoder_shared_mem_usage(coder_param->encoder_param)+ + check_hw_info_scaler_shared_mem_usage(coder_param->scaler_param,16); + } - /*! then move this device_info to the end of the device_info queue so that it will - be selected p_last in the auto-allocate selection process, for load - balancing */ - p_device_pool = ni_rsrc_get_device_pool(); + task_mem_precentage = 100 * task_mem_usage / total; - if (p_device_pool) + if(task_mem_precentage > 90) { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_pool->lock); - } - - ni_rsrc_move_device_to_end_of_pool(device_type, guid, p_device_pool); + //calculate mem usage is an estimated num , maybe too big + task_mem_precentage = 90; + } - ReleaseMutex(p_device_pool->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_LOCK, 0); + for(i = 0;icard_info[0][i].shared_mem_usage >= 100)//all shared memory usages are the same in one card + { + card_remove[i] = 1; + } + } - lockf(p_device_pool->lock, F_ULOCK, 0); -#endif +} - ni_rsrc_free_device_pool(p_device_pool); +/*!********************************************************************************************* +* \brief Create and alloc a pointer to ni_hw_device_info_quadra_coder_param_t +* This function is used for ni_check_hw_info() +* +* \param[in] mode 0 for decoder,1 for encoder,2 for scaler,3 for AI, >= 4 for hw_mode +* +* \return a pointer to ni_hw_device_info_quadra_coder_param_t on success,NULL for otherwise +***********************************************************************************************/ +ni_hw_device_info_quadra_coder_param_t *ni_create_hw_device_info_quadra_coder_param(int mode) +{ + ni_hw_device_info_quadra_coder_param_t *p_coder_param = NULL; + p_coder_param = (ni_hw_device_info_quadra_coder_param_t *)malloc(sizeof(ni_hw_device_info_quadra_coder_param_t)); + if(p_coder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_coder_param\n"); + return p_coder_param; } - } - - if (p_load) - { - *p_load = job_mload; - } - return p_device_context; + memset(p_coder_param,0,sizeof(ni_hw_device_info_quadra_coder_param_t)); + p_coder_param->hw_mode = 0; + if(mode == 0)//decoder + { + p_coder_param->decoder_param = (ni_hw_device_info_quadra_decoder_param_t *)malloc(sizeof(ni_hw_device_info_quadra_decoder_param_t)); + if(p_coder_param->decoder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_decoder_param\n"); + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + } + else if(mode == 1)//encoder + { + p_coder_param->encoder_param = (ni_hw_device_info_quadra_encoder_param_t *)malloc(sizeof(ni_hw_device_info_quadra_encoder_param_t)); + if(p_coder_param->encoder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_encoder_param\n"); + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + } + else if(mode == 2)//scaler + { + p_coder_param->scaler_param = (ni_hw_device_info_quadra_scaler_param_t *)malloc(sizeof(ni_hw_device_info_quadra_scaler_param_t)); + if(p_coder_param->scaler_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_scaler_param\n"); + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + } + else if(mode == 3)//AI + { + p_coder_param->ai_param = (ni_hw_device_info_quadra_ai_param_t *)malloc(sizeof(ni_hw_device_info_quadra_ai_param_t)); + if(p_coder_param->ai_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_ai_param\n"); + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + } + else//hw_mode + { + p_coder_param->encoder_param = (ni_hw_device_info_quadra_encoder_param_t *)malloc(sizeof(ni_hw_device_info_quadra_encoder_param_t)); + if(p_coder_param->encoder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_encoder_param\n"); + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + p_coder_param->decoder_param = (ni_hw_device_info_quadra_decoder_param_t *)malloc(sizeof(ni_hw_device_info_quadra_decoder_param_t)); + if(p_coder_param->decoder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_decoder_param\n"); + free(p_coder_param->encoder_param); + p_coder_param->encoder_param = NULL; + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + p_coder_param->scaler_param = (ni_hw_device_info_quadra_scaler_param_t *)malloc(sizeof(ni_hw_device_info_quadra_scaler_param_t)); + if(p_coder_param->scaler_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_scaler_param\n"); + free(p_coder_param->encoder_param); + p_coder_param->encoder_param = NULL; + free(p_coder_param->decoder_param); + p_coder_param->decoder_param = NULL; + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + p_coder_param->ai_param = (ni_hw_device_info_quadra_ai_param_t *)malloc(sizeof(ni_hw_device_info_quadra_ai_param_t)); + if(p_coder_param->ai_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for hw_device_info_quadra_ai_param\n"); + free(p_coder_param->encoder_param); + p_coder_param->encoder_param = NULL; + free(p_coder_param->decoder_param); + p_coder_param->decoder_param = NULL; + free(p_coder_param->scaler_param); + p_coder_param->scaler_param = NULL; + free(p_coder_param); + p_coder_param = NULL; + return p_coder_param; + } + p_coder_param->hw_mode = 1; + } + if(p_coder_param->encoder_param) + { + p_coder_param->encoder_param->bit_8_10 = 8; + p_coder_param->encoder_param->code_format = 0; + p_coder_param->encoder_param->fps = 30; + p_coder_param->encoder_param->lookaheadDepth = 0; + p_coder_param->encoder_param->rdoLevel = 0; + p_coder_param->encoder_param->w = 1920; + p_coder_param->encoder_param->h = 1080; + p_coder_param->encoder_param->ui8enableRdoQuant = 0; + p_coder_param->encoder_param->uploader = 0; + p_coder_param->encoder_param->rgba = 0; + } + if(p_coder_param->decoder_param) + { + p_coder_param->decoder_param->w = 1920; + p_coder_param->decoder_param->h = 1080; + p_coder_param->decoder_param->bit_8_10 = 8; + p_coder_param->decoder_param->fps = 30; + p_coder_param->decoder_param->rgba = 0; + p_coder_param->decoder_param->hw_frame = 1; + } + if(p_coder_param->scaler_param) + { + p_coder_param->scaler_param->h = 1920; + p_coder_param->scaler_param->w = 1080; + p_coder_param->scaler_param->bit_8_10 = 8; + p_coder_param->scaler_param->rgba = 0; + } + if(p_coder_param->ai_param) + { + p_coder_param->ai_param->h = 1920; + p_coder_param->ai_param->w = 1080; + p_coder_param->ai_param->bit_8_10 = 8; + p_coder_param->ai_param->rgba = 0; + } + return p_coder_param; } -/*!***************************************************************************** -* \brief Allocate resources for decoding/encoding, by designating explicitly -* the device to use. do not track the load on the host side -* -* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[in] guid unique device (decoder or encoder) module id -* \return pointer to ni_device_context_t if found, NULL otherwise -* -* Note: only need to specify the device type and guid and codec type +/*!********************************************************************************************* +* \brief Free resource in p_hw_device_info_quadra_coder_param +* This function is used for ni_check_hw_info() +* +* \param[in] device_type_num * +* \param[in] avaliable_card_num * -* Note: the returned ni_device_context_t content is not supposed to be used by -* caller directly: should only be passed to API in the subsequent -* calls; also after its use, the context should be released by -* calling ni_rsrc_free_device_context. -*******************************************************************************/ -ni_device_context_t *ni_rsrc_allocate_simple_direct -( - ni_device_type_t device_type, - int guid -) +* \return a pointer to ni_hw_device_info_quadra_t on success,NULL for otherwise +***********************************************************************************************/ +void ni_destory_hw_device_info_quadra_coder_param(ni_hw_device_info_quadra_coder_param_t *p_hw_device_info_quadra_coder_param) { - ni_device_pool_t *p_device_pool = NULL; - - ni_device_context_t *p_device_context = ni_rsrc_get_device_context(device_type, guid); - - return p_device_context; + if(p_hw_device_info_quadra_coder_param == NULL) + { + return; + } + if(p_hw_device_info_quadra_coder_param->encoder_param) + { + free(p_hw_device_info_quadra_coder_param->encoder_param); + p_hw_device_info_quadra_coder_param->encoder_param = NULL; + } + if(p_hw_device_info_quadra_coder_param->decoder_param) + { + free(p_hw_device_info_quadra_coder_param->decoder_param); + p_hw_device_info_quadra_coder_param->decoder_param = NULL; + } + if(p_hw_device_info_quadra_coder_param->scaler_param) + { + free(p_hw_device_info_quadra_coder_param->scaler_param); + p_hw_device_info_quadra_coder_param->scaler_param = NULL; + } + if(p_hw_device_info_quadra_coder_param->ai_param) + { + free(p_hw_device_info_quadra_coder_param->ai_param); + p_hw_device_info_quadra_coder_param->ai_param = NULL; + } + free(p_hw_device_info_quadra_coder_param); + return; } - -/*!***************************************************************************** -* \brief Release resources allocated for decoding/encoding. -* function This *must* be called at the end of transcoding -* with previously assigned load value by allocate* functions. +/*!********************************************************************************************* +* \brief Create a ni_hw_device_info_quadra_t +* This function is used for ni_check_hw_info() * -* \param[in/out] p_ctxt the device context -* \param[in] load the load value returned by allocate* functions +* \param[in] device_type_num +* \param[in] avaliable_card_num * -* \return None -* THE API needs to be removed from this fild and related test needs to cleanup -*******************************************************************************/ -void ni_rsrc_release_resource(ni_device_context_t *p_device_context, - unsigned long load) +* \return a pointer to ni_hw_device_info_quadra_t on success,NULL for otherwise +***********************************************************************************************/ +ni_hw_device_info_quadra_t *ni_hw_device_info_alloc_quadra(int device_type_num,int avaliable_card_num) { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_context->lock); - } -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_LOCK, 0); -#endif + int i; + ni_hw_device_info_quadra_t *p_hw_device_info = (ni_hw_device_info_quadra_t *)malloc(sizeof(ni_hw_device_info_quadra_t)); + if(!p_hw_device_info) + { + ni_log(NI_LOG_ERROR,"ERROR: Failed to allocate memory for p_hw_device_info_quadra_t\n"); + goto p_hw_device_info_end; + } - if (p_device_context->p_device_info->xcode_load_pixel < load) - { - ni_log(NI_LOG_INFO, "Warning: releasing resource load %lu > current load %lu\n", load, - p_device_context->p_device_info->xcode_load_pixel); - } - else - { - p_device_context->p_device_info->xcode_load_pixel -= load; - // Remove as the value is getting from the FW - // p_device_context->p_device_info->model_load = (int)((double)(p_device_context->p_device_info->xcode_load_pixel) * 100 / total_cap); -#if __linux__ || __APPLE__ - if (msync((void *)p_device_context->p_device_info, sizeof(ni_device_info_t), MS_SYNC | MS_INVALIDATE)) + p_hw_device_info->device_type_num = device_type_num; + p_hw_device_info->device_type = (ni_device_type_t *)malloc(sizeof(ni_device_type_t) * device_type_num); + if(!p_hw_device_info->device_type) { - ni_log(NI_LOG_ERROR, "ERROR %s() msync() p_device_context->" - "p_device_info: %s\n", __func__, strerror(NI_ERRNO)); + ni_log(NI_LOG_ERROR,"ERROR: Failed to allocate memory for p_hw_device_info_quadra_t->device_type\n"); + goto device_type_end; } -#endif - } -#ifdef _WIN32 - ReleaseMutex(p_device_context->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_context->lock, F_ULOCK, 0); -#endif + p_hw_device_info->card_info = (ni_card_info_quadra_t **)malloc(sizeof(ni_card_info_quadra_t*) * p_hw_device_info->device_type_num); + if(p_hw_device_info->card_info == NULL) + { + ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for p_hw_device_info_quadra_t->card_info\n", NI_ERRNO); + p_hw_device_info->err_code = NI_RETCODE_ERROR_MEM_ALOC; + //unlock_and_return + goto card_info_end; + } + memset(p_hw_device_info->card_info, 0, sizeof(ni_card_info_quadra_t*) * p_hw_device_info->device_type_num); + + p_hw_device_info->available_card_num = avaliable_card_num; + p_hw_device_info->consider_mem = 0; + for(i = 0; i < p_hw_device_info->device_type_num; ++i) + { + p_hw_device_info->card_info[i] = (ni_card_info_quadra_t *)malloc(sizeof(ni_card_info_quadra_t) * p_hw_device_info->available_card_num); + if(p_hw_device_info->card_info[i] == NULL) + { + ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for p_hw_device_info_quadra_t->card_info\n", NI_ERRNO); + goto card_info_i_end; + } + } + + return p_hw_device_info; + +card_info_i_end: + for(i = 0; i < p_hw_device_info->device_type_num; ++i) + { + if(p_hw_device_info->card_info[i]) + { + free(p_hw_device_info->card_info[i]); + p_hw_device_info->card_info[i] = NULL; + } + } + free(p_hw_device_info->card_info); + p_hw_device_info->card_info = NULL; +card_info_end: + free(p_hw_device_info->device_type); + p_hw_device_info->device_type = NULL; +device_type_end: + free(p_hw_device_info); + p_hw_device_info = NULL; +p_hw_device_info_end: + return NULL; } -/*!***************************************************************************** -* \brief check the NetInt h/w device in resource pool on the host. -* -* \param[in] guid the global unique device index in resource pool -* device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +/*!********************************************************************************************* +* \brief Free resource in a pointer of ni_hw_device_info_quadra_t +* This function is used for ni_check_hw_info() +* +* \param[in] p_hw_device_info Poiner to a ni_hw_device_info_quadra_t struct * -* \return -* NI_RETCODE_SUCCESS -*******************************************************************************/ -int ni_rsrc_check_hw_available(int guid, ni_device_type_t device_type) +* \return None +***********************************************************************************************/ +void ni_hw_device_info_free_quadra(ni_hw_device_info_quadra_t *p_hw_device_info) +{ + int i; + if(!p_hw_device_info) + { + return; + } + free(p_hw_device_info->device_type); + p_hw_device_info->device_type = NULL; + for(i = 0; i < p_hw_device_info->device_type_num; ++i) + { + free(p_hw_device_info->card_info[i]); + p_hw_device_info->card_info[i] = NULL; + } + free(p_hw_device_info->card_info); + p_hw_device_info->card_info = NULL; + free(p_hw_device_info); + return; +} + +int ni_check_hw_info(ni_hw_device_info_quadra_t **pointer_to_p_hw_device_info, + int task_mode, + ni_hw_device_info_quadra_threshold_param_t *hw_info_threshold_param, + ni_device_type_t preferential_device_type, + ni_hw_device_info_quadra_coder_param_t * coder_param, + int hw_mode, + int consider_mem) { + //order of ni_hw_device_info_quadra_threshold_param_t *hw_info_threshold_param, order + //order of ni_device_type_t all_need_device_type + //ni_device_type_t preferential_device_type, in the first place + //other order of device_type ni_device_type_t adjust to the order of all_need_device_type + //int hw_info_param_num = hw_mode ? 2 : 1;adjust to 3 + int should_match_rev = 1; + int module_count = 1; + ni_device_context_t *dev_ctxt_arr = NULL; + int32_t *module_id_arr = NULL; + // int32_t best_load_module_id = -1; ni_device_pool_t *p_device_pool = NULL; - ni_device_context_t *p_device_ctx = NULL; - ni_session_context_t session_ctx = {0}; - ni_xcoder_params_t api_param = {0}; - uint32_t max_nvme_io_size = 0; - bool b_release_pool_mtx = false; - ni_retcode_t retval = NI_RETCODE_SUCCESS; - int retry_cnt = 0; + ni_device_queue_t *coders = NULL; + ni_device_context_t *p_device_context = NULL; + ni_session_context_t xCtxt = { 0 }; + int *card_remove = NULL;//cards which are not satisfied threshold + // uint64_t reserved_memory = 0; + // int needed_memory = 0; + uint64_t decoder_need_load = 0; + uint64_t encoder_need_load = 0; + int retval = 0;//1 for success , 0 for failure + int ret = 0; + int hw_info_param_num = hw_mode ? 4 : 1; + int device_type_num = 1; + const int all_device_type_num = 4; - if (guid < 0) + ni_device_type_t all_need_device_type[4] = {NI_DEVICE_TYPE_DECODER,NI_DEVICE_TYPE_ENCODER,NI_DEVICE_TYPE_SCALER,NI_DEVICE_TYPE_AI};//decoder encoder scaler and AI + /*note: preference device type will be moved to all_need_device_type[0], + * and sequence of device type in other structs(such as p_hw_device_info.device_type) will be changed in the order of all_need_device_type + */ + + int i = 0; + bool b_valid = false; + + + // int *mem_usage = NULL; + + ni_hw_device_info_quadra_t *p_hw_device_info = NULL; + + //check hw_info_param + if(!pointer_to_p_hw_device_info) { - ni_log(NI_LOG_ERROR, "ERROR invalid guid:%d\n", guid); - return NI_RETCODE_INVALID_PARAM; + ni_log(NI_LOG_ERROR, "Error: Invalid input params: pointer_to_p_hw_device_info is NULL.\n"); + return retval; } - if (!(NI_DEVICE_TYPE_DECODER == device_type || - NI_DEVICE_TYPE_ENCODER == device_type)) + if(*pointer_to_p_hw_device_info) { - ni_log(NI_LOG_ERROR, "ERROR: Unknown device type:%d\n", device_type); - return NI_RETCODE_INVALID_PARAM; + p_hw_device_info = *pointer_to_p_hw_device_info; + b_valid = true; } - ni_device_session_context_init(&session_ctx); - session_ctx.keep_alive_timeout = NI_DEFAULT_KEEP_ALIVE_TIMEOUT; - session_ctx.src_bit_depth = 8; - session_ctx.hw_id = guid; + // Check input parameters here + if(!coder_param){ + if(b_valid) + { + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; + } + ni_log(NI_LOG_ERROR, "Error: Invalid input params: coder_param is NULL.\n"); + return retval; + }else if(hw_mode && hw_mode != coder_param->hw_mode) + { + ni_log(NI_LOG_ERROR, "Error: Invalid input params: hw_mode = %d, coder_param->hw_mode = %d\n", + hw_mode,coder_param->hw_mode); + return retval; + }else if(!hw_mode) + { + if(preferential_device_type == NI_DEVICE_TYPE_ENCODER && coder_param->encoder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Invalid input params: preferential_device_type == NI_DEVICE_TYPE_ENCODER but coder_param->encoder_param == NULL\n"); + return retval; + } + if(preferential_device_type == NI_DEVICE_TYPE_DECODER && coder_param->decoder_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Invalid input params: preferential_device_type == NI_DEVICE_TYPE_DECODER but coder_param->decoder_param == NULL\n"); + return retval; + } + if(preferential_device_type == NI_DEVICE_TYPE_SCALER && coder_param->scaler_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Invalid input params: preferential_device_type == NI_DEVICE_TYPE_SCALER but coder_param->scaler_param == NULL\n"); + return retval; + } + if(preferential_device_type == NI_DEVICE_TYPE_AI && coder_param->ai_param == NULL) + { + ni_log(NI_LOG_ERROR, "Error: Invalid input params: preferential_device_type == NI_DEVICE_TYPE_AI but coder_param->ai_param == NULL\n"); + return retval; + } + } - if (NI_DEVICE_TYPE_DECODER == device_type) + + if((task_mode != 0 && task_mode != 1) || + (preferential_device_type != NI_DEVICE_TYPE_DECODER && preferential_device_type != NI_DEVICE_TYPE_ENCODER && + preferential_device_type != NI_DEVICE_TYPE_SCALER && preferential_device_type != NI_DEVICE_TYPE_AI))//scaler { - if (ni_decoder_init_default_params(&api_param, 30, 1, NI_MIN_BITRATE, - XCODER_MIN_ENC_PIC_WIDTH, - XCODER_MIN_ENC_PIC_HEIGHT) < 0) + if(b_valid) { - ni_log(NI_LOG_ERROR, "ERROR: set decoder default params error\n"); - return NI_RETCODE_INVALID_PARAM; + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; } - } else + ni_log(NI_LOG_ERROR, "Error: Invalid input params: realtime %d device_type %d\n", + task_mode, preferential_device_type); + return retval; + } + + if(!hw_info_threshold_param) { - if (ni_encoder_init_default_params( - &api_param, 30, 1, NI_MIN_BITRATE, XCODER_MIN_ENC_PIC_WIDTH, - XCODER_MIN_ENC_PIC_HEIGHT, NI_CODEC_FORMAT_H264) < 0) + if(b_valid) { - ni_log(NI_LOG_ERROR, "ERROR: set encoder default params error\n"); - return NI_RETCODE_INVALID_PARAM; + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; + } + ni_log(NI_LOG_ERROR, "Error: Invalid input params: hw_info_threshold_param is NULL.\n"); + return retval; + }else{ + for(i = 0;i < hw_info_param_num; ++i) + { + if(hw_info_threshold_param[i].load_threshold < 0||//check this + hw_info_threshold_param[i].load_threshold > 100 || + hw_info_threshold_param[i].task_num_threshold < 0 || + hw_info_threshold_param[i].task_num_threshold > NI_MAX_CONTEXTS_PER_HW_INSTANCE|| + ( hw_info_threshold_param[i].device_type != NI_DEVICE_TYPE_DECODER && + hw_info_threshold_param[i].device_type != NI_DEVICE_TYPE_ENCODER && + hw_info_threshold_param[i].device_type != NI_DEVICE_TYPE_SCALER && + hw_info_threshold_param[i].device_type != NI_DEVICE_TYPE_AI)) + { + if(b_valid) + { + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; + } + ni_log(NI_LOG_ERROR, "Error: Invalid input params: In %s, hw_info_threshold_param[%d].device_type = %d, hw_info_threshold_param[%d].load_threshold = %d, hw_info_threshold_param[%d].task_num_threshold = %d\n", + (hw_mode ? "hardware_mode":"software_mode"), i, hw_info_threshold_param[i].device_type, i, hw_info_threshold_param[i].load_threshold, i, hw_info_threshold_param[i].task_num_threshold); + return retval; } + } + } + // all parameters have been checked + + /*Customer wants to set fps = 120 when fps > 120 and set fps = 5 when fps < 5*/ + if(coder_param->encoder_param) + { + if(coder_param->encoder_param->fps > 120) + { + coder_param->encoder_param->fps = 120; + } + if(coder_param->encoder_param->fps < 5) + { + coder_param->encoder_param->fps = 5; + } + } + if(coder_param->decoder_param) + { + if(coder_param->decoder_param->fps > 120) + { + coder_param->decoder_param->fps = 120; + } + if(coder_param->decoder_param->fps < 5) + { + coder_param->decoder_param->fps = 5; + } + } + + //ni_rsrc_init() is unsafe in multi process/thread ,do not call ni_rsrc_init() here + + if (NI_RETCODE_SUCCESS != (ret = ni_rsrc_refresh(should_match_rev))) + { + ni_log(NI_LOG_ERROR, "Error: resource pool records might be corrupted!!\n"); + if(b_valid) + { + p_hw_device_info->err_code = ret; + } + return retval; } - session_ctx.p_session_config = &api_param; p_device_pool = ni_rsrc_get_device_pool(); if (!p_device_pool) { - ni_log(NI_LOG_ERROR, "ERROR: get device poll failed\n"); - retval = NI_RETCODE_ERROR_GET_DEVICE_POOL; - LRETURN; + ni_log(NI_LOG_ERROR, "Error:Can not get device pool info ..\n"); + if(b_valid) + { + p_hw_device_info->err_code = NI_RETCODE_ERROR_GET_DEVICE_POOL; + } + return retval; } #ifdef _WIN32 - if (WAIT_ABANDONED == - WaitForSingleObject(p_device_pool->lock, - INFINITE)) // no time-out interval) + if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) { - ni_log(NI_LOG_INFO, - "ERROR: ni_rsrc_list_devices() failed to obtain mutex: %p\n", - p_device_pool->lock); - retval = NI_RETCODE_FAILURE; + ni_log(NI_LOG_ERROR, "ERROR: Failed to obtain mutex: %p\n", p_device_pool->lock); + LRETURN; + } +#elif defined(__linux__) + if (lockf(p_device_pool->lock, F_LOCK, 0)) + { + ni_log(NI_LOG_ERROR, "Error lockf() failed\n"); + if(b_valid) + { + p_hw_device_info->err_code = NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; + } LRETURN; } -#elif __linux__ - lockf(p_device_pool->lock, F_LOCK, 0); #endif - b_release_pool_mtx = true; - // get device context - p_device_ctx = ni_rsrc_get_device_context(device_type, guid); - if (p_device_ctx) + coders = p_device_pool->p_device_queue; + if (!coders) { - session_ctx.device_handle = ni_device_open( - p_device_ctx->p_device_info->blk_name, &max_nvme_io_size); - session_ctx.blk_io_handle = session_ctx.device_handle; - if (NI_INVALID_DEVICE_HANDLE == session_ctx.device_handle) - { - ni_log(NI_LOG_ERROR, "open device failed: %d\n", errno); - retval = NI_RETCODE_ERROR_INVALID_HANDLE; - } else + ni_log(NI_LOG_ERROR, "Error pdevice_queue null!!\n"); + if(b_valid) { -#ifdef _WIN32 - session_ctx.event_handle = ni_create_event(); - if (NI_INVALID_EVENT_HANDLE == session_ctx.event_handle) - { - ni_log(NI_LOG_INFO, "Error create envent:%d\n", GetLastError()); - retval = NI_RETCODE_FAILURE; - LRETURN; - } -#endif - retval = ni_device_session_query(&session_ctx, device_type); - if (NI_RETCODE_SUCCESS != retval) - { - ni_log(NI_LOG_ERROR, - "guid %d. %s, %s is not avaiable, type: %d, retval:%d\n", - guid, p_device_ctx->p_device_info->dev_name, - p_device_ctx->p_device_info->blk_name, device_type, - retval); - retval = NI_RETCODE_FAILURE; - } else - { - while (1) - { - retry_cnt++; - retval = ni_device_session_open(&session_ctx, device_type); - ni_device_session_close(&session_ctx, 0, device_type); - if (retval == NI_RETCODE_SUCCESS) - { - ni_log(NI_LOG_INFO, "guid %d. %s %s is avaiable\n", - guid, p_device_ctx->p_device_info->dev_name, - p_device_ctx->p_device_info->blk_name); - break; - } else if ( - retry_cnt < 10 && - retval == - NI_RETCODE_ERROR_VPU_RECOVERY) // max 2 seconds - { - ni_log(NI_LOG_INFO, - "vpu recovery happened on guid %d. %s %s, retry " - "cnt:%d\n", - guid, p_device_ctx->p_device_info->dev_name, - p_device_ctx->p_device_info->blk_name, - retry_cnt); -#ifndef _WIN32 - ni_usleep(200000); // 200 ms -#endif - continue; - } else - { - ni_log(NI_LOG_ERROR, - "session open error guid %d. %s, %s, type: %d, " - "retval:%d\n", - guid, p_device_ctx->p_device_info->dev_name, - p_device_ctx->p_device_info->blk_name, - device_type, retval); - retval = NI_RETCODE_FAILURE; - break; - } - } + p_hw_device_info->err_code = NI_RETCODE_ERROR_GET_DEVICE_POOL; + } + LRETURN; + } + + //////Init p_hw_device_info start////// + + + // move preferential_device_type in all_need_device_type to top + for(i = 0; i < all_device_type_num; ++i) + { + if(all_need_device_type[i] == preferential_device_type) + { + ni_device_type_t tmp = all_need_device_type[i]; + all_need_device_type[i] = all_need_device_type[0]; + all_need_device_type[0] = tmp; + break; + } + //ni_device_type_t is a enum + } + qsort(&all_need_device_type[1], all_device_type_num - 1, sizeof(ni_device_type_t), int_cmp); + + //adjust order of hw_info_threshold_param as all_need_device_type + if(hw_mode) + { + // default device_type_num is 1 + device_type_num = 4;//decoder and encoder and scaler and AI + //adjust order of hw_info_threshold_param as all_need_device_type + for(i = 0; i < device_type_num; ++i) + { + if(hw_info_threshold_param[i].device_type == preferential_device_type) + { + ni_hw_device_info_quadra_threshold_param_t tmp = hw_info_threshold_param[i]; + hw_info_threshold_param[i] = hw_info_threshold_param[0]; + hw_info_threshold_param[0] = tmp; + break; } } - } else + qsort(&hw_info_threshold_param[1], device_type_num - 1, + sizeof(ni_hw_device_info_quadra_threshold_param_t), ni_hw_device_info_quadra_threshold_param_t_compare); + } + + if(!(*pointer_to_p_hw_device_info)) { - ni_log(NI_LOG_ERROR, - "Error get device resource: guid %d, device_ctx %p\n", guid, - p_device_ctx); - retval = NI_RETCODE_FAILURE; + p_hw_device_info = ni_hw_device_info_alloc_quadra(device_type_num,coders->xcoder_cnt[preferential_device_type]); + if(!p_hw_device_info) + { + ni_log(NI_LOG_ERROR,"ERROR: Failed to allocate memory for p_hw_device_info\n"); + LRETURN; + } + *pointer_to_p_hw_device_info = p_hw_device_info; + b_valid = true; } + else + { + // p_hw_device_info = *pointer_to_p_hw_device_info; + //already set this before -END: + //if user alloc hw_device_info themself check it + if(!p_hw_device_info->device_type) + { + ni_log(NI_LOG_ERROR,"ERROR: pointer_to_p_hw_device_info is not a pointer to NULL, but ->device_type is NULL\n"); + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + if(!p_hw_device_info->card_info) + { + ni_log(NI_LOG_ERROR,"ERROR: pointer_to_p_hw_device_info is not a pointer to NULL, but ->card_info is NULL\n"); + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + for(i = 0; i < device_type_num; ++i) + { + if(!p_hw_device_info->card_info[i]) + { + ni_log(NI_LOG_ERROR,"ERROR: pointer_to_p_hw_device_info is not a pointer to NULL, but ->card_info[%d] is NULL\n", i); + p_hw_device_info->err_code = NI_RETCODE_PARAM_INVALID_VALUE; + LRETURN; + } + } + } + //p_hw_device_info alloc succeed - if (b_release_pool_mtx) + //coders->decoders_cnt == coder->encoders_cnt has checked in the ni_logan_rsrc_refresh + p_hw_device_info->available_card_num = coders->xcoder_cnt[preferential_device_type]; + p_hw_device_info->device_type_num = device_type_num; + + for(i = 0; i < p_hw_device_info->device_type_num; ++i) { -#ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); -#elif __linux__ - lockf(p_device_pool->lock, F_ULOCK, 0); -#endif + p_hw_device_info->device_type[i] = all_need_device_type[i]; + for(int j = 0; j < p_hw_device_info->available_card_num; ++j) + { + p_hw_device_info->card_info[i][j].card_idx = -1; + p_hw_device_info->card_info[i][j].load = -1; + p_hw_device_info->card_info[i][j].model_load = -1; + p_hw_device_info->card_info[i][j].task_num = -1; + p_hw_device_info->card_info[i][j].max_task_num = NI_MAX_CONTEXTS_PER_HW_INSTANCE; + p_hw_device_info->card_info[i][j].shared_mem_usage = -1; + } } - ni_close_event(session_ctx.event_handle); - ni_device_close(session_ctx.device_handle); - - ni_rsrc_free_device_context(p_device_ctx); + p_hw_device_info->card_current_card = -1; + p_hw_device_info->err_code = NI_RETCODE_SUCCESS; + //////Init p_hw_device_info done////// - ni_rsrc_free_device_pool(p_device_pool); + if(consider_mem) + { + // mem_usage = (int *)malloc(sizeof(int) * (p_hw_device_info->available_card_num)); + // if(!mem_usage) + // { + // ni_log(NI_LOG_ERROR,"ERROR: Failed to allocate memory for p_hw_device_info\n"); + // p_hw_device_info->err_code = NI_RETCODE_ERROR_MEM_ALOC; + // LRETURN; + // } + p_hw_device_info->consider_mem = 1; + } + else + { + p_hw_device_info->consider_mem = 0; + } + + if (p_hw_device_info->available_card_num <= 0) + { + LRETURN; + } - return retval; -} + card_remove = (int32_t *)malloc(sizeof(int32_t) * p_hw_device_info->available_card_num); + if (!card_remove) + { + ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for card_remove\n", NI_ERRNO); + p_hw_device_info->err_code = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; + } + memset(card_remove, 0, sizeof(int32_t) * p_hw_device_info->available_card_num); -/*!***************************************************************************** -* \brief Remove an NetInt h/w device from resource pool on the host. -* -* \param[in] p_dev the NVMe device name -* -* \return -* NI_RETCODE_SUCCESS -* NI_RETCODE_FAILURE -*******************************************************************************/ -int ni_rsrc_remove_device(const char* dev) -{ - int i, j, k, count, rc = NI_RETCODE_FAILURE; - ni_device_queue_t *p_device_queue = NULL; - ni_device_pool_t *p_device_pool = ni_rsrc_get_device_pool(); - if (!dev) + module_count = coders->xcoder_cnt[preferential_device_type]; + dev_ctxt_arr = (ni_device_context_t *)malloc(sizeof(ni_device_context_t) * module_count); + if (!dev_ctxt_arr) { - ni_log(NI_LOG_ERROR, "ERROR: bad input parameter in %s()\n", __func__); - return NI_RETCODE_FAILURE; + ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for ni_rsrc_detect\n", NI_ERRNO); + p_hw_device_info->err_code = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; } - if (p_device_pool) - { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) //we got the mutex + module_id_arr = (int32_t *)malloc(sizeof(int32_t) * module_count); + if (!module_id_arr) { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_pool->lock); + ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for ni_rsrc_detect\n", NI_ERRNO); + p_hw_device_info->err_code = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; } -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_LOCK, 0); -#endif - p_device_queue = p_device_pool->p_device_queue; + //info start + memcpy(module_id_arr, coders->xcoders[preferential_device_type], sizeof(int32_t) * module_count);//copy useful card - // assume all XCODER types are grouped - count = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_DECODER]; - int guid; - for (i = 0; i < count; i++) - { - int has_xcoder[NI_DEVICE_TYPE_XCODER_MAX] = {0}; - char xc_lck_name[NI_DEVICE_TYPE_XCODER_MAX][32] = {0}; - ni_device_context_t *p_xcoder_device_ctx[NI_DEVICE_TYPE_XCODER_MAX] = { - NULL}; + //First module ID in coders->decoders/encoders is of lowest load + // memcpy((void *)&best_load_module_id, module_id_arr, sizeof(int32_t)); + qsort(module_id_arr, module_count, sizeof(int32_t), int_cmp);// why? - guid = p_device_queue->xcoders[NI_DEVICE_TYPE_DECODER][i]; - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) + // p_hw_device_info->card_current_card = best_load_module_id; + + for(i = 0; i < p_hw_device_info->available_card_num; ++i) + { + for(int j = 0; j < device_type_num; ++j)//need to fix this { - if (p_device_queue->xcoder_cnt[k]) + memset(&xCtxt, 0, sizeof(xCtxt)); + p_device_context = ni_rsrc_get_device_context(all_need_device_type[j], module_id_arr[i]); + if(p_device_context) { - p_xcoder_device_ctx[k] = - ni_rsrc_get_device_context((ni_device_type_t)k, guid); - if (!p_xcoder_device_ctx[k] || - 0 != - strcmp(p_xcoder_device_ctx[k]->p_device_info->dev_name, - dev)) + xCtxt.blk_io_handle = ni_device_open(p_device_context->p_device_info->blk_name, + &(xCtxt.max_nvme_io_size)); + xCtxt.device_handle = xCtxt.blk_io_handle; + //Check device can be opend + if (NI_INVALID_DEVICE_HANDLE == xCtxt.device_handle) { - break; + ni_log(NI_LOG_ERROR, "Error open device %s, blk device %s\n", + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->blk_name); + ni_rsrc_free_device_context(p_device_context); + card_remove[i] = 1; + continue; } - has_xcoder[k] = 1; - } - } - if (k < NI_DEVICE_TYPE_XCODER_MAX) - { - // previous loop ended prematurely - for (j = 0; j <= k; j++) - { - if (!p_xcoder_device_ctx[j]) +#ifdef _WIN32 + xCtxt.event_handle = ni_create_event(); + if (NI_INVALID_EVENT_HANDLE == xCtxt.event_handle) { + ni_rsrc_free_device_context(p_device_context); + ni_device_close(xCtxt.device_handle); + ni_log(NI_LOG_ERROR, "ERROR %d: print_perf() create event\n", NI_ERRNO); + card_remove[i] = 1; continue; } - ni_rsrc_free_device_context(p_xcoder_device_ctx[j]); - } - continue; - } +#endif + //Check decode/encode can be queired + xCtxt.hw_id = p_device_context->p_device_info->hw_id; + if (NI_RETCODE_SUCCESS != ni_device_session_query(&xCtxt, all_need_device_type[j])) + { + ni_device_close(xCtxt.device_handle); +#ifdef _WIN32 + ni_close_event(xCtxt.event_handle); +#endif + ni_log(NI_LOG_ERROR, "Error query %s %s %s.%d\n", + (all_need_device_type[j] == NI_DEVICE_TYPE_DECODER) ? "decoder" : + (all_need_device_type[j] == NI_DEVICE_TYPE_ENCODER) ? "encoder" : + (all_need_device_type[j] == NI_DEVICE_TYPE_SCALER) ? "scaler " : "AIs ", + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->blk_name, + p_device_context->p_device_info->hw_id); + ni_rsrc_free_device_context(p_device_context); + card_remove[i] = 1; + continue; + } + ni_device_close(xCtxt.device_handle); +#ifdef _WIN32 + ni_close_event(xCtxt.event_handle); +#endif + if (0 == xCtxt.load_query.total_contexts) + { + xCtxt.load_query.current_load = 0; + } - // found the device_info and remove its lock and storage - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - if (has_xcoder[k]) + p_hw_device_info->card_info[j][i].card_idx = p_device_context->p_device_info->module_id; + + //use model_load in card remove for encoder just like before +#ifdef XCODER_311 + p_hw_device_info->card_info[j][i].load = xCtxt.load_query.current_load; //monitor changes this + +#else + p_hw_device_info->card_info[j][i].load = + (xCtxt.load_query.total_contexts == 0 || xCtxt.load_query.current_load > xCtxt.load_query.fw_load) ? xCtxt.load_query.current_load : xCtxt.load_query.fw_load; +#endif + // module_load_user_can_not_see[j][i] = xCtxt.load_query.fw_model_load; + p_hw_device_info->card_info[j][i].model_load = xCtxt.load_query.fw_model_load; + + p_hw_device_info->card_info[j][i].task_num = xCtxt.load_query.total_contexts; + p_hw_device_info->card_info[j][i].max_task_num = NI_MAX_CONTEXTS_PER_HW_INSTANCE; + if(consider_mem) + { + // mem_usage[i] = xCtxt.load_query.fw_share_mem_usage; + p_hw_device_info->card_info[j][i].shared_mem_usage = xCtxt.load_query.fw_share_mem_usage; + } + ni_rsrc_free_device_context(p_device_context); + p_device_context = NULL; + } + else { - ni_rsrc_get_lock_name((ni_device_type_t)k, guid, xc_lck_name[k], - sizeof(xc_lck_name[0])); - ni_log(NI_LOG_INFO, "type %d guid %d shm_name: %s lck_name: %s, ", k, guid, - p_xcoder_device_ctx[k]->shm_name, xc_lck_name[k]); + ni_log(NI_LOG_ERROR, "ERROR %d: Failed to get device context\n", NI_ERRNO); + p_hw_device_info->err_code = NI_RETCODE_ERROR_MEM_ALOC; + LRETURN; } } - // remove it from coders queue and decrement device_info counter, re-arrange - // coders queue -#ifdef _WIN32 - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) + + } + + if(coder_param->decoder_param) + { + decoder_need_load = check_hw_info_decoder_need_load(coder_param->decoder_param); + } + if(coder_param->encoder_param) + { + encoder_need_load = check_hw_info_encoder_need_load(coder_param->encoder_param); + } + // if(coder_param->scaler_param) + // { + //cane not estimate scaler load now + // } + + //mark the card removed depends on the load_threshold or task_num_threshold + //in hw_mode ,device_type_num == 3 but only encoder and decoder will be taken into account,we can not estimate scaler load now + //in sw mode ,device_type_num == 1 only preferitial_device_type will be taken into account + for(i = 0; i < p_hw_device_info->available_card_num; ++i) + { + for(int j = 0; j < p_hw_device_info->device_type_num; ++j) { - if (has_xcoder[k]) +#ifdef XCODER_311 + ni_log(NI_LOG_DEBUG, "%s Card[%3d], load: %3d, task_num: %3d, model_load: %3d, shared_mem_usage: %3d\n", +#else + ni_log(NI_LOG_INFO, "%s Card[%3d], load: %3d, task_num: %3d, model_load: %3d, shared_mem_usage: %3d\n", +#endif + (p_hw_device_info->device_type[j] == NI_DEVICE_TYPE_DECODER ? "Decoder" : + ((p_hw_device_info->device_type[j] == NI_DEVICE_TYPE_ENCODER) ? "Encoder" : + (p_hw_device_info->device_type[j] == NI_DEVICE_TYPE_SCALER) ? "Scaler " : "AIs ")), + p_hw_device_info->card_info[j][i].card_idx, + p_hw_device_info->card_info[j][i].load, + p_hw_device_info->card_info[j][i].task_num, + p_hw_device_info->card_info[j][i].model_load, + p_hw_device_info->card_info[j][i].shared_mem_usage); + + if(card_remove[i] == 1) { - CloseHandle(p_xcoder_device_ctx[k]->lock); + continue;//for print } - } - rc = NI_RETCODE_SUCCESS; -#elif __linux__ || __APPLE__ -#ifndef _ANDROID - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) - { - if (has_xcoder[k]) + if(all_need_device_type[j] == NI_DEVICE_TYPE_DECODER) { - if (0 == shm_unlink(p_xcoder_device_ctx[k]->shm_name)) + if(decoder_need_load + p_hw_device_info->card_info[j][i].model_load >= 100) { - ni_log(NI_LOG_INFO, "dev type %d shm_name %s deleted.\n", k, - p_xcoder_device_ctx[k]->shm_name); - } else + card_remove[i] = 1; + } + } + + if(all_need_device_type[j] == NI_DEVICE_TYPE_ENCODER) + { + if(encoder_need_load + p_hw_device_info->card_info[j][i].model_load >= 100) { - ni_log(NI_LOG_ERROR, "dev type %d shm_name %s deletion " - "failure.\n", k, p_xcoder_device_ctx[k]->shm_name); - break; + card_remove[i] =1; } + } + //TODO scaler load - if (0 == unlink(xc_lck_name[k])) + if (task_mode) + { + //in the past customer use model_load to represent load + //for encoder consider model_load like before + if(all_need_device_type[i] == NI_DEVICE_TYPE_ENCODER) { - ni_log(NI_LOG_INFO, "dev type %d lck_name %s deleted.\n", k, - xc_lck_name[k]); - } else + if (p_hw_device_info->card_info[j][i].model_load > hw_info_threshold_param[j].load_threshold || + p_hw_device_info->card_info[j][i].task_num + 1 >= hw_info_threshold_param[j].task_num_threshold) + { + card_remove[i] = 1; + } + } + else { - ni_log(NI_LOG_ERROR, "dev type %d lck_name %s deletion " - "failure.\n", k, xc_lck_name[k]); - break; + if (p_hw_device_info->card_info[j][i].load > hw_info_threshold_param[j].load_threshold || + p_hw_device_info->card_info[j][i].task_num + 1 >= hw_info_threshold_param[j].task_num_threshold) + { + card_remove[i] = 1; + } + } + } + else + { + if (p_hw_device_info->card_info[j][i].task_num > hw_info_threshold_param[j].task_num_threshold) + { + card_remove[i] = 1; } } } -#endif + } -#endif - // move everything after position i forward - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) + if(consider_mem) + { + if(hw_mode) + { + check_hw_info_remove_card_with_memory(card_remove,p_hw_device_info,p_hw_device_info->available_card_num,coder_param,10); + } + else if(preferential_device_type == 0) + { + check_hw_info_remove_card_with_memory(card_remove,p_hw_device_info,p_hw_device_info->available_card_num,coder_param,0); + } + else if(preferential_device_type == 1) + { + check_hw_info_remove_card_with_memory(card_remove,p_hw_device_info,p_hw_device_info->available_card_num,coder_param,1); + } + else if(preferential_device_type == 2) + { + check_hw_info_remove_card_with_memory(card_remove,p_hw_device_info,p_hw_device_info->available_card_num,coder_param,2); + } + } + + if (task_mode) + { + //select the min_task_num + //p_hw_device_info->card_info[0] is the preferential_device_type + int min_task_num = p_hw_device_info->card_info[0][0].max_task_num; + for (i = 0; i < p_hw_device_info->available_card_num; i++) { - for (j = i + 1; j < count; j++) + if (p_hw_device_info->card_info[0][i].task_num < min_task_num && + card_remove[i] == 0) { - p_device_queue->xcoders[k][j - 1] = - p_device_queue->xcoders[k][j]; + min_task_num = p_hw_device_info->card_info[0][i].task_num; } - p_device_queue->xcoders[k][count - 1] = -1; - p_device_queue->xcoder_cnt[k]--; } -#if __linux__ || __APPLE__ - if (msync((void *)p_device_pool->p_device_queue, - sizeof(ni_device_queue_t), MS_SYNC | MS_INVALIDATE)) + //select the min load + int min_load = 100; + for (i = 0; i < p_hw_device_info->available_card_num; i++) { - ni_log(NI_LOG_ERROR, "ERROR %s() msync() p_device_pool->" - "p_device_queue: %s\n", __func__, strerror(NI_ERRNO)); - } else + if (p_hw_device_info->card_info[0][i].load < min_load && + card_remove[i] == 0 && + p_hw_device_info->card_info[0][i].task_num == min_task_num) + { + min_load = p_hw_device_info->card_info[0][i].load; + p_hw_device_info->card_current_card = p_hw_device_info->card_info[0][i].card_idx; + } + } + } + else + { + //p_hw_device_info->card_info[0] is the preferential_device_type + //select the min task num + int min_task_num = p_hw_device_info->card_info[0][0].max_task_num; + for (i = 0; i < p_hw_device_info->available_card_num; i++) { - ni_log(NI_LOG_INFO, "%s deleted successfully !\n", dev); - rc = NI_RETCODE_SUCCESS; + if (p_hw_device_info->card_info[0][i].task_num < min_task_num && + card_remove[i] == 0) + { + p_hw_device_info->card_current_card = p_hw_device_info->card_info[0][i].card_idx; + min_task_num = p_hw_device_info->card_info[0][i].task_num; + } } -#endif - break; } + if (p_hw_device_info->card_current_card >= 0) + { + retval = 1; //has the card to use + } + +END: #ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_ULOCK, 0); + ReleaseMutex((HANDLE)p_device_pool->lock); + +#elif defined(__linux__) + if (lockf(p_device_pool->lock, F_ULOCK,0)) + { + ni_log(NI_LOG_ERROR, "Error lockf() failed\n"); + if(p_hw_device_info) + { + p_hw_device_info->err_code = NI_RETCODE_ERROR_UNLOCK_DEVICE; + } + retval = 0; + } + ni_rsrc_free_device_pool(p_device_pool); + p_device_context = NULL; #endif - ni_rsrc_free_device_pool(p_device_pool); + fflush(stderr); + if (module_id_arr) + { + free(module_id_arr); + module_id_arr = NULL; } - - return rc; + if (dev_ctxt_arr) + { + free(dev_ctxt_arr); + dev_ctxt_arr = NULL; + } + if (card_remove) + { + free(card_remove); + card_remove = NULL; + } + if(b_valid) + { + if(hw_mode) + { +#ifdef XCODER_311 + ni_log(NI_LOG_DEBUG, "In hw_mode select card_current_card %d retval %d\n", +#else + ni_log(NI_LOG_INFO, "In hw_mode select card_current_card %d retval %d\n", +#endif + p_hw_device_info->card_current_card, retval); + } + else + { +#ifdef XCODER_311 + ni_log(NI_LOG_DEBUG, "In sw_mode select device_type %s card_current_card %d retval %d\n", +#else + ni_log(NI_LOG_INFO, "In sw_mode select device_type %s card_current_card %d retval %d\n", +#endif + ((preferential_device_type == 0) ? "decode" : (preferential_device_type == 1 ? "encode" : "scaler")), p_hw_device_info->card_current_card, retval); + } + } + return retval; } + /*!***************************************************************************** -* \brief Add an NetInt h/w device into resource pool on the host. +* \brief Allocate resources for decoding/encoding, based on the provided rule * -* \param[in] p_dev the NVMe device name -* \param[in] should_match_rev 0: transcoder firmware revision matching the -* library's version is NOT required for placing -* the transcoder into resource pool; 1: otherwise +* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +* \param[in] rule allocation rule +* \param[in] codec EN_H264 or EN_H265 +* \param[in] width width of video resolution +* \param[in] height height of video resolution +* \param[in] frame_rate video stream frame rate +* \param[out] p_load the p_load that will be generated by this encoding +* task. Returned *only* for encoder for now. * -* \return -* NI_RETCODE_SUCCESS -* NI_RETCODE_FAILURE +* \return pointer to ni_device_context_t if found, NULL otherwise +* +* Note: codec, width, height, fps need to be supplied for NI_DEVICE_TYPE_ENCODER only, +* they are ignored otherwize. +* Note: the returned ni_device_context_t content is not supposed to be used by +* caller directly: should only be passed to API in the subsequent +* calls; also after its use, the context should be released by +* calling ni_rsrc_free_device_context. *******************************************************************************/ -int ni_rsrc_add_device(const char* dev, int should_match_rev) +ni_device_context_t *ni_rsrc_allocate_auto( + ni_device_type_t device_type, + ni_alloc_rule_t rule, + ni_codec_t codec, + int width, int height, + int frame_rate, + uint64_t *p_load) { - uint32_t i, j = 0, k = 0, count, fw_ver_compat_warning = 0; - int ret = 0; - ni_retcode_t rc = NI_RETCODE_SUCCESS; - ni_device_handle_t fd = 0; - ni_device_queue_t *p_device_queue; - ni_device_info_t device_info; - ni_device_capability_t cap; - ni_device_pool_t *p_device_pool = ni_rsrc_get_device_pool(); - - if (!dev) - { - ni_log(NI_LOG_ERROR, "ERROR: bad input parameter in %s()\n", __func__); - return NI_RETCODE_FAILURE; - } - // get the biggest guid, increment it by 1 and use it as the new guid - if (p_device_pool) - { -#ifdef _WIN32 - if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) //we got the mutex - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", - __func__, p_device_pool->lock); - } -#elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_LOCK, 0); -#endif - - p_device_queue = p_device_pool->p_device_queue; - count = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_DECODER]; - int32_t guid = -1; - for (i = 0; i < count; i++) - { - ni_device_context_t *tmp_ctxt = ni_rsrc_get_device_context( - NI_DEVICE_TYPE_DECODER, - p_device_queue->xcoders[NI_DEVICE_TYPE_DECODER][i]); - if (tmp_ctxt && 0 == strcmp(tmp_ctxt->p_device_info->dev_name, dev)) - { - rc = NI_RETCODE_FAILURE; - ni_log(NI_LOG_ERROR, "ERROR: Transcoder %s already active, guid: " - "%d\n", dev, - p_device_queue->xcoders[NI_DEVICE_TYPE_DECODER][i]); - ni_rsrc_free_device_context(tmp_ctxt); - LRETURN; - } else - { - ni_rsrc_free_device_context(tmp_ctxt); - } + ni_device_pool_t *p_device_pool = NULL; + ni_device_info_t *p_device_info = NULL; + ni_device_context_t *p_device_context = NULL; + ni_session_context_t p_session_context = {0}; + int *coders = NULL; + int i = 0, count = 0, rc = NI_RETCODE_FAILURE; + int guid = -1; + int load = 0; + uint32_t num_sw_instances = 0; + int least_model_load = 0; + uint64_t job_mload = 0; - if (p_device_queue->xcoders[NI_DEVICE_TYPE_DECODER][i] > guid) - { - guid = p_device_queue->xcoders[NI_DEVICE_TYPE_DECODER][i]; - } - } - guid++; - // retrieve the device_info capability info from f/w - memset(&device_info, 0, sizeof(ni_device_info_t)); - ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN, "%s", dev); - if (ret < 0) + if(device_type != NI_DEVICE_TYPE_DECODER && device_type != NI_DEVICE_TYPE_ENCODER) { - rc = NI_RETCODE_FAILURE; - LRETURN; + ni_log2(NULL, NI_LOG_ERROR, "ERROR: Device type %d is not allowed\n", device_type); + return NULL; } - memset(&cap, 0, sizeof(ni_device_capability_t)); - - uint32_t tmp_io_size; - - ni_find_blk_name(device_info.dev_name, device_info.blk_name, sizeof(device_info.blk_name)); - fd = ni_device_open(device_info.blk_name, &tmp_io_size); + /*! retrieve the record and based on the allocation rule specified, find the + least loaded or least number of s/w instances among the coders */ + p_device_pool = ni_rsrc_get_device_pool(); - if (NI_INVALID_DEVICE_HANDLE == fd) + if (!p_device_pool) { - rc = NI_RETCODE_FAILURE; - ni_log(NI_LOG_ERROR, "Failed to open device: %s\n", device_info.dev_name); - LRETURN; + ni_log2(NULL, NI_LOG_ERROR, "ERROR: %s() Could not get device pool\n", __func__); + return NULL; } - rc = ni_device_capability_query(fd, &cap); - if ((NI_RETCODE_SUCCESS == rc) && - (is_supported_xcoder(cap.device_is_xcoder)) && - (!should_match_rev || ni_is_fw_compatible(cap.fw_rev))) + ni_device_session_context_init(&p_session_context); +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) //we got the mutex { - fw_ver_compat_warning = 0; - if (ni_is_fw_compatible(cap.fw_rev) == 2) - { - ni_log(NI_LOG_INFO, "WARNING - Query %s FW version: %.*s is below the minimum support version for " - "this SW version. Some features may be missing.\n", - device_info.dev_name, (int) sizeof(cap.fw_rev), cap.fw_rev); - fw_ver_compat_warning = 1; - } - - ni_log(NI_LOG_INFO, "%s num_hw: %d\n", device_info.dev_name, cap.hw_elements_cnt); - uint32_t total_modules = cap.xcoder_devices_cnt; + ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", __func__, p_device_pool->lock); + } +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_LOCK, 0); +#endif - ni_device_info_t *pCoderInfo = NULL; - for (j = 0; j < total_modules; j++) - { - pCoderInfo = NULL; + coders = p_device_pool->p_device_queue->xcoders[device_type]; + count = p_device_pool->p_device_queue->xcoder_cnt[device_type]; - memset(&device_info, 0, sizeof(ni_device_info_t)); - ret = snprintf(device_info.dev_name, NI_MAX_DEVICE_NAME_LEN, "%s", dev); - if (ret < 0) + for (i = 0; i < count; i++) + { + /*! get the individual device_info info and check the load/num-of-instances */ + p_device_context = ni_rsrc_get_device_context(device_type, coders[i]); + if (!p_device_context) { - rc = NI_RETCODE_FAILURE; - LRETURN; - } - ni_find_blk_name(device_info.dev_name, device_info.blk_name, sizeof(device_info.blk_name)); - device_info.hw_id = cap.xcoder_devices[j].hw_id; - device_info.fw_ver_compat_warning = fw_ver_compat_warning; - memcpy(device_info.fw_rev, cap.fw_rev, sizeof(device_info.fw_rev)); - - memcpy(device_info.fw_branch_name, cap.fw_branch_name, sizeof(device_info.fw_branch_name) - 1); - memcpy(device_info.fw_commit_time, cap.fw_commit_time, - sizeof(device_info.fw_commit_time) - 1); - memcpy(device_info.fw_commit_hash, cap.fw_commit_hash, - sizeof(device_info.fw_commit_hash) - 1); - memcpy(device_info.fw_build_time, cap.fw_build_time, - sizeof(device_info.fw_build_time) - 1); - memcpy(device_info.fw_build_id, cap.fw_build_id, - sizeof(device_info.fw_build_id) - 1); - - device_info.max_fps_4k = cap.xcoder_devices[j].max_4k_fps; - device_info.max_instance_cnt = cap.xcoder_devices[j].max_number_of_contexts; - device_info.device_type = (ni_device_type_t) cap.xcoder_devices[j].codec_type; - - // check if entry has been created for this h/w (hw_id): - // if not, then create a new entry; otherwise just update it - ni_device_context_t *p_device_context = ni_rsrc_get_device_context(device_info.device_type, guid); - if ( (p_device_context) && (p_device_context->p_device_info->hw_id == device_info.hw_id) ) - { - pCoderInfo = p_device_context->p_device_info; - } - ni_codec_t fmt = (ni_codec_t) cap.xcoder_devices[j].codec_format; - if (pCoderInfo) - { - ni_log(NI_LOG_INFO, "%s h/w id %d update\n", - device_type_str[device_info.device_type], device_info.hw_id); - rc = ni_rsrc_fill_device_info(pCoderInfo, fmt, - device_info.device_type, - &cap.xcoder_devices[j]); + ni_log(NI_LOG_ERROR, + "ERROR: %s() ni_rsrc_get_device_context() failed\n", __func__); + continue; } - else - { - ni_log(NI_LOG_INFO, "%s h/w id %d create\n", - device_type_str[device_info.device_type], device_info.hw_id); - pCoderInfo = &device_info; - rc = ni_rsrc_fill_device_info(pCoderInfo, fmt, - device_info.device_type, - &cap.xcoder_devices[j]); - if (NI_RETCODE_SUCCESS == rc) - { - /*! add the h/w device_info entry */ - pCoderInfo->module_id = guid; - p_device_queue->xcoder_cnt[device_info.device_type]++; - p_device_queue->xcoders - [device_info.device_type] - [p_device_queue->xcoder_cnt[device_info.device_type] - 1] = - pCoderInfo->module_id; - ni_rsrc_get_one_device_info(&device_info); - } - } - if (p_device_context) + // p_first retrieve status from f/w and update storage + + p_session_context.blk_io_handle = ni_device_open(p_device_context->p_device_info->dev_name, &p_session_context.max_nvme_io_size); + p_session_context.device_handle = p_session_context.blk_io_handle; + + if (NI_INVALID_DEVICE_HANDLE == p_session_context.device_handle) { + ni_log(NI_LOG_ERROR, "ERROR %s() ni_device_open() %s: %s\n", + __func__, p_device_context->p_device_info->dev_name, + strerror(NI_ERRNO)); ni_rsrc_free_device_context(p_device_context); + continue; } - } // for each device_info module -#if __linux__ || __APPLE__ - if (msync((void *)p_device_pool->p_device_queue, sizeof(ni_device_queue_t), - MS_SYNC | MS_INVALIDATE)) - { - ni_log(NI_LOG_ERROR, "ERROR %s() msync() p_device_pool->" - "p_device_queue: %s\n", __func__, strerror(NI_ERRNO)); - rc = NI_RETCODE_FAILURE; - } else - ni_log(NI_LOG_INFO, "%s added successfully !\n", dev); -#endif - } - else - { // xcoder NOT supported - rc = NI_RETCODE_FAILURE; - ni_log(NI_LOG_INFO, "Query %s rc %d not a supported xcoder: %u, or " - "mismatch revision: %.*s; not added\n", dev, rc, - cap.device_is_xcoder, (int) sizeof(cap.fw_rev), cap.fw_rev); - } - if (NI_INVALID_DEVICE_HANDLE != fd) - { - ni_device_close(fd); - } + p_session_context.hw_id = p_device_context->p_device_info->hw_id; + rc = ni_device_session_query(&p_session_context, device_type); + + ni_device_close(p_session_context.device_handle); - END: + if (NI_RETCODE_SUCCESS != rc) + { + ni_log(NI_LOG_ERROR, "ERROR: query %s %s.%d\n", + g_device_type_str[device_type], + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + ni_rsrc_free_device_context(p_device_context); + continue; + } #ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); + if (WAIT_ABANDONED == WaitForSingleObject(p_device_context->lock, INFINITE)) // no time-out interval) //we got the mutex + { + ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %p\n", + __func__, p_device_context->lock); + } #elif __linux__ || __APPLE__ - lockf(p_device_pool->lock, F_ULOCK, 0); + lockf(p_device_context->lock, F_LOCK, 0); #endif + ni_rsrc_update_record(p_device_context, &p_session_context); - ni_rsrc_free_device_pool(p_device_pool); - } + p_device_info = p_device_context->p_device_info; + if (i == 0) + { + guid = coders[i]; + load = p_device_info->load; + least_model_load = p_device_info->model_load; + num_sw_instances = p_device_info->active_num_inst; + } - return rc; -} + ni_log(NI_LOG_INFO, "Coder [%d]: %d , load: %d (%d), activ_inst: %d , max_inst %d\n", + i, coders[i], p_device_info->load, p_device_info->model_load, p_device_info->active_num_inst, + p_device_info->max_instance_cnt); + + switch (rule) + { + case EN_ALLOC_LEAST_INSTANCE: + { + if (p_device_info->active_num_inst < num_sw_instances) + { + guid = coders[i]; + num_sw_instances = p_device_info->active_num_inst; + } + break; + } + + case EN_ALLOC_LEAST_LOAD: + default: + { + if (NI_DEVICE_TYPE_ENCODER == device_type) + { + if (p_device_info->model_load < least_model_load) + { + guid = coders[i]; + least_model_load = p_device_info->model_load; + } + } + else if (p_device_info->load < load) + { + guid = coders[i]; + load = p_device_info->load; + } + break; + } + } -/*!***************************************************************************** -* \brief Free all resources taken by the device pool -* -* \param[in] p_device_pool Poiner to a device pool struct -* -* \return None -*******************************************************************************/ -void ni_rsrc_free_device_pool(ni_device_pool_t* p_device_pool) -{ - if (p_device_pool) - { - if (NI_INVALID_LOCK_HANDLE != p_device_pool->lock) - { #ifdef _WIN32 - CloseHandle(p_device_pool->lock); + ReleaseMutex(p_device_context->lock); #elif __linux__ || __APPLE__ - close(p_device_pool->lock); + lockf(p_device_context->lock, F_ULOCK, 0); #endif + ni_rsrc_free_device_context(p_device_context); } -#ifdef _WIN32 - UnmapViewOfFile(p_device_pool->p_device_queue); -#else - munmap(p_device_pool->p_device_queue, sizeof(ni_device_queue_t)); -#endif - - free(p_device_pool); - } -} - -/*!***************************************************************************** - * \brief lock a file lock and open a session on a device - * - * \param device_type - * \param lock - * - * \return None - *******************************************************************************/ -int ni_rsrc_lock_and_open(int device_type, ni_lock_handle_t* lock) -{ - - int count = 0; - int status = NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; -#ifdef _WIN32 - *lock = CreateMutex(NULL, FALSE, XCODERS_RETRY_LCK_NAME[device_type]); - if (NULL == *lock) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() CreateMutex() %s failed: %s\n", - __func__, XCODERS_RETRY_LCK_NAME[device_type], - strerror(NI_ERRNO)); - return NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; - } -#else - do - { - if (count>=1) + if (guid >= 0) { - //sleep 10ms if the file lock is locked by other FFmpeg process - ni_usleep(LOCK_WAIT); - } - // Here we try to open the file lock, retry if it failed - *lock = - open(XCODERS_RETRY_LCK_NAME[device_type], O_RDWR | O_CREAT | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + p_device_context = ni_rsrc_get_device_context(device_type, guid); + if (!p_device_context) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s() ni_rsrc_get_device_context() failed\n", __func__); + LRETURN; + } - if (*lock < 0) - { - count++; - if (count > MAX_LOCK_RETRY) - { - ni_log(NI_LOG_ERROR, "Can not lock down the file lock after 6s"); - return NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; - } - } - } - while (*lock < 0); -#endif - // Now the lock is free so we lock it down - count = 0; - do - { - //sleep 10ms if the file lock is locked by other FFmpeg process - if (count>=1) - { - //sleep 10ms if the file lock is locked by other FFmpeg process - ni_usleep(LOCK_WAIT); - } -#ifdef _WIN32 - DWORD ret = WaitForSingleObject(*lock, 1); // time-out 1ms - if (WAIT_OBJECT_0 == ret) - { - status = NI_RETCODE_SUCCESS; - } else if (WAIT_TIMEOUT != ret) - { - ni_log(NI_LOG_ERROR, "ERROR: %s() failed to obtain mutex: %s\n", - __func__, strerror(NI_ERRNO)); + if (NI_DEVICE_TYPE_ENCODER == device_type) + { + job_mload = width * height * frame_rate; + } } -#else - status = lockf(*lock, F_LOCK, 0); -#endif - if (status != 0) + else { - count++; - if (count > MAX_LOCK_RETRY) - { - ni_log(NI_LOG_ERROR, "Can not put down the lock after 6s"); - return NI_RETCODE_ERROR_LOCK_DOWN_DEVICE; - } + ni_log(NI_LOG_ERROR, "ERROR: %s() cannot find guid\n", __func__); + p_device_context = NULL; } - } - while (status != 0); - - return NI_RETCODE_SUCCESS; -} - -/*!***************************************************************************** - * \brief unlock a file lock - * - * \param device_type - * \param lock - * - * \return None - *******************************************************************************/ -int ni_rsrc_unlock(int device_type, ni_lock_handle_t lock) -{ - if (lock == NI_INVALID_LOCK_HANDLE) - { - return NI_RETCODE_FAILURE; - } - int count = 0; - ni_lock_handle_t status = NI_INVALID_LOCK_HANDLE; - do - { - if (count >= 1) - { - ni_usleep(LOCK_WAIT); - } +END: #ifdef _WIN32 - if (ReleaseMutex(lock)) - { - status = (ni_lock_handle_t)(0); - } -#else - status = lockf(lock, F_ULOCK, 0); + ReleaseMutex(p_device_pool->lock); +#elif __linux__ || __APPLE__ + lockf(p_device_pool->lock, F_ULOCK, 0); #endif - count++; - if (count > MAX_LOCK_RETRY) - { - ni_log(NI_LOG_ERROR, "Can not unlock the lock after 6s"); - return NI_RETCODE_ERROR_UNLOCK_DEVICE; - } - } while (status != (ni_lock_handle_t)(0)); - -#ifdef _WIN32 - CloseHandle(lock); -#else - close(lock); -#endif //_WIN32 defined - return NI_RETCODE_SUCCESS; -} + ni_device_session_context_clear(&p_session_context); + ni_rsrc_free_device_pool(p_device_pool); -/*!***************************************************************************** -* \brief check if device FW revision is compatible with SW API -* -* \param fw_rev -* -* \return 1 for full compatibility, 2 for partial, 0 for none -*******************************************************************************/ -int ni_rsrc_is_fw_compat(uint8_t fw_rev[8]) -{ - return ni_is_fw_compatible(fw_rev); + if (p_load) + { + *p_load = job_mload; + } + return p_device_context; } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.h index 44984853..51be8e93 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api.h @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_rsrc_api.h -* -* \brief Exported definitions related to resource management of NI Quadra devices -* -*******************************************************************************/ + * \file ni_rsrc_api.h + * + * \brief Public definitions for managing NETINT video processing devices + ******************************************************************************/ #pragma once @@ -56,12 +55,8 @@ typedef enum EN_CODEC_MAX } ni_codec_t; -static const char *ni_codec_format_str[] = {"H.264", "H.265", "VP9", "JPEG", - "AV1"}; -static const char *ni_dec_name_str[] = {"h264_ni_quadra_dec", "h265_ni_quadra_dec", - "vp9_ni_quadra_dec", "jpeg_ni_quadra_dec"}; -static const char *ni_enc_name_str[] = {"h264_ni_quadra_enc", "h265_ni_quadra_enc", "empty", - "jpeg_ni_quadra_enc", "av1_ni_quadra_enc"}; +extern bool g_device_in_ctxt; +extern ni_device_handle_t g_dev_handle; typedef enum { @@ -69,12 +64,6 @@ typedef enum EN_ACTIVE } ni_sw_instance_status_t; -typedef enum -{ - EN_ALLOC_LEAST_LOAD, - EN_ALLOC_LEAST_INSTANCE -} ni_alloc_rule_t; - typedef struct _ni_device_queue { uint32_t xcoder_cnt[NI_DEVICE_TYPE_XCODER_MAX]; @@ -118,9 +107,12 @@ typedef struct _ni_device_info int module_id; /*! global unique id, assigned at creation */ int load; /*! p_load value retrieved from f/w */ int model_load; /*! p_load value modelled internally */ - unsigned long xcode_load_pixel; /*! xcode p_load in pixels: encoder only */ + uint64_t xcode_load_pixel; /*! xcode p_load in pixels: encoder only */ int fw_ver_compat_warning; // fw revision is not supported by this libxcoder - uint8_t fw_rev[8]; // fw revision + uint8_t fl_ver_nor_flash[8]; // firmware loader version stored in nor flash + uint8_t fl_ver_last_ran[8]; + uint8_t fw_rev_nor_flash[8]; // fw revision stored in nor flash + uint8_t fw_rev[8]; // fw revision loaded, i.e., running uint8_t fw_branch_name[256]; uint8_t fw_commit_time[26]; uint8_t fw_commit_hash[41]; @@ -157,6 +149,110 @@ typedef struct _ni_device_context ni_device_info_t * p_device_info; } ni_device_context_t; +typedef struct _ni_card_info_quadra +{ + int card_idx; + int load; + int model_load; + int task_num; + int max_task_num; + int shared_mem_usage; +} ni_card_info_quadra_t; + +typedef struct _ni_hw_device_info_quadra +{ + int available_card_num; + int device_type_num; + int consider_mem; + ni_device_type_t *device_type; + ni_card_info_quadra_t **card_info; + int card_current_card; + int err_code; +} ni_hw_device_info_quadra_t; + +typedef struct _ni_hw_device_info_quadra_encoder_param +{ + uint32_t fps;/*! encoder fps*/ + uint32_t h;/*! height*/ + uint32_t w;/*! width*/ + uint32_t code_format;/*! 1 for h264,2 for h265,3 for av1,4 for JPEG*/ + uint32_t ui8enableRdoQuant; + uint32_t rdoLevel; + uint32_t lookaheadDepth;/*! lookaheadDepth [0:40]*/ + uint32_t bit_8_10;/*! 8 for 8 bit,10 for 10 bit*/ + int uploader;/*1 for uploader,0 for not uploader*/ + int rgba;/*1 for rgba,0 for not*/ +}ni_hw_device_info_quadra_encoder_param_t; + +typedef struct _ni_hw_device_info_quadra_decoder_param +{ + uint32_t fps;/*! decoder fps*/ + uint32_t h;/*! height*/ + uint32_t w;/*! width*/ + uint32_t bit_8_10;/*! 8 for 8 bit,10 for 10 bit*/ + int rgba;/*!decoder for rgba? 1 for rgba,0 for not*/ + int hw_frame;/*if out=hw,1 for out = hw_frame,0 for not*/ +}ni_hw_device_info_quadra_decoder_param_t; + +typedef struct _ni_hw_device_info_quadra_scaler_param +{ + uint32_t h;/*!output height*/ + uint32_t w;/*!output width*/ + uint32_t bit_8_10;/*! 8 for 8 bit,10 for 10 bit*/ + int rgba;/*!output for rgba? 1 for rgba,0 for not*/ +}ni_hw_device_info_quadra_scaler_param_t; + +typedef struct _ni_hw_device_info_quadra_ai_param +{ + uint32_t h;/*!output height*/ + uint32_t w;/*!output width*/ + uint32_t bit_8_10;/*! 8 for 8 bit,10 for 10 bit*/ + int rgba;/*!output for rgba? 1 for rgba,0 for not*/ +}ni_hw_device_info_quadra_ai_param_t; + +typedef struct _ni_hw_device_info_quadra_threshold_param +{ + ni_device_type_t device_type; + int load_threshold; + int task_num_threshold; +}ni_hw_device_info_quadra_threshold_param_t; + +typedef struct _ni_hw_device_info_quadra_coder_param +{ + int hw_mode; + ni_hw_device_info_quadra_encoder_param_t *encoder_param; + ni_hw_device_info_quadra_decoder_param_t *decoder_param; + ni_hw_device_info_quadra_scaler_param_t *scaler_param; + ni_hw_device_info_quadra_ai_param_t *ai_param; +}ni_hw_device_info_quadra_coder_param_t; +typedef struct _ni_device_vf_ns_id +{ + uint16_t vf_id; + uint16_t ns_id; +} ni_device_vf_ns_id_t; + +typedef struct _ni_device_temp +{ + int32_t composite_temp; + int32_t on_board_temp; + int32_t on_die_temp; +} ni_device_temp_t; + +typedef struct _ni_device_extra_info +{ + int32_t composite_temp; + int32_t on_board_temp; + int32_t on_die_temp; + uint32_t power_consumption; + uint32_t reserve[4]; +} ni_device_extra_info_t; + +typedef enum +{ + EN_ALLOC_LEAST_LOAD, + EN_ALLOC_LEAST_INSTANCE +} ni_alloc_rule_t; + /*!****************************************************************************** * \brief Initialize and create all resources required to work with NETINT NVMe * transcoder devices. This is a high level API function which is used @@ -322,23 +418,15 @@ LIB_API void ni_rsrc_print_all_devices_capability2(bool list_uninitialized); LIB_API ni_device_info_t* ni_rsrc_get_device_info(ni_device_type_t device_type, int guid); /*!**************************************************************************** - -* \brief Get the least used device that can handle decoding or encoding -* a video stream of certain resolution/frame-rate/codec. +* \brief Get GUID of the device by block device name and type * -* \param[in] width width of video resolution -* \param[in] height height of video resolution -* \param[in] frame_rate video stream frame rate -* \param[in] codec EN_H264 or EN_H265 -* \param[in] type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[out] info detailed device information. If is non-NULL, the -* device info is stored in the memory pointed to by it. +* \param[in] blk_name device's block name +* \param[in] type device type * -* \return device GUID (>= 0) if found , -1 otherwise +* \return device GUID (>= 0) if found, NI_RETCODE_FAILURE (-1) otherwise *******************************************************************************/ -LIB_API int ni_rsrc_get_available_device(int width, int height, int frame_rate, - ni_codec_t codec, ni_device_type_t device_type, - ni_device_info_t * p_device_info); +LIB_API int ni_rsrc_get_device_by_block_name(const char *blk_name, + ni_device_type_t device_type); /*!***************************************************************************** * \brief Update the load value and s/w instances info of a specific decoder or @@ -353,68 +441,9 @@ LIB_API int ni_rsrc_get_available_device(int width, int height, int frame_rate, * NI_RETCODE_SUCCESS * NI_RETCODE_FAILURE *******************************************************************************/ -LIB_API int ni_rsrc_update_device_load(ni_device_context_t* p_ctxt, int load, +int ni_rsrc_update_device_load(ni_device_context_t* p_ctxt, int load, int sw_instance_cnt, const ni_sw_instance_info_t sw_instance_info[]); -/*!***************************************************************************** -* \brief Allocate resources for decoding/encoding, based on the provided rule -* -* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[in] rule allocation rule -* \param[in] codec EN_H264 or EN_H265 -* \param[in] width width of video resolution -* \param[in] height height of video resolution -* \param[in] frame_rate video stream frame rate -* \param[out] p_load the load that will be generated by this encoding -* task. Returned *only* for encoder for now. -* -* \return pointer to ni_device_context_t if found, NULL otherwise -* -* Note: codec, width, height, fps need to be supplied for NI_DEVICE_TYPE_ENCODER only, -* they are ignored otherwize. -* Note: the returned ni_device_context_t content is not supposed to be used by -* caller directly: should only be passed to API in the subsequent -* calls; also after its use, the context should be released by -* calling ni_rsrc_free_device_context. -*******************************************************************************/ -LIB_API ni_device_context_t* ni_rsrc_allocate_auto( ni_device_type_t device_type, - ni_alloc_rule_t rule, - ni_codec_t codec, - int width, int height, - int frame_rate, - unsigned long *p_load); - -/*!***************************************************************************** -* \brief Allocate resources for decoding/encoding, by designating explicitly -* the device to use. -* -* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER -* \param[in] guid unique device (decoder or encoder) module id -* \param[in] codec EN_H264 or EN_H265 -* \param[in] width width of video resolution -* \param[in] height height of video resolution -* \param[in] frame_rate video stream frame rate -* \param[out] p_load the load that will be generated by this encoding -* task. Returned *only* for encoder for now. -* -* \return pointer to ni_device_context_t if found, NULL otherwise -* -* Note: codec, width, height, fps need to be supplied by encoder; they -* are ignored for decoder. -* -* Note: the returned ni_device_context_t content is not supposed to be used by -* caller directly: should only be passed to API in the subsequent -* calls; also after its use, the context should be released by -* calling ni_rsrc_free_device_context. -*******************************************************************************/ -LIB_API ni_device_context_t* ni_rsrc_allocate_direct( ni_device_type_t device_type, - int guid, - ni_codec_t codec, - int width, - int height, - int frame_rate, - unsigned long *p_load); - /*!***************************************************************************** * \brief Allocate resources for decoding/encoding, by designating explicitly * the device to use. do not track the load on the host side @@ -448,7 +477,7 @@ ni_device_context_t *ni_rsrc_allocate_simple_direct * \return None *******************************************************************************/ LIB_API void ni_rsrc_release_resource(ni_device_context_t *p_ctxt, - unsigned long load); + uint64_t load); /*!***************************************************************************** * \brief check the NetInt h/w device in resource pool on the host. @@ -472,6 +501,17 @@ LIB_API int ni_rsrc_check_hw_available(int guid, ni_device_type_t device_type); *******************************************************************************/ LIB_API int ni_rsrc_remove_device(const char* p_dev); +/*!***************************************************************************** +* \brief Remove all NetInt h/w devices from resource pool on the host. +* +* \param none +* +* \return +* NI_RETCODE_SUCCESS +* NI_RETCODE_FAILURE +*******************************************************************************/ +LIB_API int ni_rsrc_remove_all_devices(void); + /*!***************************************************************************** * \brief Add an NetInt h/w device into resource pool on the host. * @@ -482,6 +522,7 @@ LIB_API int ni_rsrc_remove_device(const char* p_dev); * * \return * NI_RETCODE_SUCCESS +* NI_RETCODE_INVALID_PARAM * NI_RETCODE_FAILURE *******************************************************************************/ LIB_API int ni_rsrc_add_device(const char* p_dev, int should_match_rev); @@ -542,6 +583,117 @@ LIB_API int ni_rsrc_unlock(int device_type, ni_lock_handle_t lock); *******************************************************************************/ LIB_API int ni_rsrc_is_fw_compat(uint8_t fw_rev[8]); +/*!****************************************************************************** + * \brief Create a pointer to hw_device_info_coder_param_t instance .This instance will be created and + * set to default vaule by param mode.You may change the resolution fps bit_8_10 or other vaule you want to set. + * + * \param[in] mode:0:create instance with decoder_param ,encoder_param, scaler_param and ai_param will be set to NULL + * 1:create instance with encoder_param ,decoder_param, scaler_param and ai_param will be set to NULL + * 2:create instance with scaler_param ,decoder_param, encoder_param and ai_param will be set to NULL + * 3:create instance with ai_param ,decoder_param, encoder_param and scaler_param will be set to NULL + * >= 4:create instance with decoder_param encoder_param scaler_param and ai_param for ni_check_hw_info() hw_mode + * + * \return NULL-error,pointer to an instance when success + *******************************************************************************/ +LIB_API ni_hw_device_info_quadra_coder_param_t *ni_create_hw_device_info_quadra_coder_param(int mode); + +/*!****************************************************************************** + * \brief Release a pointer to hw_device_info_coder_param_t instance created by create_hw_device_info_coder_param + * + * + * \param[in] p_hw_device_info_coder_param:pointer to a hw_device_info_coder_param_t instance created by create_hw_device_info_coder_param + * + *******************************************************************************/ +LIB_API void ni_destory_hw_device_info_quadra_coder_param(ni_hw_device_info_quadra_coder_param_t *p_hw_device_info_quadra_coder_param); + +/*!****************************************************************************** + * \brief Create a pointer to ni_hw_device_info_quadra_t instance . + * + * \param[in] device_type_num:number of device type to be allocated in this function + * + * \param[in] avaliable_card_num:number of avaliable card per device to be allocated in this function + * + * \return NULL-error,pointer to an instance when success + *******************************************************************************/ +LIB_API ni_hw_device_info_quadra_t *ni_hw_device_info_alloc_quadra(int device_type_num,int avaliable_card_num); + +/*!****************************************************************************** + * \brief Release a pointer to ni_hw_device_info_quadra_t instance created by create_hw_device_info_coder_param + * + * + * \param[in] p_hw_device_info:pointer to a ni_hw_device_info_quadra_t instance created by create_hw_device_info_coder_param + * + *******************************************************************************/ +LIB_API void ni_hw_device_info_free_quadra(ni_hw_device_info_quadra_t *p_hw_device_info); + +/*!***************************************************************************** + * \brief check hw info, return the appropriate card number to use depends on the load&task_num&used resource + * + * \param[out] pointer_to_p_hw_device_info : pointer to user-supplied ni_hw_device_info_quadra_t (allocated by ni_hw_device_info_alloc). + * May be a ponter to NULL ,in which case a ni_hw_device_info_quadra_coder_param_t is allocated by this function + * and written to pointer_to_p_hw_device_info. + * record the device info, including available card num and which card to select, + * and each card's informaton, such as, the load, task num, device type + * \param[in] task_mode: affect the scheduling strategy, + * 1 - both the load_num and task_num should consider, usually applied to live scenes + * 0 - only consider the task_num, don not care the load_num + * \param[in] hw_info_threshold_param : an array of threshold including device type task threshold and load threshold + * in hw_mode fill the arry with both encoder and decoder threshold or + * fill the arry with preferential device type threshold when don not in hw_mode + * load threshold in range[0:100] task num threshold in range [0:32] + * \param[in] preferential_device_type : which device type is preferential 0:decode 1:encode . + * This need to set to encoder/decoder even if in sw_mode to check whether coder_param is wrong. + * \param[in] coder_param : encoder and decoder information that helps to choose card .This coder_param can be created and + * set to default value by function hw_device_info_coder_param_t * create_hw_device_info_coder_param(). + * You may change the resolution fps bit_8_10 or other vaule you want to use + * \param[in] hw_mode:Set 1 then this function will choose encoder and decoder in just one card . + * When no card meets the conditions ,NO card will be choosed. + * You can try to use set hw_mode 0 to use sw_mode to do encoder/decoder in different card when hw_mode reports an error + * In hw_mode set both encoder_param and decoder_param in coder_param. + * Set 0 then just consider sw_mode to choose which card to do encode/decode, + * In sw_mode set one param in coder_param the other one will be set to NULL. + * \param[in] consider_mem : set 1 this function will consider memory usage extra + * set 0 this function will not consider memory usage + * + * \return 0-error 1-success + *******************************************************************************/ +LIB_API int ni_check_hw_info(ni_hw_device_info_quadra_t **pointer_to_p_hw_device_info, + int task_mode, + ni_hw_device_info_quadra_threshold_param_t *hw_info_threshold_param, + ni_device_type_t preferential_device_type, + ni_hw_device_info_quadra_coder_param_t * coder_param, + int hw_mode, + int consider_mem); + + +/*!***************************************************************************** +* \brief Allocate resources for decoding/encoding, based on the provided rule +* +* \param[in] device_type NI_DEVICE_TYPE_DECODER or NI_DEVICE_TYPE_ENCODER +* \param[in] rule allocation rule +* \param[in] codec EN_H264 or EN_H265 +* \param[in] width width of video resolution +* \param[in] height height of video resolution +* \param[in] frame_rate video stream frame rate +* \param[out] p_load the load that will be generated by this encoding +* task. Returned *only* for encoder for now. +* +* \return pointer to ni_device_context_t if found, NULL otherwise +* +* Note: codec, width, height, fps need to be supplied for NI_DEVICE_TYPE_ENCODER only, +* they are ignored otherwize. +* Note: the returned ni_device_context_t content is not supposed to be used by +* caller directly: should only be passed to API in the subsequent +* calls; also after its use, the context should be released by +* calling ni_rsrc_free_device_context. +*******************************************************************************/ +LIB_API ni_device_context_t* ni_rsrc_allocate_auto( ni_device_type_t device_type, + ni_alloc_rule_t rule, + ni_codec_t codec, + int width, int height, + int frame_rate, + uint64_t *p_load); + #ifdef __cplusplus } #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api_android.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api_android.h index 638377e7..32c93e5b 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api_android.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_api_android.h @@ -20,12 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_rsrc_api_android.h -* -* \brief Exported definitions related to resource management of NI Quadra devices -* -*******************************************************************************/ - + * \file ni_rsrc_api_android.h + * + * \brief Public definitions for managing NETINT video processing devices on + * Android + ******************************************************************************/ #ifndef ANDROID_NI_RSRC_API_H #define ANDROID_NI_RSRC_API_H diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_list.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_list.c index dbe0f060..9d985a4d 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_list.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_list.c @@ -20,15 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** + * \file ni_rsrc_list.c * - * \file ni_rsrc_list.c - * - * @date April 1, 2018 - * - * \brief - * - * @author - * + * \brief Application to query and print info about NETINT video processing + * devices on system ******************************************************************************/ #if __linux__ || __APPLE__ @@ -44,14 +39,6 @@ #include "ni_rsrc_api.h" #include "ni_util.h" - -/*!****************************************************************************** - * \brief - * - * \param - * - * \return - *******************************************************************************/ int32_t main(int argc, char *argv[]) { int opt; diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_mon.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_mon.c index 0d57a901..cf0a0dbb 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_mon.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_mon.c @@ -20,15 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** + * \file ni_rsrc_mon.c * - * \file ni_rsrc_mon.c - * - * @date April 1, 2018 - * - * \brief - * - * @author - * + * \brief Application to query and print live performance/load info of + * registered NETINT video processing devices on system ******************************************************************************/ #if __linux__ || __APPLE__ @@ -38,6 +33,7 @@ #include #include +#include #include #include @@ -48,13 +44,38 @@ #include "ni_rsrc_priv.h" #include "ni_util.h" +#define MAX_DEVICE_NAME_SIZE (9) +#define ABSOLUTE_TEMP_ZERO (-273) +#define NP_LOAD (0) +#define TP_LOAD (1) +#define PCIE_LOAD (2) + +uint32_t* g_temp_load = NULL; //TP load storage +uint32_t* g_temp_pload = NULL; //Pcie load storage +uint32_t* g_temp_pthroughput = NULL; //Pcie throughput storage +uint32_t* g_temp_sharemem = NULL; //TP sharedmem storage + +ni_device_handle_t device_handles[NI_DEVICE_TYPE_XCODER_MAX] + [NI_MAX_DEVICE_CNT] = {0}; + #ifdef _ANDROID #include #define PROP_DECODER_TYPE "nidec_service_init" - +#define LOG_TAG "ni_rsrc_mon" #endif +enum outFormat +{ + FMT_TEXT, + FMT_FULL_TEXT, + FMT_SIMPLE_TEXT, + FMT_JSON, + FMT_JSON1, + FMT_JSON2, + FMT_EXTRA +}; + #ifdef _WIN32 #include "ni_getopt.h" @@ -116,8 +137,94 @@ void setup_signal_handler(void) perror("ERROR: signal handler setup"); } } + +/*!****************************************************************************** + * \brief get PCIe address + * + * \param[in] char *device_name e.g. /dev/nvme0n1 + * + * \return void + * *******************************************************************************/ +void get_pcie_addr(char *device_name, char *pcie) +{ + get_dev_pcie_addr(device_name, pcie, NULL, NULL, NULL, NULL); +} + +/*!****************************************************************************** + * \brief get linux numa_node + * + * \param[in] char *device_name + * + * \return int atoi(cmd_ret) + *******************************************************************************/ +int get_numa_node(char *device_name) +{ + int ret = -1; + FILE *cmd_fp; + char *ptr = NULL; + char cmd[128] = {0}; + char cmd_ret[64] = {0}; + + if(!device_name) + { + return ret; + } + ptr = device_name + 5; + snprintf(cmd, sizeof(cmd) - 1, "cat /sys/block/%s/device/*/numa_node",ptr); + cmd_fp = popen(cmd, "r"); + if (!cmd_fp) + { + return ret; + } + if (fgets(cmd_ret, sizeof(cmd_ret)/sizeof(cmd_ret[0]), cmd_fp) == 0) + { + goto get_numa_node_ret; + } + ret = atoi(cmd_ret); + +get_numa_node_ret: + pclose(cmd_fp); + return ret; +} + #endif //__linux__ +/*!****************************************************************************** + * \brief remove one device from stored device_handles + * + * \param ni_device_type_t device_type + * + * \param int32_t module_id + * + * \param ni_device_handle_t device_handle + * + * \return int 0 for success, -1 for failure + *******************************************************************************/ +int remove_device_from_saved(ni_device_type_t device_type, int32_t module_id, + ni_device_handle_t device_handle) +{ + if (!IS_XCODER_DEVICE_TYPE(device_type)) + { + fprintf(stderr, "Error: device_type %d is not a valid device type\n", + device_type); + return -1; + } + ni_device_type_t xcoder_device_type = GET_XCODER_DEVICE_TYPE(device_type); + if (device_handles[xcoder_device_type][module_id] == device_handle) + { + device_handles[xcoder_device_type][module_id] = + NI_INVALID_DEVICE_HANDLE; + return 0; + } else + { + fprintf(stderr, + "Error: device_handle to remove %d" + "not match device_handles[%d][%d]=%d\n", + device_handle, device_type, module_id, + device_handles[xcoder_device_type][module_id]); + return -1; + } +} /*!****************************************************************************** * \brief convert number from argv input to integer if safe @@ -164,153 +271,2039 @@ int compareInt32_t(const void *a, const void *b) return 0; } -/*!****************************************************************************** - * \brief print performance data for either decoder or encoder - * - * \param[in] ni_device_type_t module_type - * \param[in] ni_device_queue_t *coders - * \param[in] ni_session_context_t *sessionCtxt - * - * \return ni_retcode_t rc - *******************************************************************************/ -void print_perf(ni_device_type_t module_type, ni_device_queue_t *coders, - ni_session_context_t *sessionCtxt) +unsigned int get_modules(ni_device_type_t device_type, + ni_device_queue_t *p_device_queue, + char *device_name, + int32_t **module_ids) +{ + unsigned int device_count; + size_t size_of_i32; + + size_of_i32 = sizeof(int32_t); + + device_count = p_device_queue->xcoder_cnt[device_type]; + *module_ids = malloc(size_of_i32 * device_count); + if (!(*module_ids)) + { + fprintf(stderr, "ERROR: malloc() failed for module_ids\n"); + return 0; + } + + memcpy(*module_ids, + p_device_queue->xcoders[device_type], + size_of_i32 * device_count); + + qsort(*module_ids, + device_count, + size_of_i32, + compareInt32_t); + + strncpy(device_name, + g_device_type_str[device_type], + MAX_DEVICE_NAME_SIZE); + + return device_count; +} + +bool open_and_query(ni_device_type_t device_type, + ni_device_context_t *p_device_context, + ni_session_context_t *p_session_context, + char *device_name, int detail, ni_instance_mgr_detail_status_v1_t *detail_data_v1) +{ + ni_retcode_t return_code; + + if (!p_device_context) + { + return false; + } + + // check if device has been opened already + ni_device_type_t xcoder_device_type = GET_XCODER_DEVICE_TYPE(device_type); + int module_id = p_device_context->p_device_info->module_id; + if (device_handles[xcoder_device_type][module_id] != NI_INVALID_DEVICE_HANDLE) + { + p_session_context->device_handle = + device_handles[xcoder_device_type][module_id]; + } else + { + p_session_context->device_handle = + ni_device_open(p_device_context->p_device_info->dev_name, + &p_session_context->max_nvme_io_size); + if (p_session_context->device_handle != NI_INVALID_DEVICE_HANDLE) + { + device_handles[xcoder_device_type][module_id] = + p_session_context->device_handle; + } + } + + if (p_session_context->device_handle == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, + "ERROR: ni_device_open() failed for %s: %s\n", + p_device_context->p_device_info->dev_name, + strerror(NI_ERRNO)); + ni_rsrc_free_device_context(p_device_context); + return false; + } + + p_session_context->blk_io_handle = + p_session_context->device_handle; + p_session_context->hw_id = + p_device_context->p_device_info->hw_id; + + if(detail) + { + if (ni_cmp_fw_api_ver((char*) &p_device_context->p_device_info->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6i") < 0) + { + fprintf(stderr, + "ERROR: cannot print detailed info for %s as it has FW API " + "version < 6.i\n", p_device_context->p_device_info->dev_name); + return false; + } + else if (ni_cmp_fw_api_ver((char*)&p_device_context->p_device_info->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6r6") < 0) + { + return_code = ni_device_session_query_detail(p_session_context, + GET_XCODER_DEVICE_TYPE(device_type), (ni_instance_mgr_detail_status_t *)detail_data_v1); + } + else + { + return_code = ni_device_session_query_detail_v1(p_session_context, + GET_XCODER_DEVICE_TYPE(device_type), detail_data_v1); + } + } + else + { + return_code = ni_device_session_query(p_session_context, + GET_XCODER_DEVICE_TYPE(device_type)); + } + if (return_code != NI_RETCODE_SUCCESS) + { + fprintf(stderr, + "ERROR: ni_device_session_query() returned %d for %s:%s:%d\n", + return_code, + device_name, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + remove_device_from_saved(device_type, module_id, + p_session_context->device_handle); + ni_device_close(p_session_context->device_handle); + ni_rsrc_free_device_context(p_device_context); + return false; + } + + if (!p_session_context->load_query.total_contexts) + { + p_session_context->load_query.current_load = 0; + } + + memcpy(p_session_context->fw_rev, + p_device_context->p_device_info->fw_rev, + 8); + + return true; +} + +bool open_and_get_log(ni_device_context_t *p_device_context, + ni_session_context_t *p_session_context, + void** p_log_buffer, + bool gen_log_file) { - int i; // used in later FOR-loop when compiled without c99 - int module_count = 0; - char module_name[8]; - ni_device_context_t *dev_ctxt_arr = NULL; + ni_retcode_t return_code; + if (!p_device_context) + return false; + + p_session_context->device_handle = + ni_device_open(p_device_context->p_device_info->blk_name, + &p_session_context->max_nvme_io_size); + if (p_session_context->device_handle == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, + "ERROR: ni_device_open() failed for %s: %s\n", + p_device_context->p_device_info->blk_name, + strerror(NI_ERRNO)); + ni_rsrc_free_device_context(p_device_context); + return false; + } + p_session_context->blk_io_handle = + p_session_context->device_handle; + p_session_context->hw_id = + p_device_context->p_device_info->module_id; + + return_code = ni_device_alloc_and_get_firmware_logs(p_session_context, p_log_buffer, gen_log_file); + return return_code ? false : true; +} + +void dump_fw_log(ni_device_queue_t *coders, ni_session_context_t *sessionCtxt, int devid) +{ + int i; + unsigned int module_count; int32_t *module_id_arr = NULL; + char module_name[MAX_DEVICE_NAME_SIZE]; ni_device_context_t *p_device_context = NULL; + ni_device_type_t module_type = NI_DEVICE_TYPE_DECODER; - if (!IS_XCODER_DEVICE_TYPE(module_type)) - { - fprintf(stderr, "ERROR: unsupported module_type %d\n", module_type); - return; + module_count = get_modules(module_type, coders, module_name, &module_id_arr); + if (!module_count) { + printf("Error: module not found!\n"); + return; } - module_count = coders->xcoder_cnt[module_type]; - strcpy(module_name, device_type_str[module_type]); - dev_ctxt_arr = malloc(sizeof(ni_device_context_t) * module_count); - if (!dev_ctxt_arr) + bool gen_log_file = true; // dump and write fw logs to runtime dir + + void* p_log_buffer = NULL; + if (devid >= 0 && devid < module_count) { - fprintf(stderr, "ERROR: malloc() failed for dev_ctxt_arr\n"); - return; + // dump fw logs of specified card + p_device_context = ni_rsrc_get_device_context(module_type, module_id_arr[devid]); + if (p_device_context->p_device_info->module_id == devid) + { + if (!open_and_get_log(p_device_context, sessionCtxt, &p_log_buffer, gen_log_file)) { + printf("Error: failed to dump fw log of card:%d blk_name:%s\n", + devid, p_device_context->p_device_info->blk_name); + } else { + printf("Success: dumped fw log of card:%d blk_name:%s\n", + devid, p_device_context->p_device_info->blk_name); + } + ni_device_close(sessionCtxt->device_handle); + ni_rsrc_free_device_context(p_device_context); + } } - module_id_arr = malloc(sizeof(int32_t) * module_count); - if (!module_id_arr) + else { - fprintf(stderr, "ERROR: malloc() failed for module_id_arr\n"); - free(dev_ctxt_arr); - return; + // dump fw logs of all quadra cards + for (i = 0; i < module_count; i++) + { + p_device_context = ni_rsrc_get_device_context(module_type, module_id_arr[i]); + if (!open_and_get_log(p_device_context, sessionCtxt, &p_log_buffer, gen_log_file)) { + printf("Error: failed to dump fw log of card:%d blk_name:%s\n", + p_device_context->p_device_info->module_id, + p_device_context->p_device_info->blk_name); + } else { + printf("Success: dumped fw log of card:%d blk_name:%s\n", + p_device_context->p_device_info->module_id, + p_device_context->p_device_info->blk_name); + } + ni_device_close(sessionCtxt->device_handle); + ni_rsrc_free_device_context(p_device_context); + } } - memcpy(module_id_arr, coders->xcoders[module_type], - sizeof(int32_t) * module_count); - printf("Num %ss: %d\n", device_type_str[module_type], module_count); + free(p_log_buffer); + free(module_id_arr); +} - // gotta test how long this sorting takes (SZ) - // sort module IDs used - qsort(module_id_arr, module_count, sizeof(int32_t), compareInt32_t); - - // Print performance info headings - if (IS_XCODER_DEVICE_TYPE(module_type)) +bool swap_encoder_and_uploader(ni_device_type_t *p_device_type, + char *device_name) +{ + switch (*p_device_type) { - printf("%-5s %-4s %-10s %-4s %-4s %-9s %-7s %-14s %-20s\n", "INDEX", "LOAD", - "MODEL_LOAD", "INST", "MEM", "SHARE_MEM", "P2P_MEM", "DEVICE", "NAMESPACE"); + case NI_DEVICE_TYPE_ENCODER: + *p_device_type = NI_DEVICE_TYPE_UPLOAD; + strcpy(device_name, "uploader"); + return true; + case NI_DEVICE_TYPE_UPLOAD: + *p_device_type = NI_DEVICE_TYPE_ENCODER; + default: + return false; } +} + +#define DYN_STR_BUF_CHUNK_SIZE 4096 +typedef struct dyn_str_buf +{ + int str_len; // Note: this does not include EOL char + int buf_size; + char *str_buf; // Pointer to string +} dyn_str_buf_t; + +/*!***************************************************************************** + * \brief Accumulate string data in a dynamically sized buffer. This is + * useful to separate error messages from json and table output. + * + * \param[in] *dyn_str_buf pointer to structure holding dyn_str_buf info + * \param[in] *fmt printf format specifier + * \param[in] ... additional arguments + * + * \return 0 for success, -1 for error + ******************************************************************************/ +int strcat_dyn_buf(dyn_str_buf_t *dyn_str_buf, const char *fmt, ...) +{ + int avail_buf; + int formatted_len; + int add_buf_size = 0; + char *tmp_char_ptr = NULL; + + if (!dyn_str_buf) + { + fprintf(stderr, "ERROR: invalid param *dyn_str_buf\n"); + return -1; + } + + if (!fmt) + { + return 0; + } + + va_list vl, tmp_vl; + va_start(vl, fmt); + va_copy(tmp_vl, vl); + + // determine length of string to add + formatted_len = vsnprintf(NULL, 0, fmt, tmp_vl); + va_end(tmp_vl); + + // check if str_buf needs to be expanded in increments of chunk size + avail_buf = dyn_str_buf->buf_size - dyn_str_buf->str_len; + add_buf_size = (formatted_len + 1) > avail_buf ? + ((formatted_len + 1 - avail_buf + DYN_STR_BUF_CHUNK_SIZE - 1) / + DYN_STR_BUF_CHUNK_SIZE) * + DYN_STR_BUF_CHUNK_SIZE : + 0; - /*! query each coder and print out their status */ - for (i = 0; i < module_count; i++) + // realloc() to expand str_buf if necessary + if (add_buf_size) + { + tmp_char_ptr = (char *)realloc(dyn_str_buf->str_buf, + sizeof(char) * dyn_str_buf->buf_size + + add_buf_size); + if (!tmp_char_ptr) + { + fprintf(stderr, "ERROR: strcat_dyn_buf() failed realloc()\n"); + va_end(vl); + return -1; + } + dyn_str_buf->str_buf = tmp_char_ptr; + dyn_str_buf->buf_size += add_buf_size; + } + + // concatenate string to buffer + vsprintf(dyn_str_buf->str_buf + dyn_str_buf->str_len, fmt, vl); + dyn_str_buf->str_len += formatted_len; + + va_end(vl); + return 0; +} + +void clear_dyn_str_buf(dyn_str_buf_t *dyn_str_buf) +{ + free(dyn_str_buf->str_buf); + memset(dyn_str_buf, 0, sizeof(dyn_str_buf_t)); +} + +void print_full_text(ni_device_queue_t *p_device_queue, + ni_session_context_t *p_session_context, int detail, ni_instance_mgr_detail_status_v1_t *detail_data_v1) +{ + char device_name[MAX_DEVICE_NAME_SIZE] = {0}; + unsigned int index, device_count; + int32_t *module_ids; + dyn_str_buf_t output_buf = {0}; + + ni_device_context_t *p_device_context; + ni_device_type_t device_type; + ni_load_query_t load_query; + ni_retcode_t return_code; + + for (device_type = NI_DEVICE_TYPE_DECODER; + device_type != NI_DEVICE_TYPE_XCODER_MAX; + device_type++) + { + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + if (!device_count) + { + continue; + } +UPLOADER: + strcat_dyn_buf(&output_buf, "Num %ss: %u\n", device_name, device_count); + + switch (device_type) + { + case NI_DEVICE_TYPE_DECODER: + strcat_dyn_buf(&output_buf, + "INDEX LOAD(VPU MODEL FW ) INST MEM(TOTAL CRITICAL SHARE ) " + "DEVICE L_FL2V N_FL2V FR N_FR\n"); + break; + case NI_DEVICE_TYPE_SCALER: + case NI_DEVICE_TYPE_AI: + strcat_dyn_buf(&output_buf, + "INDEX LOAD(VPU FW ) INST MEM(TOTAL SHARE ) " + "DEVICE L_FL2V N_FL2V FR N_FR\n"); + break; + case NI_DEVICE_TYPE_ENCODER: + strcat_dyn_buf(&output_buf, + "INDEX LOAD(VPU MODEL FW ) INST MEM(TOTAL CRITICAL SHARE P2P) " + "DEVICE L_FL2V N_FL2V FR N_FR\n"); + break; + case NI_DEVICE_TYPE_UPLOAD: + strcat_dyn_buf(&output_buf, + "INDEX LOAD( FW ) INST MEM(TOTAL SHARE P2P) " + "DEVICE L_FL2V N_FL2V FR N_FR\n"); + break; + default: + break; + } + + for (index = 0; index < device_count; index++) + { + p_device_context = + ni_rsrc_get_device_context(device_type, + module_ids[index]); + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + switch (device_type) + { + case NI_DEVICE_TYPE_DECODER: + strcat_dyn_buf(&output_buf, + "%-5d %-3u %-3u %-3u %-3u/%-3d %-3u %-3u " + "%-3u %-11s %-8.8s %-8.8s %-8.8s %-8.8s\n", + p_device_context->p_device_info->module_id, + p_session_context->load_query.current_load, + p_session_context->load_query.fw_model_load, + p_session_context->load_query.fw_load, + p_session_context->load_query.total_contexts, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_video_shared_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash); + break; + case NI_DEVICE_TYPE_SCALER: + case NI_DEVICE_TYPE_AI: + strcat_dyn_buf(&output_buf, + "%-5d %-3u %-3u %-3u/%-3d %-3u " + "%-3u %-11s %-8.8s %-8.8s %-8.8s %-8.8s\n", + p_device_context->p_device_info->module_id, + p_session_context->load_query.current_load, + p_session_context->load_query.fw_load, + p_session_context->load_query.total_contexts, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash); + break; + case NI_DEVICE_TYPE_ENCODER: + strcat_dyn_buf(&output_buf, + "%-5d %-3u %-3u %-3u %-3u/%-3d %-3u %-3u " + "%-3u %-3u %-11s %-8.8s %-8.8s %-8.8s %-8.8s\n", + p_device_context->p_device_info->module_id, + p_session_context->load_query.current_load, + p_session_context->load_query.fw_model_load, + p_session_context->load_query.fw_load, + p_session_context->load_query.total_contexts, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_video_shared_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_session_context->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash); + break; + case NI_DEVICE_TYPE_UPLOAD: + strcat_dyn_buf(&output_buf, + "%-5d %-3u %-3u/%-3d %-3u " + "%-3u %-3u %-11s %-8.8s %-8.8s %-8.8s %-8.8s\n", + p_device_context->p_device_info->module_id, + p_session_context->load_query.fw_load, + p_session_context->load_query.active_hwuploaders, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_session_context->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash); + break; + default: + break; + } + + ni_rsrc_free_device_context(p_device_context); + } + + if (swap_encoder_and_uploader(&device_type, device_name)) + { + goto UPLOADER; + } + + free(module_ids); + } + + //Nvme[0] and TP[1] and Pcie[2] load + for (int icore = NP_LOAD; icore <= PCIE_LOAD; icore++) + { + // ASSUMPTION: Each Quadra has at least and only one encoder. + device_type = NI_DEVICE_TYPE_ENCODER; + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + + if (icore == NP_LOAD) + { + strcat_dyn_buf(&output_buf, "Num Nvmes: "); + g_temp_load = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_load) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_load\n"); + return; + } + g_temp_pload = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_pload) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_pload\n"); + return; + } + g_temp_pthroughput = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_pthroughput) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_pthroughput\n"); + return; + } + g_temp_sharemem = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_sharemem) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_sharemem\n"); + return; + } + } + else + { + (icore == TP_LOAD)?strcat_dyn_buf(&output_buf, "Num TPs: "):strcat_dyn_buf(&output_buf, "Num PCIes: "); + } + + strcat_dyn_buf(&output_buf, "%u\n", device_count); + if (icore == PCIE_LOAD) + { + strcat_dyn_buf(&output_buf, + "INDEX LOAD( FW ) PCIE_THROUGHPUT GBps " + "DEVICE L_FL2V N_FL2V FR N_FR\n"); + } + else + { + strcat_dyn_buf(&output_buf, + "INDEX LOAD( FW ) MEM( SHARE ) " + "DEVICE L_FL2V N_FL2V FR N_FR\n"); + } + if (!device_count) + { + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + free(g_temp_load); + free(g_temp_pload); + free(g_temp_pthroughput); + free(g_temp_sharemem); + return; + } + + for (index = 0; index < device_count; index++) + { + p_device_context = + ni_rsrc_get_device_context(device_type, + module_ids[index]); + if (icore == NP_LOAD) + { + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + return_code = ni_query_nvme_status(p_session_context, &load_query); + if (return_code != NI_RETCODE_SUCCESS) + { + fprintf(stderr, + "ERROR: ni_query_nvme_status() returned %d for %s:%s:%d\n", + return_code, + device_name, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + remove_device_from_saved(device_type, + p_device_context->p_device_info->module_id, + p_session_context->device_handle); + ni_device_close(p_session_context->device_handle); + goto CLOSE; + } + g_temp_load[index] = load_query.tp_fw_load; + g_temp_pload[index] = load_query.pcie_load; + g_temp_pthroughput[index] = load_query.pcie_throughput; + g_temp_sharemem[index] = load_query.fw_share_mem_usage; + } + if (icore==PCIE_LOAD) + { + load_query.fw_load = g_temp_pload[index]; + load_query.fw_share_mem_usage = g_temp_pthroughput[index]; + + strcat_dyn_buf(&output_buf, + "%-5d %-3u %-3.1f " + "%-11s %-8.8s %-8.8s %-8.8s %-8.8s\n", + p_device_context->p_device_info->module_id, + load_query.fw_load, + (float)load_query.fw_share_mem_usage/10, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash); + } + else + { + load_query.fw_load = (icore==TP_LOAD)?g_temp_load[index]:load_query.fw_load; + load_query.fw_share_mem_usage = (icore==TP_LOAD)?g_temp_sharemem[index]:load_query.fw_share_mem_usage; + + strcat_dyn_buf(&output_buf, + "%-5d %-3u %-3u " + "%-11s %-8.8s %-8.8s %-8.8s %-8.8s\n", + p_device_context->p_device_info->module_id, + load_query.fw_load, + load_query.fw_share_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash); + } + + CLOSE: + ni_rsrc_free_device_context(p_device_context); + } + } + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + free(g_temp_load); + free(g_temp_pload); + free(g_temp_pthroughput); + free(g_temp_sharemem); + free(module_ids); +} + +void print_simple_text(ni_device_queue_t *p_device_queue, + ni_session_context_t *p_session_context, int detail, ni_instance_mgr_detail_status_v1_t *detail_data_v1) +{ + bool copied_block_name; + char block_name[NI_MAX_DEVICE_NAME_LEN] = {0}; + char device_name[MAX_DEVICE_NAME_SIZE] = {0}; + int guid; + unsigned int number_of_quadras; + unsigned int number_of_device_types_present; + unsigned int device_type_counter; + unsigned int *maximum_firmware_loads; + unsigned int *maximum_firmware_loads_per_quadra; + dyn_str_buf_t output_buf = {0}; + + ni_device_context_t *p_device_context; + ni_device_type_t device_type; + ni_device_type_t maximum_device_type; + ni_load_query_t load_query; + ni_retcode_t return_code; + + // Use NI_DEVICE_TYPE_ENCODER instead of NI_DEVICE_TYPE_NVME + // so that Quadras running older firmware will show up. + // Assumption: Each Quadra has at least one encoder. + number_of_quadras = p_device_queue->xcoder_cnt[NI_DEVICE_TYPE_ENCODER]; + + maximum_firmware_loads = calloc(number_of_quadras, sizeof(unsigned int)); + if (!maximum_firmware_loads) + { + fprintf(stderr, "calloc() returned NULL\n"); + return; + } + + maximum_firmware_loads_per_quadra = NULL; + p_device_context = NULL; + + for (guid = 0; guid < number_of_quadras; guid++) + { + maximum_device_type = NI_DEVICE_TYPE_XCODER_MAX; + maximum_firmware_loads_per_quadra = maximum_firmware_loads + guid; + number_of_device_types_present = 0; + device_type_counter = 0; + copied_block_name = false; + + for (device_type = NI_DEVICE_TYPE_DECODER; + device_type < maximum_device_type; + device_type++) + { + if (p_device_queue->xcoders[device_type][guid] != -1) + { + number_of_device_types_present++; + } + } + + for (device_type = NI_DEVICE_TYPE_DECODER; + device_type < maximum_device_type; + device_type++) + { + memcpy(device_name, + g_device_type_str[device_type], + MAX_DEVICE_NAME_SIZE); + + if (p_device_queue->xcoders[device_type][guid] == -1) + { + continue; + } + + p_device_context = + ni_rsrc_get_device_context(device_type, + p_device_queue->xcoders[device_type][guid]); + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + if (ni_cmp_fw_api_ver((char*) &p_session_context->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + "6O") < 0) + { + if (maximum_device_type == NI_DEVICE_TYPE_XCODER_MAX) + { + strcat_dyn_buf(&output_buf, + "%s: Simple output not supported. Try '-o full' " + "instead.\n", + p_device_context->p_device_info->dev_name); + maximum_device_type = NI_DEVICE_TYPE_ENCODER; + } + ni_device_close(p_session_context->device_handle); + ni_rsrc_free_device_context(p_device_context); + continue; + } + + if (!copied_block_name) + { + strncpy(block_name, + p_device_context->p_device_info->dev_name, + NI_MAX_DEVICE_NAME_LEN); + copied_block_name = true; + } + + if (*maximum_firmware_loads_per_quadra < p_session_context->load_query.fw_load) + { + *maximum_firmware_loads_per_quadra = p_session_context->load_query.fw_load; + } + + device_type_counter++; + if (device_type_counter < number_of_device_types_present) + { + remove_device_from_saved(device_type, + p_device_context->p_device_info->module_id, + p_session_context->device_handle); + ni_device_close(p_session_context->device_handle); + ni_rsrc_free_device_context(p_device_context); + } + } + + if (maximum_device_type == NI_DEVICE_TYPE_ENCODER) + { + continue; + } + + //Nvme and TP load + { + return_code = + ni_query_nvme_status(p_session_context, &load_query); + if (return_code == NI_RETCODE_SUCCESS) + { + if (*maximum_firmware_loads_per_quadra < load_query.fw_load) + { + *maximum_firmware_loads_per_quadra = load_query.fw_load; + } + if (*maximum_firmware_loads_per_quadra < load_query.tp_fw_load) + { + *maximum_firmware_loads_per_quadra = load_query.tp_fw_load; + } + strcat_dyn_buf(&output_buf, "%s: %u%%\n", block_name, + *maximum_firmware_loads_per_quadra); + } + else + { + fprintf( + stderr, "ERROR: ni_query_nvme_status() returned %d for %s:%s:%d\n", + return_code, device_name, p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + remove_device_from_saved(device_type, + p_device_context->p_device_info->module_id, + p_session_context->device_handle); + ni_device_close(p_session_context->device_handle); + } + } + + ni_rsrc_free_device_context(p_device_context); + } + + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + free(maximum_firmware_loads); +} + +void print_json(ni_device_queue_t *p_device_queue, + ni_session_context_t *p_session_context, int detail, ni_instance_mgr_detail_status_v1_t *detail_data_v1) +{ + char device_name[MAX_DEVICE_NAME_SIZE] = {0}; + unsigned int index, device_count; + int instance_count; + int32_t *module_ids; + uint32_t total_contexts; + uint32_t vpu_load; + uint32_t model_load; +#ifdef __linux__ + char pcie[64] = {0}; + int numa_node; +#endif + dyn_str_buf_t output_buf = {0}; + + ni_device_context_t *p_device_context; + ni_device_type_t device_type; + ni_load_query_t load_query; + ni_retcode_t return_code; + int max_device_type = NI_DEVICE_TYPE_XCODER_MAX; + if(detail) + max_device_type = NI_DEVICE_TYPE_SCALER; + + for (device_type = NI_DEVICE_TYPE_DECODER; + device_type != max_device_type; + device_type++) { - p_device_context = ni_rsrc_get_device_context(module_type, module_id_arr[i]); + instance_count = 0; + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + if (!device_count) + { + continue; + } - /*! libxcoder query to get status info including load and instances;*/ - if (p_device_context) +UPLOADER: + for (index = 0; index < device_count; index++) { - sessionCtxt->device_handle = - ni_device_open(p_device_context->p_device_info->blk_name, - &sessionCtxt->max_nvme_io_size); - sessionCtxt->blk_io_handle = sessionCtxt->device_handle; + p_device_context = + ni_rsrc_get_device_context(device_type, + module_ids[index]); + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + if (device_type == NI_DEVICE_TYPE_UPLOAD) + { + total_contexts = p_session_context->load_query.active_hwuploaders; + vpu_load = 0; + model_load = 0; + } + else + { + total_contexts = p_session_context->load_query.total_contexts; + vpu_load = p_session_context->load_query.current_load; + model_load = p_session_context->load_query.fw_model_load; + } +#ifdef __linux__ + get_pcie_addr(p_device_context->p_device_info->dev_name, pcie); + numa_node = get_numa_node(p_device_context->p_device_info->dev_name); +#endif - // Check device can be opened - if (NI_INVALID_DEVICE_HANDLE == sessionCtxt->device_handle) + if(detail) + { + strcat_dyn_buf(&output_buf, + "{ \"%s\" :\n" + "\t[\n", + device_name + ); + for(index = 0; index < NI_MAX_CONTEXTS_PER_HW_INSTANCE; index++) + { + if(detail_data_v1->sInstDetailStatus[index].ui16FrameRate) + { + if(device_type == NI_DEVICE_TYPE_DECODER) + { + strcat_dyn_buf(&output_buf, + "\t\t{\n" + "\t\t\t\"NUMBER\": %u,\n" + "\t\t\t\"INDEX\": %u,\n" + "\t\t\t\"AvgCost\": %u,\n" + "\t\t\t\"FrameRate\": %u,\n" + "\t\t\t\"IDR\": %u,\n" + "\t\t\t\"InFrame\": %u,\n" + "\t\t\t\"OutFrame\": %u,\n" + "\t\t\t\"Width\": %u,\n" + "\t\t\t\"Height\": %u,\n" + "\t\t\t\"DEVICE\": \"%s\",\n" + "\t\t},\n", + device_count, + instance_count++, + detail_data_v1->sInstDetailStatus[index].ui8AvgCost, + detail_data_v1->sInstDetailStatus[index].ui16FrameRate, + detail_data_v1->sInstDetailStatus[index].ui32NumIDR, + detail_data_v1->sInstDetailStatus[index].ui32NumInFrame, + detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame, + detail_data_v1->sInstDetailStatusAppend[index].ui32Width, + detail_data_v1->sInstDetailStatusAppend[index].ui32Height, + p_device_context->p_device_info->dev_name); + } + else if (device_type == NI_DEVICE_TYPE_ENCODER) + { + strcat_dyn_buf(&output_buf, + "\t\t{\n" + "\t\t\t\"NUMBER\": %u,\n" + "\t\t\t\"INDEX\": %u,\n" + "\t\t\t\"AvgCost\": %u,\n" + "\t\t\t\"FrameRate\": %u,\n" + "\t\t\t\"IDR\": %u,\n" + "\t\t\t\"UserIDR\": %u,\n" + "\t\t\t\"InFrame\": %u,\n" + "\t\t\t\"OutFrame\": %u,\n" + "\t\t\t\"BR\": %u,\n" + "\t\t\t\"AvgBR\": %u,\n" + "\t\t\t\"Width\": %u,\n" + "\t\t\t\"Height\": %u,\n" + "\t\t\t\"DEVICE\": \"%s\",\n" + "\t\t},\n", + device_count, + instance_count++, + detail_data_v1->sInstDetailStatus[index].ui8AvgCost, + detail_data_v1->sInstDetailStatus[index].ui16FrameRate, + detail_data_v1->sInstDetailStatus[index].ui32NumIDR, + detail_data_v1->sInstDetailStatusAppend[index].ui32UserIDR, + detail_data_v1->sInstDetailStatus[index].ui32NumInFrame, + detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame, + detail_data_v1->sInstDetailStatus[index].ui32BitRate, + detail_data_v1->sInstDetailStatus[index].ui32AvgBitRate, + detail_data_v1->sInstDetailStatusAppend[index].ui32Width, + detail_data_v1->sInstDetailStatusAppend[index].ui32Height, + p_device_context->p_device_info->dev_name); + } + } + } + strcat_dyn_buf(&output_buf, + "\t]\n" + "}\n" + ); + } + else + { + if (p_session_context->overall_load_query.admin_queried && + device_type != NI_DEVICE_TYPE_UPLOAD) + { + strcat_dyn_buf(&output_buf, + "{ \"%s\" :\n" + "\t[\n" + "\t\t{\n" + "\t\t\t\"NUMBER\": %u,\n" + "\t\t\t\"INDEX\": %d,\n" + "\t\t\t\"LOAD\": %u,\n" + "\t\t\t\"LOAD-ALL\": %u,\n" + "\t\t\t\"MODEL_LOAD\": %u,\n" + "\t\t\t\"MODEL_LOAD-ALL\": %u,\n" + "\t\t\t\"FW_LOAD\": %u,\n" + "\t\t\t\"INST\": %u,\n" + "\t\t\t\"INST-ALL\": %u,\n" + "\t\t\t\"MAX_INST\": %d,\n" + "\t\t\t\"MEM\": %u,\n" + "\t\t\t\"CRITICAL_MEM\": %u,\n" + "\t\t\t\"SHARE_MEM\": %u,\n" + "\t\t\t\"P2P_MEM\": %u,\n" + "\t\t\t\"DEVICE\": \"%s\",\n" + "\t\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\t\"FR\": \"%.8s\",\n" + "\t\t\t\"N_FR\": \"%.8s\"" + #ifdef __linux__ + ",\n\t\t\t\"NUMA_NODE\": %d,\n" + "\t\t\t\"PCIE_ADDR\": \"%s\"\n" + #else + ",\n" + #endif + "\t\t}\n" + "\t]\n" + "}\n", + device_name, device_count, + p_device_context->p_device_info->module_id, + vpu_load, + p_session_context->overall_load_query.overall_current_load, + model_load, + p_session_context->overall_load_query.overall_fw_model_load, + p_session_context->load_query.fw_load, total_contexts, + p_session_context->overall_load_query.overall_instance_count, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_video_shared_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_session_context->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash +#ifdef __linux__ + , + numa_node, pcie +#endif + ); + } + else { - fprintf(stderr, "ERROR: ni_device_open() failed for %s: %s\n", - p_device_context->p_device_info->blk_name, strerror(NI_ERRNO)); - ni_rsrc_free_device_context(p_device_context); - continue; + strcat_dyn_buf(&output_buf, + "{ \"%s\" :\n" + "\t[\n" + "\t\t{\n" + "\t\t\t\"NUMBER\": %u,\n" + "\t\t\t\"INDEX\": %d,\n" + "\t\t\t\"LOAD\": %u,\n" + "\t\t\t\"MODEL_LOAD\": %u,\n" + "\t\t\t\"FW_LOAD\": %u,\n" + "\t\t\t\"INST\": %u,\n" + "\t\t\t\"MAX_INST\": %d,\n" + "\t\t\t\"MEM\": %u,\n" + "\t\t\t\"CRITICAL_MEM\": %u,\n" + "\t\t\t\"SHARE_MEM\": %u,\n" + "\t\t\t\"P2P_MEM\": %u,\n" + "\t\t\t\"DEVICE\": \"%s\",\n" + "\t\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\t\"FR\": \"%.8s\",\n" + "\t\t\t\"N_FR\": \"%.8s\"" + #ifdef __linux__ + ",\n\t\t\t\"NUMA_NODE\": %d,\n" + "\t\t\t\"PCIE_ADDR\": \"%s\"\n" + #else + ",\n" + #endif + "\t\t}\n" + "\t]\n" + "}\n", + device_name, device_count, + p_device_context->p_device_info->module_id, + vpu_load, + model_load, + p_session_context->load_query.fw_load, total_contexts, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_video_shared_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_session_context->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash + #ifdef __linux__ + , + numa_node, pcie + #endif + ); } + } + ni_rsrc_free_device_context(p_device_context); + } - // Check xcoder can be queried - sessionCtxt->hw_id = p_device_context->p_device_info->hw_id; - if (NI_RETCODE_SUCCESS != - ni_device_session_query(sessionCtxt, module_type)) + if(!detail) + { + if (swap_encoder_and_uploader(&device_type, device_name)) { - ni_device_close(sessionCtxt->device_handle); - fprintf(stderr, "Error query %s %s.%d\n", module_name, - p_device_context->p_device_info->dev_name, - p_device_context->p_device_info->hw_id); - ni_rsrc_free_device_context(p_device_context); - continue; + goto UPLOADER; } - // printf("Done query %s %s.%d\n", module_name, - // p_device_context->p_device_info->dev_name, - // p_device_context->p_device_info->hw_id); - ni_device_close(sessionCtxt->device_handle); + } + + free(module_ids); + } + if(detail) + { + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + return; + } + + //Nvme[0] and TP[1] load and PCIe[3] load + for (int icore = NP_LOAD; icore <= PCIE_LOAD; icore++) + { + // ASSUMPTION: Each Quadra has at least and only one encoder. + device_type = NI_DEVICE_TYPE_ENCODER; + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + + if (!device_count) + { + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + return; + } + if (icore == NP_LOAD) + { + strcpy(device_name, "nvme"); + g_temp_load = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_load) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_load\n"); + return; + } + g_temp_pload = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_pload) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_pload\n"); + return; + } + g_temp_pthroughput = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_pthroughput) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_pthroughput\n"); + return; + } + g_temp_sharemem = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_sharemem) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_sharemem\n"); + return; + } + } + else + { + (icore == TP_LOAD)?strcpy(device_name, "tp"):strcpy(device_name, "pcie"); + } + for (index = 0; index < device_count; index++) + { + p_device_context = + ni_rsrc_get_device_context(device_type, + module_ids[index]); + if (icore == NP_LOAD) + { + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + return_code = + ni_query_nvme_status(p_session_context, &load_query); + if (return_code != NI_RETCODE_SUCCESS) + { + fprintf(stderr, + "ERROR: ni_query_nvme_status() returned %d for %s:%s:%d\n", + return_code, + device_name, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + remove_device_from_saved(device_type, + p_device_context->p_device_info->module_id, + p_session_context->device_handle); + ni_device_close(p_session_context->device_handle); + goto CLOSE; + } + g_temp_load[index] = load_query.tp_fw_load; + g_temp_pload[index] = load_query.pcie_load; + g_temp_pthroughput[index] = load_query.pcie_throughput; + g_temp_sharemem[index] = load_query.fw_share_mem_usage; + } + + #ifdef __linux__ + get_pcie_addr(p_device_context->p_device_info->dev_name, pcie); + numa_node = get_numa_node(p_device_context->p_device_info->dev_name); + #endif + + if (icore == PCIE_LOAD) + { + strcat_dyn_buf(&output_buf, + "{ \"%s\" :\n" + "\t[\n" + "\t\t{\n" + "\t\t\t\"NUMBER\": %u,\n" + "\t\t\t\"INDEX\": %d,\n" + "\t\t\t\"LOAD\": 0,\n" + "\t\t\t\"MODEL_LOAD\": 0,\n" + "\t\t\t\"FW_LOAD\": %u,\n" + "\t\t\t\"INST\": 0,\n" + "\t\t\t\"MAX_INST\": 0,\n" + "\t\t\t\"MEM\": 0,\n" + "\t\t\t\"CRITICAL_MEM\": 0,\n" + "\t\t\t\"SHARE_MEM\": %u,\n" + "\t\t\t\"PCIE_THROUGHPUT\": %.1f,\n" + "\t\t\t\"P2P_MEM\": 0,\n" + "\t\t\t\"DEVICE\": \"%s\",\n" + "\t\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\t\"FR\": \"%.8s\",\n" + "\t\t\t\"N_FR\": \"%.8s\"" + #ifdef __linux__ + ",\n\t\t\t\"NUMA_NODE\": %d,\n" + "\t\t\t\"PCIE_ADDR\": \"%s\"\n" + #else + ",\n" + #endif + "\t\t}\n" + "\t]\n" + "}\n", + device_name, device_count, + p_device_context->p_device_info->module_id, + g_temp_pload[index], 0, (float)g_temp_pthroughput[index]/10, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash + #ifdef __linux__ + , + numa_node, pcie + #endif + ); + } + else + { + load_query.fw_load = (icore==TP_LOAD)?g_temp_load[index]:load_query.fw_load; + load_query.fw_share_mem_usage = (icore==TP_LOAD)?g_temp_sharemem[index]:load_query.fw_share_mem_usage; + + strcat_dyn_buf(&output_buf, + "{ \"%s\" :\n" + "\t[\n" + "\t\t{\n" + "\t\t\t\"NUMBER\": %u,\n" + "\t\t\t\"INDEX\": %d,\n" + "\t\t\t\"LOAD\": 0,\n" + "\t\t\t\"MODEL_LOAD\": 0,\n" + "\t\t\t\"FW_LOAD\": %u,\n" + "\t\t\t\"INST\": 0,\n" + "\t\t\t\"MAX_INST\": 0,\n" + "\t\t\t\"MEM\": 0,\n" + "\t\t\t\"CRITICAL_MEM\": 0,\n" + "\t\t\t\"SHARE_MEM\": %u,\n" + "\t\t\t\"P2P_MEM\": 0,\n" + "\t\t\t\"DEVICE\": \"%s\",\n" + "\t\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\t\"FR\": \"%.8s\",\n" + "\t\t\t\"N_FR\": \"%.8s\"" + #ifdef __linux__ + ",\n\t\t\t\"NUMA_NODE\": %d,\n" + "\t\t\t\"PCIE_ADDR\": \"%s\"\n" + #else + ",\n" + #endif + "\t\t}\n" + "\t]\n" + "}\n", + device_name, device_count, + p_device_context->p_device_info->module_id, + load_query.fw_load, load_query.fw_share_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash + #ifdef __linux__ + , + numa_node, pcie + #endif + ); + } + CLOSE: + ni_rsrc_free_device_context(p_device_context); + } + } + + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + free(g_temp_load); + free(g_temp_pload); + free(g_temp_pthroughput); + free(g_temp_sharemem); + free(module_ids); +} + +void print_json1(ni_device_queue_t *p_device_queue, + ni_session_context_t *p_session_context, int detail, ni_instance_mgr_detail_status_v1_t *detail_data_v1, int format) +{ + bool has_written_start = false; + char device_name[MAX_DEVICE_NAME_SIZE] = {0}; + unsigned int index, device_count; + int32_t *module_ids; + uint32_t total_contexts; + uint32_t vpu_load; + uint32_t model_load; +#ifdef __linux__ + char pcie[64] = {0}; + int numa_node; +#endif + dyn_str_buf_t output_buf = {0}; + ni_device_extra_info_t p_dev_extra_info = {0}; + char power_consumption[16]; + + ni_device_context_t *p_device_context; + ni_device_type_t device_type; + ni_load_query_t load_query; + ni_retcode_t return_code; + + for (device_type = NI_DEVICE_TYPE_DECODER; + device_type != NI_DEVICE_TYPE_XCODER_MAX; + device_type++) + { + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + if (!device_count) + { + continue; + } + +UPLOADER: + if (!has_written_start) + { + strcat_dyn_buf(&output_buf, "{\n \"%ss\": [\n", device_name); + has_written_start = true; + } + else + { + strcat_dyn_buf(&output_buf, " \"%ss\": [\n", device_name); + } + + for (index = 0; index < device_count; index++) + { + p_device_context = + ni_rsrc_get_device_context(device_type, + module_ids[index]); + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + if (device_type == NI_DEVICE_TYPE_UPLOAD) + { + total_contexts = p_session_context->load_query.active_hwuploaders; + vpu_load = 0; + model_load = 0; + } + else + { + total_contexts = p_session_context->load_query.total_contexts; + vpu_load = p_session_context->load_query.current_load; + model_load = p_session_context->load_query.fw_model_load; + } +#ifdef __linux__ + get_pcie_addr(p_device_context->p_device_info->dev_name, pcie); + numa_node = get_numa_node(p_device_context->p_device_info->dev_name); +#endif + if (format == 2) + { + if (ni_query_extra_info(p_session_context->device_handle, + &p_dev_extra_info, + p_device_context->p_device_info->fw_rev)) + { + p_dev_extra_info.composite_temp = 0; + } + if (p_dev_extra_info.power_consumption + 1) + { + sprintf(power_consumption, "%umW", p_dev_extra_info.power_consumption); + } + } + if (p_session_context->overall_load_query.admin_queried && + device_type != NI_DEVICE_TYPE_UPLOAD) + { + strcat_dyn_buf(&output_buf, + "\t{\n" + "\t\t\"NUMBER\": %u,\n" + "\t\t\"INDEX\": %d,\n" + "\t\t\"LOAD\": %u,\n" + "\t\t\"LOAD-ALL\": %u,\n" + "\t\t\"MODEL_LOAD\": %u,\n" + "\t\t\"MODEL_LOAD-ALL\": %u,\n" + "\t\t\"FW_LOAD\": %u,\n" + "\t\t\"INST\": %u,\n" + "\t\t\"INST-ALL\": %u,\n" + "\t\t\"MAX_INST\": %d,\n" + "\t\t\"MEM\": %u,\n" + "\t\t\"CRITICAL_MEM\": %u,\n" + "\t\t\"SHARE_MEM\": %u,\n" + "\t\t\"P2P_MEM\": %u,\n" + "\t\t\"DEVICE\": \"%s\",\n" + "\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\"FR\": \"%.8s\",\n" + "\t\t\"N_FR\": \"%.8s\"" +#ifdef __linux__ + ",\n\t\t\"NUMA_NODE\": %d,\n" + "\t\t\"PCIE_ADDR\": \"%s\"" +#endif + ,device_count, p_device_context->p_device_info->module_id, + vpu_load, + p_session_context->overall_load_query.overall_current_load, + model_load, + p_session_context->overall_load_query.overall_fw_model_load, + p_session_context->load_query.fw_load, total_contexts, + p_session_context->overall_load_query.overall_instance_count, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_video_shared_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_session_context->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash +#ifdef __linux__ + , + numa_node, pcie +#endif + ); + } else + { + strcat_dyn_buf(&output_buf, + "\t{\n" + "\t\t\"NUMBER\": %u,\n" + "\t\t\"INDEX\": %d,\n" + "\t\t\"LOAD\": %u,\n" + "\t\t\"MODEL_LOAD\": %u,\n" + "\t\t\"FW_LOAD\": %u,\n" + "\t\t\"INST\": %u,\n" + "\t\t\"MAX_INST\": %d,\n" + "\t\t\"MEM\": %u,\n" + "\t\t\"CRITICAL_MEM\": %u,\n" + "\t\t\"SHARE_MEM\": %u,\n" + "\t\t\"P2P_MEM\": %u,\n" + "\t\t\"DEVICE\": \"%s\",\n" + "\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\"FR\": \"%.8s\",\n" + "\t\t\"N_FR\": \"%.8s\"" +#ifdef __linux__ + ",\n\t\t\"NUMA_NODE\": %d,\n" + "\t\t\"PCIE_ADDR\": \"%s\"" +#endif + ,device_count, p_device_context->p_device_info->module_id, + vpu_load, + model_load, + p_session_context->load_query.fw_load, total_contexts, + p_device_context->p_device_info->max_instance_cnt, + p_session_context->load_query.fw_video_mem_usage, + p_session_context->load_query.fw_video_shared_mem_usage, + p_session_context->load_query.fw_share_mem_usage, + p_session_context->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash +#ifdef __linux__ + , + numa_node, pcie +#endif + ); + } + if (format == 2) + { + strcat_dyn_buf(&output_buf, + ",\n\t\t\"TEMP\": %d,\n" + "\t\t\"POWER\": \"%s\"\n" + "\t}", + p_dev_extra_info.composite_temp + ABSOLUTE_TEMP_ZERO, + (p_dev_extra_info.power_consumption + 1) ? power_consumption : "N/A"); + } + else + { + strcat_dyn_buf(&output_buf, "\n\t}"); + } + if (index < device_count - 1) + { + strcat_dyn_buf(&output_buf, ",\n"); + } + else + { + strcat_dyn_buf(&output_buf, "\n"); + } + + ni_rsrc_free_device_context(p_device_context); + } + + strcat_dyn_buf(&output_buf, " ],\n"); + + if (swap_encoder_and_uploader(&device_type, device_name)) + { + goto UPLOADER; + } + + free(module_ids); + } + + //Nvme[0] and TP[1] load + for (int icore = NP_LOAD; icore <= PCIE_LOAD; icore++) + { + // ASSUMPTION: Each Quadra has at least and only one encoder. + device_type = NI_DEVICE_TYPE_ENCODER; + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + + if (!device_count) + { + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + return; + } + if (icore == NP_LOAD) + { + strcat_dyn_buf(&output_buf, " \"nvmes\": [\n"); + g_temp_load = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_load) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_load\n"); + return; + } + g_temp_pload = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_pload) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_pload\n"); + return; + } + g_temp_pthroughput = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_pthroughput) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_pthroughput\n"); + return; + } + g_temp_sharemem = (uint32_t*)calloc(device_count, sizeof(uint32_t)); + if (!g_temp_sharemem) + { + fprintf(stderr, "ERROR: calloc() failed for g_temp_sharemem\n"); + return; + } + } + else + { + (icore == TP_LOAD)?strcat_dyn_buf(&output_buf, " \"tps\": [\n"):strcat_dyn_buf(&output_buf, " \"pcies\": [\n"); + } + for (index = 0; index < device_count; index++) + { + p_device_context = + ni_rsrc_get_device_context(device_type, + module_ids[index]); + if (icore == NP_LOAD) + { + if (!open_and_query(device_type, + p_device_context, + p_session_context, + device_name, detail, detail_data_v1)) + { + continue; + } + + return_code = + ni_query_nvme_status(p_session_context, &load_query); + if (return_code != NI_RETCODE_SUCCESS) + { + fprintf(stderr, + "ERROR: ni_query_nvme_status() returned %d for %s:%s:%d\n", + return_code, + device_name, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + remove_device_from_saved(device_type, + p_device_context->p_device_info->module_id, + p_session_context->device_handle); + ni_device_close(p_session_context->device_handle); + goto CLOSE; + } + g_temp_load[index] = load_query.tp_fw_load; + g_temp_pload[index] = load_query.pcie_load; + g_temp_pthroughput[index] = load_query.pcie_throughput; + g_temp_sharemem[index] = load_query.fw_share_mem_usage; + } +#ifdef __linux__ + get_pcie_addr(p_device_context->p_device_info->dev_name, pcie); + numa_node = get_numa_node(p_device_context->p_device_info->dev_name); +#endif + if (format == 2) + { + if (ni_query_extra_info(p_session_context->device_handle, + &p_dev_extra_info, + p_device_context->p_device_info->fw_rev)) + { + p_dev_extra_info.composite_temp = 0; + } + if (p_dev_extra_info.power_consumption + 1) + { + sprintf(power_consumption, "%umW", p_dev_extra_info.power_consumption); + } + } + + if (icore==PCIE_LOAD) + { + strcat_dyn_buf(&output_buf, + "\t{\n" + "\t\t\"NUMBER\": %u,\n" + "\t\t\"INDEX\": %d,\n" + "\t\t\"LOAD\": 0,\n" + "\t\t\"MODEL_LOAD\": 0,\n" + "\t\t\"FW_LOAD\": %u,\n" + "\t\t\"INST\": 0,\n" + "\t\t\"MAX_INST\": 0,\n" + "\t\t\"MEM\": 0,\n" + "\t\t\"CRITICAL_MEM\": 0,\n" + "\t\t\"SHARE_MEM\": %u,\n" + "\t\t\"PCIE_THROUGHPUT\": %.1f,\n" + "\t\t\"P2P_MEM\": 0,\n" + "\t\t\"DEVICE\": \"%s\",\n" + "\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\"FR\": \"%.8s\",\n" + "\t\t\"N_FR\": \"%.8s\"" +#ifdef __linux__ + ",\n\t\t\"NUMA_NODE\": %d,\n" + "\t\t\"PCIE_ADDR\": \"%s\"" +#endif + ,device_count, p_device_context->p_device_info->module_id, + g_temp_pload[index], 0, (float)g_temp_pthroughput[index]/10, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash +#ifdef __linux__ + , + numa_node, pcie +#endif + ); + } + else + { + load_query.fw_load = (icore==TP_LOAD)?g_temp_load[index]:load_query.fw_load; + load_query.fw_share_mem_usage = (icore==TP_LOAD)?g_temp_sharemem[index]:load_query.fw_share_mem_usage; + + strcat_dyn_buf(&output_buf, + "\t{\n" + "\t\t\"NUMBER\": %u,\n" + "\t\t\"INDEX\": %d,\n" + "\t\t\"LOAD\": 0,\n" + "\t\t\"MODEL_LOAD\": 0,\n" + "\t\t\"FW_LOAD\": %u,\n" + "\t\t\"INST\": 0,\n" + "\t\t\"MAX_INST\": 0,\n" + "\t\t\"MEM\": 0,\n" + "\t\t\"CRITICAL_MEM\": 0,\n" + "\t\t\"SHARE_MEM\": %u,\n" + "\t\t\"P2P_MEM\": 0,\n" + "\t\t\"DEVICE\": \"%s\",\n" + "\t\t\"L_FL2V\": \"%s\",\n" + "\t\t\"N_FL2V\": \"%s\",\n" + "\t\t\"FR\": \"%.8s\",\n" + "\t\t\"N_FR\": \"%.8s\"" +#ifdef __linux__ + ",\n\t\t\"NUMA_NODE\": %d,\n" + "\t\t\"PCIE_ADDR\": \"%s\"" +#endif + ,device_count, p_device_context->p_device_info->module_id, + load_query.fw_load, load_query.fw_share_mem_usage, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->fl_ver_last_ran, + p_device_context->p_device_info->fl_ver_nor_flash, + p_device_context->p_device_info->fw_rev, + p_device_context->p_device_info->fw_rev_nor_flash +#ifdef __linux__ + , + numa_node, pcie +#endif + ); + } + if (format == 2) + { + strcat_dyn_buf(&output_buf, + ",\n\t\t\"TEMP\": %d,\n" + "\t\t\"POWER\": \"%s\"\n" + "\t}", + p_dev_extra_info.composite_temp + ABSOLUTE_TEMP_ZERO, + (p_dev_extra_info.power_consumption + 1) ? power_consumption : "N/A"); + } + else + { + strcat_dyn_buf(&output_buf, "\n\t}"); + } + if (index < device_count - 1) + { + strcat_dyn_buf(&output_buf, ",\n"); + } + else + { + strcat_dyn_buf(&output_buf, "\n"); + if (icore != PCIE_LOAD) + { + strcat_dyn_buf(&output_buf, " ],\n"); + } + } + +CLOSE: + ni_rsrc_free_device_context(p_device_context); + } + } + + strcat_dyn_buf(&output_buf, " ]\n}\n"); + + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + free(g_temp_load); + free(g_temp_pload); + free(g_temp_pthroughput); + free(g_temp_sharemem); + free(module_ids); +} + +void print_text(ni_device_queue_t *coders, + ni_session_context_t *sessionCtxt, int detail, ni_instance_mgr_detail_status_v1_t *detail_data_v1, ni_instance_mgr_detail_status_v1_t (*previous_detail_data_p)[NI_DEVICE_TYPE_XCODER_MAX], int checkInterval) +{ + int i, index, instance_count; // used in later FOR-loop when compiled without c99 + unsigned int module_count; + char module_name[MAX_DEVICE_NAME_SIZE] = {0}; + int32_t *module_id_arr = NULL; + dyn_str_buf_t output_buf = {0}; + ni_device_context_t *p_device_context = NULL; + ni_device_type_t module_type; + int max_device_type = NI_DEVICE_TYPE_XCODER_MAX; + + if(detail) + max_device_type = NI_DEVICE_TYPE_SCALER; + for (module_type = NI_DEVICE_TYPE_DECODER; + module_type != max_device_type; + module_type++) + { + instance_count = 0; + module_count = get_modules(module_type, + coders, + module_name, + &module_id_arr); + + if (!module_count) + { + continue; + } - if (0 == sessionCtxt->load_query.total_contexts) + strcat_dyn_buf(&output_buf, "Num %ss: %u\n", module_name, module_count); + if(detail) + { + if(module_type == NI_DEVICE_TYPE_DECODER) + { + if(checkInterval) + { + strcat_dyn_buf(&output_buf, + "%-5s %-7s %-9s %-5s %-7s %-8s %-4s %-5s %-6s %-14s %-20s\n", "INDEX", + "AvgCost", "FrameRate", "IDR", "InFrame", "OutFrame", "fps", "Width", "Height", + "DEVICE", "NAMESPACE"); + } + else + { + strcat_dyn_buf(&output_buf, + "%-5s %-7s %-9s %-5s %-7s %-8s %-5s %-6s %-14s %-20s\n", "INDEX", + "AvgCost", "FrameRate", "IDR", "InFrame", "OutFrame", "Width", "Height", + "DEVICE", "NAMESPACE"); + } + } + else if (module_type == NI_DEVICE_TYPE_ENCODER) + { + if(checkInterval) + { + strcat_dyn_buf(&output_buf, + "%-5s %-7s %-9s %-5s %-7s %-7s %-8s %-4s %-10s %-10s %-5s %-6s %-14s %-20s\n", "INDEX", + "AvgCost", "FrameRate", "IDR", "UserIDR", "InFrame", "OutFrame", "fps", "BR", "AvgBR", "Width", "Height", + "DEVICE", "NAMESPACE"); + } + else { - sessionCtxt->load_query.current_load = 0; + strcat_dyn_buf(&output_buf, + "%-5s %-7s %-9s %-5s %-7s %-7s %-8s %-10s %-10s %-5s %-6s %-14s %-20s\n", "INDEX", + "AvgCost", "FrameRate", "IDR", "UserIDR", "InFrame", "OutFrame", "BR", "AvgBR", "Width", "Height", + "DEVICE", "NAMESPACE"); } + } + } + else + strcat_dyn_buf(&output_buf, + "%-5s %-4s %-10s %-4s %-4s %-9s %-7s %-14s\n", "INDEX", + "LOAD", "MODEL_LOAD", "INST", "MEM", "SHARE_MEM", "P2P_MEM", + "DEVICE"); + + /*! query each coder and print out their status */ + for (i = 0; i < module_count; i++) + { + p_device_context = ni_rsrc_get_device_context(module_type, module_id_arr[i]); - // Print performance info row - if (IS_XCODER_DEVICE_TYPE(module_type)) + /*! libxcoder query to get status info including load and instances;*/ + if (open_and_query(module_type, + p_device_context, + sessionCtxt, + module_name, detail, detail_data_v1)) + { + if(detail) { - printf("%-5d %-4u %-10u %-4u %-4u %-9u %-7u %-14s %-20s\n", - p_device_context->p_device_info->module_id, - sessionCtxt->load_query.current_load, - sessionCtxt->load_query.fw_model_load, - sessionCtxt->load_query.total_contexts, - sessionCtxt->load_query.fw_video_mem_usage, - sessionCtxt->load_query.fw_share_mem_usage, - sessionCtxt->load_query.fw_p2p_mem_usage, - p_device_context->p_device_info->dev_name, - p_device_context->p_device_info->blk_name); + for(index = 0; index < NI_MAX_CONTEXTS_PER_HW_INSTANCE; index++) + { + if(detail_data_v1->sInstDetailStatus[index].ui16FrameRate) + { + if(previous_detail_data_p && checkInterval) + { + if(previous_detail_data_p[module_type][i].sInstDetailStatus[index].ui16FrameRate) + { + if(module_type == NI_DEVICE_TYPE_DECODER) + { + strcat_dyn_buf(&output_buf, + "%-5d %-7d %-9d %-5u %-7d %-8d %-4d %-5d %-6d %-14s %-20s\n", + instance_count++, + detail_data_v1->sInstDetailStatus[index].ui8AvgCost, + detail_data_v1->sInstDetailStatus[index].ui16FrameRate, + detail_data_v1->sInstDetailStatus[index].ui32NumIDR, + detail_data_v1->sInstDetailStatus[index].ui32NumInFrame, + detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame, + (detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame - previous_detail_data_p[module_type][i].sInstDetailStatus[index].ui32NumOutFrame) / checkInterval, + detail_data_v1->sInstDetailStatusAppend[index].ui32Width, + detail_data_v1->sInstDetailStatusAppend[index].ui32Height, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->blk_name); + } + else if (module_type == NI_DEVICE_TYPE_ENCODER) + { + strcat_dyn_buf(&output_buf, + "%-5d %-7d %-9d %-5u %-7d %-7d %-8d %-4d %-10d %-10d %-5d %-6d %-14s %-20s\n", + instance_count++, + detail_data_v1->sInstDetailStatus[index].ui8AvgCost, + detail_data_v1->sInstDetailStatus[index].ui16FrameRate, + detail_data_v1->sInstDetailStatus[index].ui32NumIDR, + detail_data_v1->sInstDetailStatusAppend[index].ui32UserIDR, + detail_data_v1->sInstDetailStatus[index].ui32NumInFrame, + detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame, + (detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame - previous_detail_data_p[module_type][i].sInstDetailStatus[index].ui32NumOutFrame) / checkInterval, + detail_data_v1->sInstDetailStatus[index].ui32BitRate, + detail_data_v1->sInstDetailStatus[index].ui32AvgBitRate, + detail_data_v1->sInstDetailStatusAppend[index].ui32Width, + detail_data_v1->sInstDetailStatusAppend[index].ui32Height, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->blk_name); + } + } + } + else + { + if(module_type == NI_DEVICE_TYPE_DECODER) + { + strcat_dyn_buf(&output_buf, + "%-5d %-7d %-9d %-5u %-7d %-8d %-5d %-6d %-14s %-20s\n", + instance_count++, + detail_data_v1->sInstDetailStatus[index].ui8AvgCost, + detail_data_v1->sInstDetailStatus[index].ui16FrameRate, + detail_data_v1->sInstDetailStatus[index].ui32NumIDR, + detail_data_v1->sInstDetailStatus[index].ui32NumInFrame, + detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame, + detail_data_v1->sInstDetailStatusAppend[index].ui32Width, + detail_data_v1->sInstDetailStatusAppend[index].ui32Height, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->blk_name); + } + else if (module_type == NI_DEVICE_TYPE_ENCODER) + { + strcat_dyn_buf(&output_buf, + "%-5d %-7d %-9d %-5u %-7d %-7d %-8d %-10d %-10d %-5d %-6d %-14s %-20s\n", + instance_count++, + detail_data_v1->sInstDetailStatus[index].ui8AvgCost, + detail_data_v1->sInstDetailStatus[index].ui16FrameRate, + detail_data_v1->sInstDetailStatus[index].ui32NumIDR, + detail_data_v1->sInstDetailStatusAppend[index].ui32UserIDR, + detail_data_v1->sInstDetailStatus[index].ui32NumInFrame, + detail_data_v1->sInstDetailStatus[index].ui32NumOutFrame, + detail_data_v1->sInstDetailStatus[index].ui32BitRate, + detail_data_v1->sInstDetailStatus[index].ui32AvgBitRate, + detail_data_v1->sInstDetailStatusAppend[index].ui32Width, + detail_data_v1->sInstDetailStatusAppend[index].ui32Height, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->blk_name); + } + } + } + } + if(previous_detail_data_p) + { + memcpy(&previous_detail_data_p[module_type][i], detail_data_v1, sizeof(ni_instance_mgr_detail_status_v1_t)); + } } - ni_rsrc_free_device_context(p_device_context); + else + { + strcat_dyn_buf(&output_buf, + "%-5d %-4u %-10u %-4u %-4u %-9u %-7u %-14s\n", + p_device_context->p_device_info->module_id, +#ifdef XCODER_311 + sessionCtxt->load_query.current_load, +#else + (sessionCtxt->load_query.total_contexts == 0 || sessionCtxt->load_query.current_load > sessionCtxt->load_query.fw_load) ? sessionCtxt->load_query.current_load : sessionCtxt->load_query.fw_load, +#endif + sessionCtxt->load_query.fw_model_load, + sessionCtxt->load_query.total_contexts, + sessionCtxt->load_query.fw_video_mem_usage, + sessionCtxt->load_query.fw_share_mem_usage, + sessionCtxt->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name); + + } + + ni_rsrc_free_device_context(p_device_context); + } } + free(module_id_arr); } - free(dev_ctxt_arr); - free(module_id_arr); - return; + + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); +} + +void print_extra(ni_device_queue_t *p_device_queue, ni_session_context_t *p_session_context) +{ + char device_name[MAX_DEVICE_NAME_SIZE]; + unsigned int index, device_count; + int32_t *module_ids; + dyn_str_buf_t output_buf = {0}; + ni_device_context_t *p_device_context; + ni_device_type_t device_type; + ni_device_extra_info_t p_dev_extra_info = {0}; + char power_consumption[16]; + + // ASSUMPTION: Each Quadra has at least and only one decoder. + device_type = NI_DEVICE_TYPE_DECODER; + device_count = get_modules(device_type, + p_device_queue, + device_name, + &module_ids); + + if (!device_count) + { + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + return; + } + + for (index = 0; index < device_count; index++) + { + p_device_context = ni_rsrc_get_device_context(device_type, module_ids[index]); + if (!p_device_context) + { + continue; + } + // check if device has been opened already + ni_device_type_t xcoder_device_type = GET_XCODER_DEVICE_TYPE(device_type); + int module_id = p_device_context->p_device_info->module_id; + if (device_handles[xcoder_device_type][module_id] != NI_INVALID_DEVICE_HANDLE) + { + p_session_context->device_handle = + device_handles[xcoder_device_type][module_id]; + } else + { + p_session_context->device_handle = + ni_device_open(p_device_context->p_device_info->dev_name, + &p_session_context->max_nvme_io_size); + if (p_session_context->device_handle != NI_INVALID_DEVICE_HANDLE) + { + device_handles[xcoder_device_type][module_id] = + p_session_context->device_handle; + } + } + + if (p_session_context->device_handle == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, + "ERROR: ni_device_open() failed for %s: %s\n", + p_device_context->p_device_info->dev_name, + strerror(NI_ERRNO)); + ni_rsrc_free_device_context(p_device_context); + continue; + } + + if (ni_query_extra_info(p_session_context->device_handle, + &p_dev_extra_info, + p_device_context->p_device_info->fw_rev)) + { + p_dev_extra_info.composite_temp = 0; + } + + if (p_dev_extra_info.power_consumption + 1) + { + sprintf(power_consumption, "%umW", p_dev_extra_info.power_consumption); + } + strcat_dyn_buf(&output_buf, + "%-4s %-8s %-14s\n", "TEMP", "POWER", "DEVICE"); + strcat_dyn_buf(&output_buf, + "%-4d %-8s %-14s\n", + p_dev_extra_info.composite_temp + ABSOLUTE_TEMP_ZERO, + (p_dev_extra_info.power_consumption + 1) ? power_consumption : "N/A", + p_device_context->p_device_info->dev_name); + + ni_rsrc_free_device_context(p_device_context); + } + + if (output_buf.str_buf) + printf("%s", output_buf.str_buf); + clear_dyn_str_buf(&output_buf); + free(module_ids); } -/*!****************************************************************************** - * \brief - * - * \param - * - * \return - *******************************************************************************/ int main(int argc, char *argv[]) { - int k; + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); int checkInterval; + int skip_init_rsrc = 0; int should_match_rev = 1; + int detail = 0; + ni_instance_mgr_detail_status_v1_t detail_data_v1 = {0}; + ni_instance_mgr_detail_status_v1_t (*previous_detail_data)[NI_DEVICE_TYPE_XCODER_MAX] = NULL; ni_device_pool_t *p_device_pool = NULL; ni_device_queue_t *coders = NULL; - ni_device_context_t *p_device_context = NULL; - ni_session_context_t xCtxt = {0}; + ni_session_context_t *p_xCtxt = NULL; time_t startTime = {0}, now = {0}; int timeout_seconds = 0; struct tm *ltime = NULL; char buf[64] = {0}; - time_t hours, minutes, seconds; + long long time_diff_hours, time_diff_minutes, time_diff_seconds; int opt; ni_log_level_t log_level = NI_LOG_INFO; - + enum outFormat printFormat = FMT_TEXT; checkInterval = 0; + bool fw_log_dump = false; + int devid = -1; + int refresh_device_pool = 1; + bool is_first_query = true; #ifdef _WIN32 SetConsoleCtrlHandler(console_ctrl_handler, TRUE); @@ -319,14 +2312,58 @@ int main(int argc, char *argv[]) #endif // arg handling - while ((opt = getopt(argc, argv, "n:rt:l:hv")) != -1) + while ((opt = getopt(argc, argv, "n:o:D:k:R:rt:Sl:hvd")) != -1) { switch (opt) { + case 'o': + // Output print format + if (!strcmp(optarg, "json")) + { + printFormat = FMT_JSON; + } + else if (!strcmp(optarg, "simple")) + { + printFormat = FMT_SIMPLE_TEXT; + } + else if (!strcmp(optarg, "text")) + { + printFormat = FMT_TEXT; + } + else if (!strcmp(optarg, "full")) + { + printFormat = FMT_FULL_TEXT; + } + else if (!strcmp(optarg, "json1")) + { + printFormat = FMT_JSON1; + } + else if (!strcmp(optarg, "json2")) + { + printFormat = FMT_JSON2; + } + else if (!strcmp(optarg, "extra")) + { + printFormat = FMT_EXTRA; + } + else + { + fprintf(stderr, "Error: unknown selection for outputFormat: %s\n", optarg); + return 1; + } + break; case 'n': // Output interval checkInterval = atoi(optarg); break; + case 'D': + fw_log_dump = atoi(optarg); + break; + case 'k': + devid = atoi(optarg); + break; + case 'R': + refresh_device_pool = atoi(optarg); case 'r': should_match_rev = 0; break; @@ -334,6 +2371,9 @@ int main(int argc, char *argv[]) timeout_seconds = atoi(optarg); printf("Timeout will be set %d\n", timeout_seconds); break; + case 'S': + skip_init_rsrc = 1; + break; case 'l': log_level = arg_to_ni_log_level(optarg); if (log_level != NI_LOG_INVALID) @@ -345,46 +2385,65 @@ int main(int argc, char *argv[]) } break; case 'h': - // help message + // help message (limit to 80 characters wide) printf("-------- ni_rsrc_mon v%s --------\n" - "The ni_rsrc_mon program provides a real-time view of NETINT " - "QUADRA resources \n" + "The ni_rsrc_mon program provides a real-time view of NETINT Quadra resources\n" "running on the system.\n" "\n" "Usage: ni_rsrc_mon [OPTIONS]\n" - "-n Specify reporting interval in one second interval. If 0 or " - "no selection,\n" + "-n Specify reporting interval in one second interval. If 0 or no selection,\n" " report only once.\n" " Default: 0\n" - "-r Init transcoder card resource regardless firmware release " - "version to\n" + "-R Specify if refresh devices on host in each monitor interval.\n" + " If 0, only refresh devices at the start.\n" + " Default: 1\n" + "-o Output format. [text, simple, full, json, json1, json2, extra]\n" + " Default: text\n" + "-D Dump firmware logs to current directory. Default: 0(not dump fw log).\n" + "-k Specify to dump which card's firmware logs.\n" + " Default: -1(dump fw log of all cards).\n" + "-r Initialize Quadra device regardless firmware release version to\n" " libxcoder version compatibility.\n" - " Default: only init cards with compatible firmware version.\n" - "-t Set timeout time in seconds for device polling. Program will " - "exit with \n" - " failure if timeout is reached without finding at least one " - "device. If 0 or \n" - " no selection, poll indefinitely until a QUADRA device is " - "found.\n" + " Default: only initialize devices with compatible firmware version.\n" + "-t Set timeout time in seconds for device polling. Program will exit with\n" + " failure if timeout is reached without finding at least one device. If 0 or\n" + " no selection, poll indefinitely until a Quadra device is found.\n" " Default: 0\n" + "-S Skip init_rsrc.\n" + "-d Print detailed infomation for decoder/encoder in text and json formats.\n" "-l Set loglevel of libxcoder API.\n" " [none, fatal, error, info, debug, trace]\n" " Default: info\n" "-h Open this help message.\n" "-v Print version info.\n" "\n" - "Reporting columns\n" - "INDEX index number used by resource manager to identify " - "the resource\n" - "LOAD realtime load\n" + "Simple output shows the maximum firmware load amongst the subsystems on the\n" + "Quadra device.\n" + "\n" + "Reporting columns for text output format\n" + "INDEX index number used by resource manager to identify the resource\n" + "LOAD realtime load given in percentage. This value is max of VPU and FW load reported in full output format\n" "MODEL_LOAD estimated load based on framerate and resolution\n" "INST number of job instances\n" - "MEM usage of memory local to the card\n" - "SHARE_MEM usage of memory shared across cards on the same " - "device\n" + "MEM usage of memory by the subsystem\n" + "SHARE_MEM usage of memory shared across subsystems on the same device\n" "P2P_MEM usage of memory by P2P\n" "DEVICE path to NVMe device file handle\n" - "NAMESPACE path to NVMe namespace file handle\n", + "NAMESPACE path to NVMe namespace file handle\n" + "\n" + "Additional reporting columns for full output format\n" + "VPU same as LOAD in JSON outputs\n" + "FW system load\n" + "TOTAL same as MEM\n" + "CRITICAL usage of memory considered critical\n" + "L_FL2V last ran firmware loader 2 version\n" + "N_FL2V nor flash firmware loader 2 version\n" + "FR current firmware revision\n" + "N_FR nor flash firmware revision\n" + "\n" + "Additional reporting columns for full JSON formats\n" + "LOAD VPU load\n" + "FW_LOAD system load\n", NI_XCODER_REVISION); return 0; case 'v': @@ -404,6 +2463,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "FATAL: unknown option character '\\x%x'\n", opt); } return 1; + case 'd': + detail = 1; + break; case ':': fprintf(stderr, "FATAL: option '-%c' lacks arg\n", opt); return 1; @@ -413,6 +2475,12 @@ int main(int argc, char *argv[]) } } + if(checkInterval > 0 && printFormat == FMT_JSON) + { + fprintf(stderr, "EXIT: -o json cannot use with -n params\n"); + return 1; + } + if ((argc <= 2) && (optind == 1)) { for (; optind < argc; optind++) @@ -421,24 +2489,61 @@ int main(int argc, char *argv[]) } } - if (ni_rsrc_init(should_match_rev,timeout_seconds) != 0) +#ifdef _ANDROID + ni_log_set_log_tag(LOG_TAG); +#endif + + p_xCtxt = ni_device_session_context_alloc_init(); + if(!p_xCtxt) { - fprintf(stderr, "FATAL: cannot access NI resource\n"); + fprintf(stderr, "FATAL: cannot allocate momory for ni_session_context_t\n"); return 1; } + ni_log_set_level(NI_LOG_ERROR); // silence informational prints + if (!skip_init_rsrc && ni_rsrc_init(should_match_rev,timeout_seconds) != 0) + { + fprintf(stderr, "FATAL: cannot access NI resource\n"); + LRETURN; + } + ni_log_set_level(log_level); + p_device_pool = ni_rsrc_get_device_pool(); if (!p_device_pool) { fprintf(stderr, "FATAL: cannot get devices info\n"); - return 1; + LRETURN; + } + + if (log_level >= NI_LOG_INFO) + { + printf("**************************************************\n"); + } + + // initialise device handles + for (int i = 0; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + for (int j = 0; j < NI_MAX_DEVICE_CNT; j++) + { + device_handles[i][j] = NI_INVALID_DEVICE_HANDLE; + } } - printf("**************************************************\n"); startTime = time(NULL); #ifdef _ANDROID system("chown mediacodec:mediacodec /dev/shm_netint/*"); #endif + if(checkInterval) + { + int allocate_size = NI_MAX_DEVICE_CNT * NI_DEVICE_TYPE_XCODER_MAX * sizeof(ni_instance_mgr_detail_status_v1_t); + previous_detail_data = (ni_instance_mgr_detail_status_v1_t (*)[NI_DEVICE_TYPE_XCODER_MAX])malloc(allocate_size); + if(previous_detail_data == NULL) + { + fprintf(stderr, "FATAL: Allocate buffer fail\n"); + return 1; + } + memset((void *)previous_detail_data, 0, allocate_size); + } while (!g_xcoder_stop_process) { now = time(NULL); @@ -447,14 +2552,21 @@ int main(int argc, char *argv[]) { strftime(buf, sizeof(buf), "%c", ltime); } - seconds = now - startTime; - minutes = seconds / 60; - hours = minutes / 60; + time_diff_seconds = (long long)difftime(now, startTime); + time_diff_minutes = time_diff_seconds / 60; + time_diff_hours = time_diff_minutes / 60; - ni_rsrc_refresh(should_match_rev); - printf("%s up %02zu:%02zu:%02zu v%s\n", buf, hours, minutes % 60, seconds % 60, - NI_XCODER_REVISION); + if (is_first_query || refresh_device_pool) + { + ni_rsrc_refresh(should_match_rev); + } + + if (log_level >= NI_LOG_INFO) + { + printf("%s up %02lld" ":%02lld" ":%02lld" " v%s\n", buf, time_diff_hours, time_diff_minutes % 60, time_diff_seconds % 60, + NI_XCODER_REVISION); + } /*! print out coders in their current order */ @@ -462,7 +2574,7 @@ int main(int argc, char *argv[]) if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) { fprintf(stderr, "ERROR: Failed to obtain mutex: %p\n", p_device_pool->lock); - return 1; + LRETURN; } #elif __linux__ if ( lockf(p_device_pool->lock, F_LOCK, 0) ) @@ -482,12 +2594,38 @@ int main(int argc, char *argv[]) } #endif - for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) + switch (printFormat) { - print_perf(k, coders, &xCtxt); + case FMT_TEXT: + print_text(coders, p_xCtxt, detail, &detail_data_v1, previous_detail_data, checkInterval); + break; + case FMT_FULL_TEXT: + print_full_text(coders, p_xCtxt, 0, &detail_data_v1); + break; + case FMT_SIMPLE_TEXT: + print_simple_text(coders, p_xCtxt, 0, &detail_data_v1); + break; + case FMT_JSON: + print_json(coders, p_xCtxt, detail, &detail_data_v1); + break; + case FMT_JSON1: + print_json1(coders, p_xCtxt, 0, &detail_data_v1, 1); + break; + case FMT_JSON2: + print_json1(coders, p_xCtxt, 0, &detail_data_v1, 2); + break; + case FMT_EXTRA: + print_extra(coders, p_xCtxt); + break; } - printf("**************************************************\n"); + is_first_query = false; + + if (log_level >= NI_LOG_INFO) + { + printf("**************************************************\n"); + } + fflush(stdout); if (checkInterval == 0) @@ -497,11 +2635,61 @@ int main(int argc, char *argv[]) } ni_usleep(checkInterval * 1000 * 1000); } + + if (fw_log_dump) + { + // dump fw log +#ifdef _WIN32 + if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) + { + fprintf(stderr, "ERROR: Failed to obtain mutex: %p\n", p_device_pool->lock); + LRETURN; + } +#elif __linux__ + if ( lockf(p_device_pool->lock, F_LOCK, 0) ) + { + perror("ERROR: cannot lock p_device_pool"); + } +#endif + coders = p_device_pool->p_device_queue; +#ifdef _WIN32 + ReleaseMutex((HANDLE)p_device_pool->lock); +#elif __linux__ + if ( lockf(p_device_pool->lock, F_ULOCK, 0) ) + { + perror("ERROR: cannot unlock p_device_pool"); + } +#endif + dump_fw_log(coders, p_xCtxt, devid); + } + + // close all opened devices + for (int i = 0; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + for (int j = 0; j < NI_MAX_DEVICE_CNT; j++) + { + if (device_handles[i][j] != NI_INVALID_DEVICE_HANDLE) + { + ni_device_close(device_handles[i][j]); + } + } + } + ni_device_session_context_clear(p_xCtxt); ni_rsrc_free_device_pool(p_device_pool); #ifdef _ANDROID system("chown mediacodec:mediacodec /dev/shm_netint/*"); system("chmod 777 /dev/block/nvme*"); + system("chmod 777 /dev/nvme*"); #endif + if(checkInterval) + { + free(previous_detail_data); + } + free(p_xCtxt); return 0; + +END: + free(p_xCtxt); + return 1; } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_namespace.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_namespace.c new file mode 100644 index 00000000..ecf2fab4 --- /dev/null +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_namespace.c @@ -0,0 +1,307 @@ +/******************************************************************************* + * + * Copyright (C) 2022 NETINT Technologies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + ******************************************************************************/ + +/*!***************************************************************************** + * \file ni_rsrc_namespace.c + * + * \brief This utility aims to set the NVMe namespace number for a Quadra NVMe + * block device. It can operate on physical devices (PCIe physical + * function) or virtual devices (PCIe virtual function). Before setting + * namespace number, use SR-IOV to create the PCIe virtual function. + * Note that only block device name is accepted for this utility. + * + * To effect the name space change, reload the NVMe driver: + * sudo modprobe -r nvme + * sudo modprobe nvme + * sudo nvme list #check the result with nvme list + ******************************************************************************/ + +#include "ni_device_api.h" +#include "ni_nvme.h" +#ifdef _WIN32 +#include "ni_getopt.h" +#else +#include +#include +#endif + +#define NI_NAMESPACE_SZ 32 + +static void usage(void) +{ + printf("usage: ni_rsrc_namespace [OPTION]\n" + "Provides NETINT QUADRA NVMe block device namespace IO operations.\n" + " -v show version.\n" + " -d the nvme block namespace. Only PF with nsid 1 allowed\n" + " -D the nvme block namespace for target over provision setting\n" + " -n the nvme block namespace count.\n" + " Default: 0\n" + " -p overprovision percent. Use exclusive of -n and -s and -q\n" + " -q namespace QoS setting. Use exclusive of -n and -s and -p\n" + " Default: 0 disabled.\n" + " 1 enable qos\n" + " 2 enable qos with overprovision\n" + " -s index of virtual PCIe functions in SR-IOV tied to the \n" + " physical PCIe function. '0' to select physical PCIe \n" + " function.\n" + " Eg. '1' to select the first virtual SR-IOV device tied \n" + " to the physical block device defined by '-d' option.\n" + " Default: 0\n" + " -h help info.\n"); +} + +int send_config_ns_command(char* dev, int ns, int sr) +{ + ni_device_handle_t handle = ni_device_open(dev, NULL); + ni_retcode_t retval; + if (handle == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, "ERROR: open %s failure for %s\n", dev, + strerror(NI_ERRNO)); + exit(-1); + } else + { + printf("Succeed to open block namespace %s\n", dev); + } + + retval = ni_device_config_namespace_num(handle, ns, sr); + if (retval != NI_RETCODE_SUCCESS) + { + fprintf(stderr, "ERROR: Config setting failure for %s\n", + strerror(NI_ERRNO)); + } + ni_device_close(handle); + return retval; +} + +int send_config_qos_mode(char *dev, int value) +{ + ni_device_handle_t handle = ni_device_open(dev, NULL); + ni_retcode_t retval; + if (handle == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, "ERROR: open %s failure for %s\n", dev, + strerror(NI_ERRNO)); + exit(-1); + } else + { + printf("Succeed to open block namespace %s\n", dev); + } + + retval = ni_device_config_qos(handle, value); + if (retval != NI_RETCODE_SUCCESS) + { + fprintf(stderr, "ERROR: Config setting failure for %s\n", + strerror(NI_ERRNO)); + } + ni_device_close(handle); + return retval; +} + +int send_config_qos_op(char *dev, char *devt, int op) +{ + ni_retcode_t retval; + ni_device_handle_t handle = ni_device_open(dev, NULL); + if (handle == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, "ERROR: open %s failure for %s\n", dev, + strerror(NI_ERRNO)); + exit(-1); + } else + { + printf("Succeed to open block namespace %s\n", dev); + } + ni_device_handle_t handle_t = ni_device_open(devt, NULL); + if (handle_t == NI_INVALID_DEVICE_HANDLE) + { + fprintf(stderr, "ERROR: open %s failure for %s\n", devt, + strerror(NI_ERRNO)); + ni_device_close(handle); + exit(-1); + } else + { + printf("Succeed to open block namespace %s\n", dev); + } + + retval = ni_device_config_qos_op(handle, handle_t, op); + if (retval != NI_RETCODE_SUCCESS) + { + fprintf(stderr, "ERROR: Config setting failure for %s\n", + strerror(NI_ERRNO)); + } + ni_device_close(handle); + ni_device_close(handle_t); + return retval; +} + +int main(int argc, char *argv[]) +{ + ni_retcode_t retval; + int opt; + char device_namespace[NI_NAMESPACE_SZ] = {'\0'}; + char device_namespace_OP[NI_NAMESPACE_SZ] = {'\0'}; + int namespace_num = 1; + int over_provision_percent = -1; + int sriov_index = 0; + int qos_mode = -1; +#ifdef __linux__ + struct stat sb; +#endif + + while ((opt = getopt(argc, argv, "d:D:n:p:q:s:hv")) != EOF) + { + switch (opt) + { + case 'h': + usage(); + exit(0); + case 'v': + printf("Release ver: %s\n" + "API ver: %s\n" + "Date: %s\n" + "ID: %s\n", + NI_XCODER_REVISION, LIBXCODER_API_VERSION, + NI_SW_RELEASE_TIME, NI_SW_RELEASE_ID); + exit(0); + case 'd': + strcpy(device_namespace, optarg); +#ifdef __linux__ + if (lstat(device_namespace, &sb) != 0 || + (sb.st_mode & S_IFMT) != S_IFBLK) + { + fprintf(stderr, "ERROR: Only block device is supported! " + "%s is not block device!\n", device_namespace); + exit(-1); + } +#endif + break; + case 'D': + strcpy(device_namespace_OP, optarg); + break; + case 'n': + // A maximum of 64 namespaces are supported for firmware + namespace_num = atoi(optarg); + if (namespace_num < 0 || namespace_num > NI_NAMESPACE_MAX_NUM) + { + fprintf(stderr, "ERROR: The number of namespace cannot " + "exceed %d\n", NI_NAMESPACE_MAX_NUM); + exit(-1); + } + break; + case 'p': + // set overprovision % + over_provision_percent = atoi(optarg); + if (over_provision_percent > 100 || over_provision_percent < 0) + { + fprintf(stderr, "ERROR: Overprovision percent cannot " + "exceed 100%% or become negative\n"); + exit(-1); + } + break; + case 'q': + // 0 disabled, 1 enabled - no idle sharing + qos_mode = atoi(optarg); + if (qos_mode < QOS_MODE_DISABLED || + qos_mode > QOS_MODE_ENABLED_SHARE) + { + fprintf(stderr, + "ERROR: QoS mode %d not supported\n", + qos_mode); + exit(-1); + } + break; + case 's': + sriov_index = atoi(optarg); + if (sriov_index < 0) + { + fprintf(stderr, "ERROR: Invalid SR-IOV device index: %d\n", + sriov_index); + exit(-1); + } + break; + default: + fprintf(stderr, "ERROR: Invalid option: %c\n", opt); + exit(-1); + } + } + + if (device_namespace[0] == '\0') + { + fprintf(stderr, "ERROR: missing argument for -d\n"); + exit(-1); + } + if (strlen(device_namespace) < 3 || + strcmp(device_namespace + strlen(device_namespace) - 2, "n1") != 0) + { + fprintf(stderr, "ERROR: Invalid device name %s, need n1, no vf\n", device_namespace); + exit(-1); + } + + if (qos_mode != -1) + { + if (namespace_num != 1 || sriov_index || over_provision_percent != -1) + { + fprintf(stderr, + "ERROR: QoS mode -q mutually exclusive of namespace and " + "SR-IOV\n"); + exit(-1); + } + retval = send_config_qos_mode(device_namespace, qos_mode); + if (retval == NI_RETCODE_SUCCESS) + { + printf("QoS mode setting succeed with number of %d\n", qos_mode); + } + return retval; + } + + if (over_provision_percent != -1) + { + if (device_namespace_OP[0] == '\0') + { + fprintf(stderr, "ERROR: missing argument for -D\n"); + exit(-1); + } + if (namespace_num != 1 || sriov_index || qos_mode != -1) + { + fprintf(stderr, + "ERROR: Overprovision percent -p mutually exclusive of " + "namespace and SR-IOV and QOS mode\n"); + exit(-1); + } + retval = send_config_qos_op(device_namespace, device_namespace_OP, + over_provision_percent); + if (retval == NI_RETCODE_SUCCESS) + { + printf("Overprovision percent setting succeed with number of %d\n", + over_provision_percent); + } + return retval; + } + + retval = send_config_ns_command(device_namespace, namespace_num, sriov_index); + if (retval == NI_RETCODE_SUCCESS) + { + printf("Namespace setting succeed with number of %d and SR-IOV " + "index %d\n", + namespace_num, sriov_index); + } + return retval; +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.cpp b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.cpp index 76acd347..aa724d0a 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.cpp +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.cpp @@ -20,26 +20,33 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_rsrc_priv.c -* -* \brief Private routines related to resource management of NI Quadra devices -* -*******************************************************************************/ + * \file ni_rsrc_priv.cpp + * + * \brief Private definitions used by ni_rsrc_api.cpp for management of + * NETINT video processing devices + ******************************************************************************/ +#include #include #include #include #include #include #include +#include #if __linux__ || __APPLE__ #include +#include #include #include #include #endif +#if __APPLE__ +#include +#endif + #ifdef _ANDROID #include "ni_rsrc_api_android.h" #endif @@ -51,6 +58,12 @@ #include "ni_log.h" #include "ni_util.h" +#if __linux__ || __APPLE__ +#ifndef _ANDROID +jmp_buf env; +#endif +#endif + uint32_t g_xcoder_stop_process = 0; /*!****************************************************************************** @@ -147,8 +160,8 @@ ni_retcode_t ni_rsrc_fill_device_info(ni_device_info_t* p_device_info, ni_codec_ p_device_info->dev_cap[2].supports_codec = EN_JPEG; p_device_info->dev_cap[2].max_res_width = p_hw_cap->max_video_width; p_device_info->dev_cap[2].max_res_height = p_hw_cap->max_video_height; - p_device_info->dev_cap[2].min_res_width = p_hw_cap->min_video_width; - p_device_info->dev_cap[2].min_res_height = p_hw_cap->min_video_height; + p_device_info->dev_cap[2].min_res_width = NI_PARAM_MIN_WIDTH; + p_device_info->dev_cap[2].min_res_height = NI_PARAM_MIN_HEIGHT; strncpy(p_device_info->dev_cap[2].profiles_supported, "Main", NI_PROFILES_SUPP_STR_LEN); @@ -221,10 +234,17 @@ int ni_rsrc_strcmp(const void * p_str, const void* p_str1) *******************************************************************************/ void ni_rsrc_get_lock_name(ni_device_type_t device_type, int32_t guid, char* p_name, size_t max_name_len) { - char type = device_type_chr[GET_XCODER_DEVICE_TYPE(device_type)]; + char type = g_device_type_chr[GET_XCODER_DEVICE_TYPE(device_type)]; if (NULL != p_name) { - snprintf(p_name, max_name_len, "%s/NI_lck_%c%d", LOCK_DIR, type, guid); + if (strcmp(CODERS_SHM_NAME, "NI_QUADRA_SHM_CODERS") == 0) + { + snprintf(p_name, max_name_len, "%s/NI_QUADRA_lck_%c%d", LOCK_DIR, type, guid); + } + else + { + snprintf(p_name, max_name_len, "%s/NI_lck_%c%d", LOCK_DIR, type, guid); + } } } @@ -237,11 +257,18 @@ void ni_rsrc_get_lock_name(ni_device_type_t device_type, int32_t guid, char* p_n *******************************************************************************/ void ni_rsrc_get_shm_name(ni_device_type_t device_type, int32_t guid, char* p_name, size_t max_name_len) { - char type = device_type_chr[GET_XCODER_DEVICE_TYPE(device_type)]; + char type = g_device_type_chr[GET_XCODER_DEVICE_TYPE(device_type)]; /*! assume there is enough space allocated in name */ if (NULL != p_name) { - snprintf(p_name, max_name_len, "NI_shm_%c%d", type, guid); + if (strcmp(CODERS_SHM_NAME, "NI_QUADRA_SHM_CODERS") == 0) + { + snprintf(p_name, max_name_len, "NI_QUADRA_shm_%c%d", type, guid); + } + else + { + snprintf(p_name, max_name_len, "NI_shm_%c%d", type, guid); + } } } @@ -260,19 +287,372 @@ int ni_is_fw_compatible(uint8_t fw_rev[8]) if ((uint8_t)fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX] == (uint8_t)NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX]) { - if ((uint8_t)fw_rev[NI_XCODER_REVISION_API_MINOR_VER_IDX] == - (uint8_t)NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX]) + if (ni_cmp_fw_api_ver((char*) &fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX], + &NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX])) { - return 1; + return 2; } else { - return 2; + return 1; } } else - { - return 0; - } + { + return 0; + } +} + +static bool check_device_capability(const ni_device_handle_t device_handle, + ni_device_capability_t *device_capability, + const char *device_name, + const int should_match_rev, + int *compatibility) +{ + ni_retcode_t retcode; + + memset(device_capability, 0, sizeof(ni_device_capability_t)); + retcode = ni_device_capability_query(device_handle, device_capability); + if (retcode != NI_RETCODE_SUCCESS) + { + ni_log(NI_LOG_ERROR, + "Capability query failed for %s! Skipping...\n", + device_name); + return false; + } + if (!is_supported_xcoder(device_capability->device_is_xcoder)) + { + ni_log(NI_LOG_INFO, + "%s not supported! Skipping...\n", + device_name); + return false; + } + *compatibility = ni_is_fw_compatible(device_capability->fw_rev); + if (should_match_rev && !(*compatibility)) + { + ni_log(NI_LOG_INFO, + "%s with FW revision %.*s not compatible! Skipping...\n", + device_name, + (int)sizeof(device_capability->fw_rev), + device_capability->fw_rev); + return false; + } + + return true; +} + +static void fill_device_info(ni_device_info_t *device_info, + const int module_id, + const ni_device_handle_t device_handle, + const char device_name[NI_MAX_DEVICE_NAME_LEN], + const int compatibility, + ni_device_capability_t *device_capability, + const ni_device_type_t device_type) +{ + ni_hw_capability_t *hw_capability; + + hw_capability = &device_capability->xcoder_devices[device_type]; + + strncpy(device_info->dev_name, device_name, (MAX_CHAR_IN_DEVICE_NAME-1)); + strncpy(device_info->blk_name, device_name, (MAX_CHAR_IN_DEVICE_NAME-1)); + device_info->hw_id = hw_capability->hw_id; + device_info->module_id = module_id; + device_info->fw_ver_compat_warning = (compatibility == 2); + + memcpy(device_info->fw_rev, + device_capability->fw_rev, + sizeof(device_info->fw_rev)); + memcpy(device_info->fw_branch_name, + device_capability->fw_branch_name, + sizeof(device_info->fw_branch_name) - 1); + memcpy(device_info->fw_commit_time, + device_capability->fw_commit_time, + sizeof(device_info->fw_commit_time) - 1); + memcpy(device_info->fw_commit_hash, + device_capability->fw_commit_hash, + sizeof(device_info->fw_commit_hash) - 1); + memcpy(device_info->fw_build_time, + device_capability->fw_build_time, + sizeof(device_info->fw_build_time) - 1); + memcpy(device_info->fw_build_id, + device_capability->fw_build_id, + sizeof(device_info->fw_build_id) - 1); + memcpy(device_info->serial_number, + device_capability->serial_number, + sizeof(device_info->serial_number)); + memcpy(device_info->model_number, + device_capability->model_number, + sizeof(device_info->model_number)); + + ni_query_fl_fw_versions(device_handle, device_info); + + device_info->max_fps_4k = hw_capability->max_4k_fps; + device_info->max_instance_cnt = hw_capability->max_number_of_contexts; + device_info->device_type = device_type; + + ni_rsrc_fill_device_info(device_info, + (ni_codec_t)hw_capability->codec_format, + device_type, + hw_capability); +} + +static void fill_shared_memory(ni_device_queue_t *device_queue, + const int should_match_rev, + const int existing_number_of_devices, + const char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]) +{ + int i, j, compatible_device_counter; + + memset(device_queue->xcoder_cnt, 0, sizeof(device_queue->xcoder_cnt)); + for (i = NI_DEVICE_TYPE_DECODER; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + for (j = 0; j < NI_MAX_DEVICE_CNT; j++) + { + device_queue->xcoders[i][j] = -1; + } + } + + compatible_device_counter = 0; + for (i = 0; i < existing_number_of_devices; i++) + { + if (!add_to_shared_memory(device_names[i], + false, + should_match_rev, + device_queue)) + { + continue; + } + compatible_device_counter++; + if (compatible_device_counter >= NI_MAX_DEVICE_CNT) + { + ni_log(NI_LOG_INFO, + "Maximum number of supported and compatible devices " + "reached. Ignoring other supported and compatible " + "devices.\n"); + break; + } + } +} + +bool find_available_guid(ni_device_queue_t *device_queue, int device_type, int *guidn) +{ + /* + Create a mask of all 128 guids, mark used by 1 and unused by 0. + */ + int32_t temp_guid; + int32_t i, j; + uint32_t guid_mask[4] = {0}; + + for (i = 0; i < NI_MAX_DEVICE_CNT; i++) + { + temp_guid = device_queue->xcoders[device_type][i]; + if (temp_guid >= 0 && temp_guid < NI_MAX_DEVICE_CNT) + { + guid_mask[temp_guid / 32] |= (1u << ((uint32_t)temp_guid % 32)); + } + } + //from the masks find the first available guidn + for (i = 0; i < 4; i++) + { + for (j = 0; j < 32; j++) + { + if ((guid_mask[i] & (1u << j)) == 0) + { + *guidn = (i * 32) + j; + return true; + } + } + } + + return false; +} + +bool add_to_shared_memory(const char device_name[NI_MAX_DEVICE_NAME_LEN], + const bool device_open_should_succeed, + const int should_match_rev, + ni_device_queue_t *device_queue) +{ + int compatibility; + int32_t guid; + int i, j; + uint32_t max_io_size; + + ni_device_capability_t device_capability; + ni_device_handle_t device_handle; + ni_device_info_t device_info; + bool success = true; + + max_io_size = NI_INVALID_IO_SIZE; + device_handle = ni_device_open(device_name, &max_io_size); + if (device_handle == NI_INVALID_DEVICE_HANDLE) + { + if (device_open_should_succeed) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Failed to add %s\n: Failed ni_device_open()\n", + __FUNCTION__, + device_name); + return false; + } + return true; + } + + if (!check_device_capability(device_handle, + &device_capability, + device_name, + should_match_rev, + &compatibility)) + { + LRETURN; + } + + if (compatibility == 2) + { + ni_log(NI_LOG_INFO, + "WARNING: %s with FW revision %.*s is below the minimum " + "supported version of this SW revision. Some features " + "may be missing!\n", + device_name, + (int)sizeof(device_capability.fw_rev), + device_capability.fw_rev); + } + + + for (i = NI_DEVICE_TYPE_DECODER; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + if (!device_capability.xcoder_cnt[i]) + { + ni_log(NI_LOG_DEBUG, + "%s %s disabled...\n", + device_name, + GET_XCODER_DEVICE_TYPE_STR(i)); + continue; + } + + j = device_queue->xcoder_cnt[i]; + guid = j ? device_queue->xcoders[i][j-1] + 1 : 0; + if (guid >= NI_MAX_DEVICE_CNT && !find_available_guid(device_queue, i, &guid)) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Failed to add %s: too many devices\n", + __FUNCTION__, + device_name); + success = false; + LRETURN; + } + device_queue->xcoders[i][j] = guid; + device_queue->xcoder_cnt[i]++; + + fill_device_info(&device_info, + guid, + device_handle, + device_name, + compatibility, + &device_capability, + (ni_device_type_t)i); + + ni_rsrc_get_one_device_info(&device_info); + } + +END: + ni_device_close(device_handle); + + return success; +} + +#ifdef _ANDROID +/*!***************************************************************************** + * \brief Open file and create file descriptor for mmap in android + * + * \param[out] fd file descriptor + * + * \param[in] path file path + * + * \param[in] flag only O_CREAT and O_EXCL now, other flags will be ignored + * + * \param[in] size set the size of file (do not use ftruncate after the file descriptor is created in android) + * + * \return If flag is O_CREAT|O_EXCL and file already exist return -17 + * If get one descriptor return 0 + * If can not get one file descriptor return -1 + ******************************************************************************/ +static int android_open_shm_file(int &fd, const char *path, int flag, size_t size) +{ + int ret = ni_rsrc_android_init(); + if (service == NULL) + { + ni_log(NI_LOG_ERROR, "ni_rsrc_get_device_pool Error service ..\n"); + return -1; + } + + string param(path); + + Return retvalue = + service->GetAppFlag(param, [&](int32_t ret, const hidl_handle &handle) { + ni_log(NI_LOG_INFO, "GetAppFlag: ret %d\n", ret); + if (ret > 0) + { + fd = dup(handle->data[0]); + ni_log(NI_LOG_INFO, "vendor:GetAppFlag fd:%d\n", fd); + } else + { + ni_log(NI_LOG_ERROR, "Error %d: get fd ..\n", NI_ERRNO); + fd = -1; + + } + }); + + if (!retvalue.isOk()) + { + ni_log(NI_LOG_ERROR, "service->GetAppFlag ret failed ..\n"); + fd = -1; + return -1; + } + + if(fd != -1) + { + if(flag & O_CREAT && flag & O_EXCL) + { + //when O_CREAT|O_EXCL and fd already exist, shm_open() will set errno = 17 and return -1 + //fd = -1;//do not set fd to -1 as shm_open(),return the existing fd and set the return value to -17 + return -17; + } + else + { + return 0; + } + } + else if(flag & O_CREAT) + { + int shm_fd = ashmem_create_region(path, size); + if(shm_fd >= 0) + { + native_handle_t *handle = native_handle_create(1, 0); + handle->data[0] = shm_fd; + hidl_handle this_hidl_handle; + this_hidl_handle.setTo(handle, true); + service->SetAppFlag(param, this_hidl_handle); + fd = dup(handle->data[0]); + if(fd == -1) + { + ni_log(NI_LOG_ERROR, "shm_fd %d was created but dup failed. errno:%s\n", handle->data[0], strerror(errno)); + return -1; + } + } + else + { + ni_log(NI_LOG_ERROR, "Could not create shm fd\n"); + fd = -1; + return -1; + } + } + else + { + ni_log(NI_LOG_ERROR, "%s does not exist and O_CREAT was not set", path); + fd = -1; + return -1; + } + return 0; } +#endif #ifdef _WIN32 @@ -420,8 +800,582 @@ void ni_rsrc_update_record(ni_device_context_t* p_device_context, ni_session_con p_session_context->load_query.context_status[i].fps; } } + +/*!****************************************************************************** + * \brief Initialize and create all resources required to work with NETINT NVMe + * transcoder devices. This is a high level API function which is used + * mostly with user application like FFMpeg that relies on those resources. + * In case of custom application integration, revised functionality might + * be necessary utilizing corresponding API functions. + * + * \param[in] should_match_rev 0: transcoder firmware revision matching the + * library's version is NOT required for placing + * the transcoder into resource pool; 1: otherwise + * timeout_seconds 0: No timeout amount, loop until init success + * or fail; else: timeout will fail init once reached + * + * \return + * NI_RETCODE_SUCCESS on success + * NI_RETCODE_FAILURE on failure + * + *******************************************************************************/ +int ni_rsrc_init_priv(const int should_match_rev, + const int existing_number_of_devices, + const char existing_device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]) +{ + DWORD rc = 0; + HANDLE lock = NULL; + HANDLE map_file_handle = NULL; + ni_device_queue_t* p_device_queue = NULL; + map_file_handle = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + sizeof(ni_device_queue_t),// maximum object size (low-order DWORD) + CODERS_SHM_NAME // name of mapping object + ); + + if (NULL == map_file_handle) + { + rc = NI_ERRNO; + ni_log(NI_LOG_ERROR, "ERROR: CreateFileMapping returned: %d\n", rc); + return NI_RETCODE_FAILURE; + } + else + { + rc = NI_ERRNO; + if(ERROR_ALREADY_EXISTS == rc) + { + ni_log(NI_LOG_INFO, "NETINT resources have been initialized already, exiting ..\n"); + CloseHandle(map_file_handle); + return NI_RETCODE_SUCCESS; + } + else + { + ni_log(NI_LOG_INFO, "NETINT resources not initialized, starting initialization ..\n"); + } + } + + p_device_queue = (ni_device_queue_t*)MapViewOfFile( + map_file_handle, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(ni_device_queue_t) + ); + + if (NULL == p_device_queue) + { + ni_log(NI_LOG_ERROR, "Could not map view of file, p_last error (%d).\n", + NI_ERRNO); + CloseHandle(map_file_handle); + return NI_RETCODE_FAILURE; + } + + lock = CreateMutex(NULL, FALSE, CODERS_LCK_NAME); + if (NULL == lock) + { + ni_log(NI_LOG_ERROR, "Init CreateMutex %s failed: %d\n", CODERS_LCK_NAME, + NI_ERRNO); + UnmapViewOfFile(p_device_queue); + CloseHandle(map_file_handle); + return NI_RETCODE_FAILURE; + } + + if (WAIT_ABANDONED == WaitForSingleObject(lock, INFINITE)) + { + ni_log(NI_LOG_ERROR, "ERROR %d: failed to obtain mutex: %p\n", + NI_ERRNO, lock); + ReleaseMutex(lock); + UnmapViewOfFile(p_device_queue); + CloseHandle(map_file_handle); + return NI_RETCODE_FAILURE; + } + + fill_shared_memory(p_device_queue, + should_match_rev, + existing_number_of_devices, + existing_device_names); + + UnmapViewOfFile(p_device_queue); + ReleaseMutex(lock); + return NI_RETCODE_SUCCESS; +} + #elif __linux__ || __APPLE__ +static ni_retcode_t create_or_read_shm(int &shm_fd, + int *oflag, + const mode_t mode) +{ + *oflag = O_CREAT | O_EXCL | O_RDWR; +#ifdef _ANDROID + int android_open_shm_file_ret = android_open_shm_file(shm_fd, CODERS_SHM_NAME, *oflag, sizeof(ni_device_queue_t)); + if(android_open_shm_file_ret == -17)/* EEXIST */ + { + *oflag = O_RDWR; + ni_log(NI_LOG_INFO, "%s exists\n", CODERS_SHM_NAME); + } + else if(android_open_shm_file_ret == -1) + { + ni_log(NI_LOG_ERROR, "failed to open file: %s\n", CODERS_SHM_NAME); + return NI_RETCODE_FAILURE; + } +#else + shm_fd = shm_open(CODERS_SHM_NAME, *oflag, mode); + while (shm_fd == -1) + { + if (NI_ERRNO == 17 /* EEXIST */) + { + ni_log(NI_LOG_INFO, "%s exists\n", CODERS_SHM_NAME); + *oflag = O_RDWR; + shm_fd = shm_open(CODERS_SHM_NAME, *oflag, mode); + } + else + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): shm_open failed for %s: %s\n", + __func__, + CODERS_SHM_NAME, + strerror(NI_ERRNO)); + return NI_RETCODE_FAILURE; + } + } +#endif + + if (*oflag == O_RDWR) + { + ni_log(NI_LOG_INFO, "checking correctness of %s\n", CODERS_SHM_NAME); + } + +#ifndef _ANDROID + else + { + if (ftruncate(shm_fd, sizeof(ni_device_queue_t)) == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): ftruncate for %s: %s\n", + __func__, + CODERS_SHM_NAME, + strerror(NI_ERRNO)); + shm_unlink(CODERS_SHM_NAME); + return NI_RETCODE_FAILURE; + } + ni_log(NI_LOG_INFO, "%s created\n", CODERS_SHM_NAME); + } +#endif + + return NI_RETCODE_SUCCESS; +} + +static ni_retcode_t get_lock(int *lck_fd, const mode_t mode) +{ + int lockf_obtained, flags, xcoder_lck_fd; + unsigned int i; + + flags = O_RDWR|O_CREAT|O_CLOEXEC; + +#ifdef _ANDROID + if (0 != access(LOCK_DIR, 0)) + { + if (0 != mkdir(LOCK_DIR, 777)) + { + ni_log(NI_LOG_ERROR, "ERROR: Could not create the %s directory", + LOCK_DIR); + return NI_RETCODE_FAILURE; + } + } +#endif + + *lck_fd = open(CODERS_LCK_NAME, flags, mode); + if (*lck_fd == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): open failed for %s: %s\n", + __func__, + CODERS_LCK_NAME, + strerror(NI_ERRNO)); + return NI_RETCODE_FAILURE; + } + + lockf_obtained = 0; + for (i = 0; i < 5 && !lockf_obtained; i++) + { + if (!lockf(*lck_fd, F_TLOCK, 0)) + { + lockf_obtained = 1; + } + else + { + ni_usleep(1000000); /* 1 second */ + } + } + + if (!lockf_obtained) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): lock failed for %s: %s\n", + __func__, + CODERS_LCK_NAME, + strerror(NI_ERRNO)); + return NI_RETCODE_FAILURE; + } + + for (i = NI_DEVICE_TYPE_DECODER; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + xcoder_lck_fd = open(XCODERS_RETRY_LCK_NAME[i], flags, mode); + if (xcoder_lck_fd == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): open failed for %s: %s\n", + __func__, + XCODERS_RETRY_LCK_NAME[i], + strerror(NI_ERRNO)); + return NI_RETCODE_FAILURE; + } + } + + return NI_RETCODE_SUCCESS; +} + +/** + * @brief This function is used to check if the existing device queue matches the expectation. +*/ +static bool check_correctness_count(const ni_device_queue_t *existing_device_queue, + const int should_match_rev, + const int existing_number_of_devices, + const char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]) +{ + int compatibility; + uint32_t max_io_size; + int i, j, k; + + ni_device_capability_t device_capability; + ni_device_handle_t device_handle; + ni_device_queue_t device_queue; + + memset(device_queue.xcoder_cnt, 0, sizeof(device_queue.xcoder_cnt)); + + max_io_size = NI_INVALID_IO_SIZE; + for (i = 0; i < existing_number_of_devices; i++) + { + device_handle = ni_device_open(device_names[i], &max_io_size); + if (device_handle == NI_INVALID_DEVICE_HANDLE) + { + continue; + } + + if (!check_device_capability(device_handle, + &device_capability, + device_names[i], + should_match_rev, + &compatibility)) + { + goto NEXT; + } + + for (j = NI_DEVICE_TYPE_DECODER; j < NI_DEVICE_TYPE_XCODER_MAX; j++) + { + //Don't count if not in queue. + if (existing_device_queue->xcoders[j][i] == -1 && device_capability.xcoder_cnt[j] != 0) + { + //If not in queue then it shouldn't be in any device module. + for (k = NI_DEVICE_TYPE_DECODER; k < NI_DEVICE_TYPE_XCODER_MAX; k++) + { + if (existing_device_queue->xcoders[k][i] != -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Discovered device %s is not in queue for module %s but is in %s\n", + __func__, + device_names[i], + GET_XCODER_DEVICE_TYPE_STR(j), GET_XCODER_DEVICE_TYPE_STR(k)); + ni_device_close(device_handle); + return false; + } + } + continue; + } + device_queue.xcoder_cnt[j] += device_capability.xcoder_cnt[j]; + } +NEXT: + ni_device_close(device_handle); + } + + for (i = NI_DEVICE_TYPE_DECODER; i < NI_DEVICE_TYPE_XCODER_MAX; i++) + { + if (device_queue.xcoder_cnt[i] == existing_device_queue->xcoder_cnt[i]) + { + continue; + } + ni_log(NI_LOG_ERROR, + "WARNING: %s(): Discovered blocks %u != Existing blocks %u\n", + __func__, + device_queue.xcoder_cnt[i], + existing_device_queue->xcoder_cnt[i]); + return false; + } + + return true; +} + +static bool check_device_queue(const ni_device_queue_t *existing_device_queue, + const int existing_number_of_devices, + const char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]) +{ + int32_t module_id; + int i, j; + + ni_device_context_t *device_context; + + for (i = 0; i < existing_number_of_devices; i++) + { + for (j = NI_DEVICE_TYPE_DECODER; j < NI_DEVICE_TYPE_XCODER_MAX; j++) + { + module_id = existing_device_queue->xcoders[j][i]; + if (module_id == -1) + { + break; + } + device_context = ni_rsrc_get_device_context((ni_device_type_t)j, + module_id); + if (!device_context) + { + ni_log(NI_LOG_ERROR, + "WARNING: %s(): Missing device context for %s %s\n", + __func__, + device_names[i], + GET_XCODER_DEVICE_TYPE_STR(j)); + return false; + } + ni_rsrc_free_device_context(device_context); + } + } + + return true; +} + +#ifndef _ANDROID +static void sigbus_handler(int signal) +{ + siglongjmp(env, 1); +} + +static void setup_signal_handler(struct sigaction *p, const int signum) +{ + struct sigaction c; + + memset(&c, 0, sizeof(struct sigaction)); + if (sigemptyset(&c.sa_mask) == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Could not initialize signal set: %d\n", + __func__, + NI_ERRNO); + exit(EXIT_FAILURE); + } + c.sa_handler = sigbus_handler; + + if (sigaction(signum, NULL, p) == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Could not save previous signal handler: %d\n", + __func__, + NI_ERRNO); + exit(EXIT_FAILURE); + } + + if (sigaction(signum, &c, NULL) == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Could not register signal handler: %d\n", + __func__, + NI_ERRNO); + exit(EXIT_FAILURE); + } +} +#endif + +static bool check_correctness(const ni_device_queue_t *existing_device_queue, + const int should_match_rev, + const int existing_number_of_devices, + const char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]) +{ + bool result = false; +#ifndef _ANDROID + const int signum = SIGBUS; + struct sigaction p; + + setup_signal_handler(&p, signum); + + if (sigsetjmp(env, 1)) + { + LRETURN; + } +#endif + + if (!check_correctness_count(existing_device_queue, + should_match_rev, + existing_number_of_devices, + device_names)) + { + LRETURN; + } + + if (!check_device_queue(existing_device_queue, + existing_number_of_devices, + device_names)) + { + LRETURN; + } + + result = true; + ni_log(NI_LOG_INFO, "%s ok\n", CODERS_SHM_NAME); + +end: +#ifndef _ANDROID + if (sigaction(signum, &p, NULL) == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): Could not restore previous signal handler: %d\n", + __func__, + NI_ERRNO); + exit(EXIT_FAILURE); + } +#endif + return result; +} + +static void delete_shm(void) +{ +#ifdef _ANDROID + /*! return if init has already been done */ + int ret = ni_rsrc_android_init(); + if (service == NULL) + { + ni_log(NI_LOG_ERROR, "ni_rsrc_get_device_pool Error service ..\n"); + return; + } + + Return retvalue = service->RemoveAllAppFlags(); + + if (!retvalue.isOk()) + { + ni_log(NI_LOG_ERROR, "service->RemoveAllAppFlags ret failed ..\n"); + return; + } +#else + DIR *dir; + struct dirent *dirent; + char path_to_remove[PATH_MAX]; + + ni_log(NI_LOG_ERROR, "Deleting shared memory files in %s\n", LOCK_DIR); + + dir = opendir(LOCK_DIR); + if (!dir) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): opendir failed for %s: %s\n", + __func__, + LOCK_DIR, + strerror(NI_ERRNO)); + return; + } + + while ((dirent = readdir(dir)) != NULL) + { + if (strncmp(dirent->d_name, "NI_", 3) != 0) + { + continue; + } + snprintf(path_to_remove, PATH_MAX, "%s/%s", LOCK_DIR, dirent->d_name); + remove(path_to_remove); + } + + if (closedir(dir) == -1) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): closedir failed for %s: %s\n", + __func__, + LOCK_DIR, + strerror(NI_ERRNO)); + return; + } +#endif + ni_log(NI_LOG_INFO, "Deleted shared memory files in %s\n", LOCK_DIR); +} + +int ni_rsrc_init_priv(const int should_match_rev, + const int existing_number_of_devices, + const char existing_device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]) +{ + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + + int return_value = 0; + int lck_fd = -1; + int shm_fd = -1; + int shm_flag; + + ni_device_queue_t *p_device_queue; + + if ((create_or_read_shm(shm_fd, &shm_flag, mode) != NI_RETCODE_SUCCESS) || + (get_lock(&lck_fd, mode) != NI_RETCODE_SUCCESS)) + { + return_value = 1; + LRETURN; + } + + p_device_queue = (ni_device_queue_t *)mmap(0, + sizeof(ni_device_queue_t), + PROT_READ | PROT_WRITE, + MAP_SHARED, + shm_fd, + 0); + if (p_device_queue == MAP_FAILED) + { + ni_log(NI_LOG_ERROR, + "ERROR: %s(): mmap failed: %s\n", + __func__, + strerror(NI_ERRNO)); + return_value = 1; + LRETURN; + } + + if (shm_flag == O_RDWR) + { + if (check_correctness(p_device_queue, + should_match_rev, + existing_number_of_devices, + existing_device_names)) + { + LRETURN; + } + + munmap(p_device_queue, sizeof(ni_device_queue_t)); + lockf(lck_fd, F_ULOCK, 0); + close(shm_fd); + delete_shm(); + return ni_rsrc_init_priv(should_match_rev, + existing_number_of_devices, + existing_device_names); + } + + fill_shared_memory(p_device_queue, + should_match_rev, + existing_number_of_devices, + existing_device_names); + +end: + lockf(lck_fd, F_ULOCK, 0); + + if (shm_fd >= 0) + { + close(shm_fd); + } + + return return_value; +} + /*!****************************************************************************** * \brief * @@ -435,6 +1389,7 @@ void ni_rsrc_get_one_device_info (ni_device_info_t * p_device_info) char shm_name[32] = { 0 }; char lck_name[32] = { 0 }; int32_t lock = -1; + bool skip_ftruncate = false; ni_retcode_t error = NI_RETCODE_SUCCESS; ni_device_info_t * p_coder_info_dst = NULL; @@ -446,7 +1401,7 @@ void ni_rsrc_get_one_device_info (ni_device_info_t * p_device_info) ni_rsrc_get_shm_name(p_device_info->device_type, p_device_info->module_id, shm_name, sizeof(shm_name)); ni_rsrc_get_lock_name(p_device_info->device_type, p_device_info->module_id, lck_name, sizeof(lck_name)); - ni_log(NI_LOG_INFO, "Creating shm_name: %s , lck_name %s\n", shm_name, lck_name); + ni_log(NI_LOG_INFO, "shm_name: %s, lck_name %s\n", shm_name, lck_name); #ifdef _ANDROID int ret = ni_rsrc_android_init(); @@ -476,20 +1431,41 @@ void ni_rsrc_get_one_device_info (ni_device_info_t * p_device_info) ni_log(NI_LOG_ERROR, "service->GetAppFlag ret failed ..\n"); LRETURN; } - if (shm_fd <= 0) + if (shm_fd < 0) { - shm_fd = ashmem_create_region(shm_name, sizeof(ni_device_info_t)); - if (shm_fd >= 0) + int fd = ashmem_create_region(shm_name, sizeof(ni_device_info_t)); + if (fd >= 0) { native_handle_t *handle = native_handle_create(1, 0); - handle->data[0] = shm_fd; + handle->data[0] = fd; service->SetAppFlag(param, handle); + shm_fd = dup(fd); ni_log(NI_LOG_ERROR, "Create shm fd %d\n", shm_fd); } } #else - shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, + shm_fd = shm_open(shm_name, + O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (shm_fd == -1) + { + if (NI_ERRNO == 17 /* EEXIST */) + { + skip_ftruncate = true; + shm_fd = shm_open(shm_name, + O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + } + else + { + ni_log(NI_LOG_ERROR, + "ERROR %s() shm_open() CODERS_SHM_NAME: %s\n", + __func__, + strerror(NI_ERRNO)); + error = NI_RETCODE_FAILURE; + LRETURN; + } + } #endif if (shm_fd < 0) @@ -502,7 +1478,7 @@ void ni_rsrc_get_one_device_info (ni_device_info_t * p_device_info) #ifndef _ANDROID /*! configure the size to ni_device_info_t */ - if (ftruncate(shm_fd, sizeof(ni_device_info_t)) < 0) + if (!skip_ftruncate && ftruncate(shm_fd, sizeof(ni_device_info_t)) < 0) { ni_log(NI_LOG_ERROR, "ERROR %s() ftruncate() shm_fd: %s\n", __func__, strerror(NI_ERRNO)); @@ -544,13 +1520,10 @@ void ni_rsrc_get_one_device_info (ni_device_info_t * p_device_info) } END: - -#ifndef _ANDROID - if (shm_fd > 0) + if (shm_fd >= 0) { close(shm_fd); } -#endif if ((NI_RETCODE_SUCCESS != error) && (lock > 0)) { @@ -605,4 +1578,89 @@ void ni_rsrc_update_record(ni_device_context_t *p_device_context, ni_session_con "p_device_info: %s\n", __func__, strerror(NI_ERRNO)); } } + + +/*!****************************************************************************** + * \brief get PCIe address information from device name + * + * \param[in] char *device_name e.g. /dev/nvme0n1. + * \param[out] char *pcie e.g. 0000:0a:00.0. Should be at least 13 bytes including null terminator + * \param[out] char *domain, optional. Should be at least 5 bytes including null terminator + * \param[out] char *slot, optional. Should be at least 3 bytes including null terminator + * \param[out] char *dev, optional. Should be at least 3 bytes including null terminator + * \param[out] char *func, optional. Should be at least 2 bytes including null terminator + * + * \return void + * *******************************************************************************/ +void get_dev_pcie_addr(char *device_name, + char *pcie, + char *domain, char *slot, char *dev, char *func) +{ +#ifndef __linux__ + return; +#else + int i=0; + char *ptr = NULL; + // path to nvme drive + char path[PATH_MAX]; + int ret; + + if(!device_name || !pcie) + { + return ; + } + + // we need to get device name from '/dev/' and remove the trailing 'n1' + char *start = device_name + 5; // skip '/dev/' + char *last_n = strrchr(start, 'n'); + int dev_name_len = (int)(last_n - start); + + // construct the path to /sys/class/nvme/ + snprintf(path, sizeof(path), "/sys/class/nvme/%.*s", dev_name_len, start); + ni_log2(NULL, NI_LOG_DEBUG,"path:%s\n", path); + + // read the target of the symbolic link + char target[PATH_MAX]; + //e.g.: ../../devices/pci0000:00/0000:00:03.1/0000:09:00.0/nvme/nvme0 + ssize_t len = readlink(path, target, sizeof(target) - 1); + if (len == -1) { + perror("readlink"); + return; + } + target[len] = '\0'; // set the null-terminating character + ni_log2(NULL, NI_LOG_DEBUG,"target:%s\n", target); + + // and find domain and slot from it + char *saveptr = NULL; + ptr = ni_strtok(target, "/", &saveptr); + pcie[4] = pcie[7] = ':'; + pcie[10] = '.'; + //last pcie info is for the device + while(ptr != NULL) { + ni_log2(NULL, NI_LOG_DEBUG, "===%d ptr:%s\n", ++i, ptr); + if (strlen(ptr) == 12)//e.g.: 0000:09:00.0 + { + ret = sscanf(ptr, "%4c:%2c:%2c.%1c", pcie, pcie+5,pcie+8,pcie+11); + if (ret != 4) + { + ni_log2(NULL, NI_LOG_DEBUG, "\tsscanf error %d errno %d %s\n", ret, errno, strerror(errno)); + } + } + ni_log2(NULL, NI_LOG_DEBUG, "=====\n"); + ptr = ni_strtok(NULL, "/", &saveptr); + } + pcie[12] = '\0'; + ni_log2(NULL, NI_LOG_DEBUG, "PCIE:%s\n", pcie); + if (!domain || !slot || !dev || !func) + { + goto end; + } + domain[4] = slot[2] = dev[2] = func[1] = '\0'; + sscanf(pcie, "%4[^:]:%2[^:]:%2[^.].%1s", domain, slot, dev, func); + ni_log2(NULL, NI_LOG_DEBUG, "\t%d: Domain: %s, Slot: %s, Device: %s, Function: %s\n", i, domain, slot, dev, func); +end: + return; +#endif +} + #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.h index 0054f656..d377683d 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_priv.h @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_rsrc_priv.h -* -* \brief Private definitions related to resource management of NI Quadra devices -* -*******************************************************************************/ + * \file ni_rsrc_priv.h + * + * \brief Private definitions used by ni_rsrc_api.cpp for management of + * NETINT video processing devices + ******************************************************************************/ #pragma once @@ -34,6 +34,8 @@ extern "C" { #include "ni_device_api.h" +// The macro definition in libxcoder_FFmpeg3.1.1only/source/ni_rsrc_priv.h need to be synchronized with libxcoder +// If you change this,you should also change LOCK_DIR in libxcoder_FFmpeg3.1.1only/source/ni_rsrc_priv.h #ifdef _ANDROID #define LOCK_DIR "/dev/shm_netint" #elif __APPLE__ @@ -44,37 +46,45 @@ extern "C" { #define CODERS_LCK_NAME LOCK_DIR "/NI_LCK_CODERS" -static const char *XCODERS_RETRY_LCK_NAME[] = { +NI_UNUSED static const char *XCODERS_RETRY_LCK_NAME[] = { LOCK_DIR "/NI_RETRY_LCK_DECODERS", LOCK_DIR "/NI_RETRY_LCK_ENCODERS", LOCK_DIR "/NI_RETRY_LCK_SCALERS", LOCK_DIR "/NI_RETRY_LCK_AI"}; #define CODERS_SHM_NAME "NI_SHM_CODERS" +// The macro definition in libxcoder_FFmpeg3.1.1only/source/ni_rsrc_priv.h need to be synchronized with libxcoder +// If you change this,you should also change MAX_LOCK_RETRY LOCK_WAIT in libxcoder_FFmpeg3.1.1only/source/ni_rsrc_priv.h #define MAX_LOCK_RETRY 6000 #define LOCK_WAIT 10000 // wait in us extern LIB_API uint32_t g_xcoder_stop_process; +// The macro definition in libxcoder_FFmpeg3.1.1only/source/ni_rsrc_priv.h need to be synchronized with libxcoder +// If you change these functions,you should also change these functions in libxcoder_FFmpeg3.1.1only/source/ni_rsrc_priv.h void ni_rsrc_get_lock_name(ni_device_type_t device_type, int32_t guid, char* p_name, size_t max_name_len); void ni_rsrc_get_shm_name(ni_device_type_t device_type, int32_t guid, char* p_name, size_t max_name_len); void ni_rsrc_update_record(ni_device_context_t *p_device_context, ni_session_context_t *p_session_ctx); void ni_rsrc_get_one_device_info(ni_device_info_t *p_device_info); ni_retcode_t ni_rsrc_fill_device_info(ni_device_info_t* p_device_info, ni_codec_t fmt, ni_device_type_t type, ni_hw_capability_t* p_hw_cap); -/*!****************************************************************************** - * \brief - * - * \param - * - * \return - *******************************************************************************/ +int ni_rsrc_init_priv(const int should_match_rev, + const int existing_number_of_devices, + const char device_names[NI_MAX_DEVICE_CNT][NI_MAX_DEVICE_NAME_LEN]); int ni_rsrc_enumerate_devices(char ni_devices[][NI_MAX_DEVICE_NAME_LEN], int max_handles); +bool add_to_shared_memory(const char device_name[NI_MAX_DEVICE_NAME_LEN], + const bool device_open_should_succeed, + const int should_match_rev, + ni_device_queue_t *device_queue); int ni_rsrc_strcmp(const void* p_str, const void* p_str1); // return 1 if fw_rev is compatible with NI_XCODER_REVISION, 0 otherwise int ni_is_fw_compatible(uint8_t fw_rev[8]); +void get_dev_pcie_addr(char *device_name, + char *pcie, + char *domain, char *slot, char *dev, char *func); + #ifdef __cplusplus } #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_update.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_update.c index 69edc306..442db950 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_update.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_rsrc_update.c @@ -20,15 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** + * \file ni_rsrc_update.c * - * \file ni_rsrc_update.c - * - * @date may 10, 2019 - * - * \brief - * - * @author - * + * \brief Application for managing registration/deregistration of individual + * NETINT video processing devices on system ******************************************************************************/ #include @@ -55,27 +50,30 @@ #endif /*!****************************************************************************** - * \brief get the NVMe device's character device name (e.g. /dev/nvmeX) + * \brief get the NVMe device's block device name (e.g. /dev/nvmeXnY) * * \param in whole device name passed in - * dev_name full device name without name-space/partition-number + * dev_name full block device name * * \return 0 if value device name is found, -1 otherwise ******************************************************************************/ static int get_dev_name(const char *in, char *dev_name) { - char *tmp = NULL; - - if ( dev_name && (strlen(in) > strlen(DEV_NAME_PREFIX) && strstr(in, DEV_NAME_PREFIX)) ) - { - tmp = (char *)in + strlen(DEV_NAME_PREFIX); - while (isdigit(*tmp)) - tmp++; - strncpy(dev_name, in, tmp - in); - dev_name[tmp - in] = '\0'; + if (!in || !dev_name) + { + ni_log(NI_LOG_ERROR, + "Error: one or more of the given arguments is NULL.\n"); + return -1; + } + + // for linux blk name (/dev/nvmeXnY) + // for apple blk name (/dev/diskX) + // for android blk name (/dev/nvmeXnY or /dev/block/nvmeXnY) + // for windows blk name (\\\\.\\PHYSICALDRIVEX) + strcpy(dev_name, in); + return 0; - } - return -1; + } static void display_help(void) @@ -87,6 +85,8 @@ static void display_help(void) "transcoder card on host\n" " -d device_file Delete the resource entry for a transcoder " "card removed from host\n" + " -D Delete ALL the resource entries for transcoder " + "card on this host\n" " -r Init transcoder card resource regardless " "firmware release version\n" " Default is to only init cards matching current " @@ -98,33 +98,35 @@ static void display_help(void) " -v Print version info and exit\n"); } -/*!****************************************************************************** - * \brief - * - * \param - * - * \return - ******************************************************************************/ int main(int argc, char *argv[]) { - int opt, rc = 0; - char char_dev_name[64]; - int should_match_rev = 1; - int add_dev = 1; // default is to add(not delete) a resource - ni_log_level_t log_level = NI_LOG_INFO; + int opt, rc = 0; + char char_dev_name[64]; + int should_match_rev = 1; + int add_dev = 0; // default is to add(not delete) a resource + int del_dev = 0; + int delete_all = 0; // delete ALL the resources on the host + ni_log_level_t log_level = NI_LOG_INFO; - if (argc == 1) { - display_help(); - return 0; - } + if (argc == 1) { + display_help(); + return 0; + } // arg handling - while ((opt = getopt(argc, argv, "hvra:d:l:")) != -1) + while ((opt = getopt(argc, argv, "hvrDa:d:l:")) != -1) { switch (opt) { case 'd': - add_dev = 0; + rc = get_dev_name(optarg, char_dev_name); + if (rc) + { + fprintf(stderr, "ERROR: get_dev_name() returned %d\n", rc); + return EXIT_FAILURE; + } + del_dev = 1; + break; case 'a': #ifdef __linux__ rc = get_dev_name(optarg, char_dev_name); @@ -133,8 +135,12 @@ int main(int argc, char *argv[]) fprintf(stderr, "ERROR: get_dev_name() returned %d\n", rc); return EXIT_FAILURE; } + add_dev = 1; #endif break; + case 'D': + delete_all = 1; + break; case 'r': should_match_rev = 0; break; @@ -164,22 +170,50 @@ int main(int argc, char *argv[]) } } - if (add_dev) - { - rc = ni_rsrc_add_device(char_dev_name, should_match_rev); - if (rc) - printf("%s not added as transcoder.\n", optarg); - else - printf("Added transcoder %s successfully.\n", char_dev_name); - return rc; - } - else - { - rc = ni_rsrc_remove_device(char_dev_name); - if (rc) - printf("%s not removed as transcoder.\n", optarg); - else - printf("Removed transcoder %s successfully.\n", char_dev_name); - return rc; - } + // check option + if (add_dev && (del_dev || delete_all)) + { + fprintf(stderr, "Error: can not add and delete device at the same time\n\n"); + display_help(); + return 1; + } + if (!should_match_rev && !add_dev) + { + fprintf(stderr, "Error: -r option must be used with -a option\n\n"); + display_help(); + return 1; + } + if (add_dev) + { + rc = ni_rsrc_add_device(char_dev_name, should_match_rev); + if (rc) + printf("%s not added as transcoder.\n", char_dev_name); + else + printf("Added transcoder %s successfully.\n", char_dev_name); + return rc; + } + else if (delete_all) + { + rc = ni_rsrc_remove_all_devices(); + if (rc) + printf("Error removing all transcoder resources.\n"); + else + printf("Removing all transcoder resources successfully.\n"); + return rc; + } + else if (del_dev) + { + rc = ni_rsrc_remove_device(char_dev_name); + if (rc) + printf("%s not removed as transcoder.\n", char_dev_name); + else + printf("Removed transcoder %s successfully.\n", char_dev_name); + return rc; + } + else + { + fprintf(stderr, "Error: ni_rsrc_update option must be used with -a or -b or -D option\n\n"); + display_help(); + return 1; + } } diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.c index 8800e06a..844c9b48 100755 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.c @@ -20,11 +20,10 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_util.c -* -* \brief Exported utility routines -* -*******************************************************************************/ + * \file ni_util.c + * + * \brief Utility definitions + ******************************************************************************/ #if __linux__ || __APPLE__ #include @@ -40,6 +39,94 @@ #include "ni_nvme.h" #include "ni_util.h" +typedef struct _ni_err_rc_txt_entry +{ + ni_retcode_t rc; + const char *txt; +} ni_err_rc_txt_entry_t; + +static const ni_err_rc_txt_entry_t ni_err_rc_description[] = { + {NI_RETCODE_SUCCESS, "SUCCESS"}, + {NI_RETCODE_FAILURE, "FAILURE"}, + {NI_RETCODE_INVALID_PARAM, "INVALID_PARAM"}, + {NI_RETCODE_ERROR_MEM_ALOC, "ERROR_MEM_ALOC"}, + {NI_RETCODE_ERROR_NVME_CMD_FAILED, "ERROR_NVME_CMD_FAILED"}, + {NI_RETCODE_ERROR_INVALID_SESSION, "ERROR_INVALID_SESSION"}, + {NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE, "ERROR_RESOURCE_UNAVAILABLE"}, + {NI_RETCODE_PARAM_INVALID_NAME, "PARAM_INVALID_NAME"}, + {NI_RETCODE_PARAM_INVALID_VALUE, "PARAM_INVALID_VALUE"}, + {NI_RETCODE_PARAM_ERROR_FRATE, "PARAM_ERROR_FRATE"}, + {NI_RETCODE_PARAM_ERROR_BRATE, "PARAM_ERROR_BRATE"}, + {NI_RETCODE_PARAM_ERROR_TRATE, "PARAM_ERROR_TRATE"}, + {NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE, "PARAM_ERROR_VBV_BUFFER_SIZE"}, + {NI_RETCODE_PARAM_ERROR_INTRA_PERIOD, "PARAM_ERROR_INTRA_PERIOD"}, + {NI_RETCODE_PARAM_ERROR_INTRA_QP, "PARAM_ERROR_INTRA_QP"}, + {NI_RETCODE_PARAM_ERROR_GOP_PRESET, "PARAM_ERROR_GOP_PRESET"}, + {NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE, "PARAM_ERROR_CU_SIZE_MODE"}, + {NI_RETCODE_PARAM_ERROR_MX_NUM_MERGE, "PARAM_ERROR_MX_NUM_MERGE"}, + {NI_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN, "PARAM_ERROR_DY_MERGE_8X8_EN"}, + {NI_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN, "PARAM_ERROR_DY_MERGE_16X16_EN"}, + {NI_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN, "PARAM_ERROR_DY_MERGE_32X32_EN"}, + {NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN, "PARAM_ERROR_CU_LVL_RC_EN"}, + {NI_RETCODE_PARAM_ERROR_HVS_QP_EN, "PARAM_ERROR_HVS_QP_EN"}, + {NI_RETCODE_PARAM_ERROR_HVS_QP_SCL, "PARAM_ERROR_HVS_QP_SCL"}, + {NI_RETCODE_PARAM_ERROR_MN_QP, "PARAM_ERROR_MN_QP"}, + {NI_RETCODE_PARAM_ERROR_MX_QP, "PARAM_ERROR_MX_QP"}, + {NI_RETCODE_PARAM_ERROR_MX_DELTA_QP, "PARAM_ERROR_MX_DELTA_QP"}, + {NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP, "PARAM_ERROR_CONF_WIN_TOP"}, + {NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT, "PARAM_ERROR_CONF_WIN_BOT"}, + {NI_RETCODE_PARAM_ERROR_CONF_WIN_L, "PARAM_ERROR_CONF_WIN_L"}, + {NI_RETCODE_PARAM_ERROR_CONF_WIN_R, "PARAM_ERROR_CONF_WIN_R"}, + {NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM, "PARAM_ERROR_USR_RMD_ENC_PARAM"}, + {NI_RETCODE_PARAM_ERROR_BRATE_LT_TRATE, "PARAM_ERROR_BRATE_LT_TRATE"}, + {NI_RETCODE_PARAM_ERROR_RCENABLE, "PARAM_ERROR_RCENABLE"}, + {NI_RETCODE_PARAM_ERROR_MAXNUMMERGE, "PARAM_ERROR_MAXNUMMERGE"}, + {NI_RETCODE_PARAM_ERROR_CUSTOM_GOP, "PARAM_ERROR_CUSTOM_GOP"}, + {NI_RETCODE_PARAM_ERROR_PIC_WIDTH, "PARAM_ERROR_PIC_WIDTH"}, + {NI_RETCODE_PARAM_ERROR_PIC_HEIGHT, "PARAM_ERROR_PIC_HEIGHT"}, + {NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE, "PARAM_ERROR_DECODING_REFRESH_TYPE"}, + {NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN, "PARAM_ERROR_CUSIZE_MODE_8X8_EN"}, + {NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN, "PARAM_ERROR_CUSIZE_MODE_16X16_EN"}, + {NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN, "PARAM_ERROR_CUSIZE_MODE_32X32_EN"}, + {NI_RETCODE_PARAM_ERROR_TOO_BIG, "PARAM_ERROR_TOO_BIG"}, + {NI_RETCODE_PARAM_ERROR_TOO_SMALL, "PARAM_ERROR_TOO_SMALL"}, + {NI_RETCODE_PARAM_ERROR_ZERO, "PARAM_ERROR_ZERO"}, + {NI_RETCODE_PARAM_ERROR_OOR, "PARAM_ERROR_OOR"}, + {NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG, "PARAM_ERROR_WIDTH_TOO_BIG"}, + {NI_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL, "PARAM_ERROR_WIDTH_TOO_SMALL"}, + {NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG, "PARAM_ERROR_HEIGHT_TOO_BIG"}, + {NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL, "PARAM_ERROR_HEIGHT_TOO_SMALL"}, + {NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG, "PARAM_ERROR_AREA_TOO_BIG"}, + {NI_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS, "ERROR_EXCEED_MAX_NUM_SESSIONS"}, + {NI_RETCODE_ERROR_GET_DEVICE_POOL, "ERROR_GET_DEVICE_POOL"}, + {NI_RETCODE_ERROR_LOCK_DOWN_DEVICE, "ERROR_LOCK_DOWN_DEVICE"}, + {NI_RETCODE_ERROR_UNLOCK_DEVICE, "ERROR_UNLOCK_DEVICE"}, + {NI_RETCODE_ERROR_OPEN_DEVICE, "ERROR_OPEN_DEVICE"}, + {NI_RETCODE_ERROR_INVALID_HANDLE, "ERROR_INVALID_HANDLE"}, + {NI_RETCODE_ERROR_INVALID_ALLOCATION_METHOD, "ERROR_INVALID_ALLOCATION_METHOD"}, + {NI_RETCODE_ERROR_VPU_RECOVERY, "ERROR_VPU_RECOVERY"}, + {NI_RETCODE_ERROR_STREAM_ERROR, "ERROR_STREAM_ERROR"}, + + {NI_RETCODE_PARAM_WARNING_DEPRECATED, "PARAM_WARNING_DEPRECATED"}, + {NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH, "PARAM_ERROR_LOOK_AHEAD_DEPTH"}, + {NI_RETCODE_PARAM_ERROR_FILLER, "PARAM_ERROR_FILLER"}, + {NI_RETCODE_PARAM_ERROR_PICSKIP, "PARAM_ERROR_PICSKIP"}, + + {NI_RETCODE_PARAM_WARN, "PARAM_WARN"}, + + {NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL, "NVME_SC_WRITE_BUFFER_FULL"}, + {NI_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE, "NVME_SC_RESOURCE_UNAVAILABLE"}, + {NI_RETCODE_NVME_SC_RESOURCE_IS_EMPTY, "NVME_SC_RESOURCE_IS_EMPTY"}, + {NI_RETCODE_NVME_SC_RESOURCE_NOT_FOUND, "NVME_SC_RESOURCE_NOT_FOUND"}, + {NI_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED, "NVME_SC_REQUEST_NOT_COMPLETED"}, + {NI_RETCODE_NVME_SC_REQUEST_IN_PROGRESS, "NVME_SC_REQUEST_IN_PROGRESS"}, + {NI_RETCODE_NVME_SC_INVALID_PARAMETER, "NVME_SC_INVALID_PARAMETER"}, + {NI_RETCODE_NVME_SC_STREAM_ERROR, "NVME_SC_STREAM_ERROR"}, + {NI_RETCODE_NVME_SC_VPU_RECOVERY, "NVME_SC_VPU_RECOVERY"}, + {NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT, "NVME_SC_VPU_RSRC_INSUFFICIENT"}, + {NI_RETCODE_NVME_SC_VPU_GENERAL_ERROR, "NVME_SC_VPU_GENERAL_ERROR"}, +}; + /*!***************************************************************************** * \brief Get time for logs with microsecond timestamps * @@ -94,20 +181,33 @@ uint32_t ni_round_up(uint32_t number_to_round, uint32_t multiple) return (number_to_round + multiple - remainder); } -int32_t ni_posix_memalign(void **pp_memptr, size_t alignment, size_t size) +/*!***************************************************************************** + * \brief Allocate aligned memory + * + * \param[in/out] memptr The address of the allocated memory will be a + * multiple of alignment, which must be a power of two + * and a multiple of sizeof(void *). If size is 0, then + * the value placed is either NULL, or a unique pointer + * value that can later be successfully passed to free. + * \param[in] alignment The alignment value of the allocated value. + * \param[in] size The allocated memory size. + * + * \return 0 for success, ENOMEM for error + ******************************************************************************/ +int ni_posix_memalign(void **memptr, size_t alignment, size_t size) { #ifdef _WIN32 - *pp_memptr = malloc(size); - if (NULL == *pp_memptr) + *memptr = _aligned_malloc(size, alignment); + if (NULL == *memptr) { - return 1; + return ENOMEM; } else { - ZeroMemory(*pp_memptr, size); + ZeroMemory(*memptr, size); return 0; } #else - return posix_memalign(pp_memptr, alignment, size); + return posix_memalign(memptr, alignment, size); #endif } @@ -128,6 +228,8 @@ uint32_t ni_get_kernel_max_io_size(const char * p_dev) size_t len = 0; int err = 0; + memset(file_name, 0, KERNEL_NVME_FILE_NAME_MAX_SZ); + if (!p_dev) { ni_log(NI_LOG_ERROR, "Invalid Arguments\n"); @@ -143,7 +245,7 @@ uint32_t ni_get_kernel_max_io_size(const char * p_dev) // Get Max number of segments from /sys memset(file_name, 0, sizeof(file_name)); - strncpy(file_name, SYS_PARAMS_PREFIX_PATH, SYS_PREFIX_SZ); + strcpy(file_name, SYS_PARAMS_PREFIX_PATH); //start from 5 chars ahead to not copy the "/dev/" since we only need whats after it strncat(file_name, (char *)(p_dev + 5), sizeof(file_name) - SYS_PREFIX_SZ); strncat(file_name, KERNEL_NVME_MAX_SEG_PATH, @@ -167,7 +269,7 @@ uint32_t ni_get_kernel_max_io_size(const char * p_dev) p_file = NULL; // Get Max segment size from /sys memset(file_name, 0, sizeof(file_name)); - strncpy(file_name, SYS_PARAMS_PREFIX_PATH, SYS_PREFIX_SZ); + strcpy(file_name, SYS_PARAMS_PREFIX_PATH); strncat(file_name, (char *)(p_dev + 5), sizeof(file_name) - SYS_PREFIX_SZ); strncat(file_name, KERNEL_NVME_MIN_IO_SZ_PATH, sizeof(file_name) - SYS_PREFIX_SZ - len); @@ -190,7 +292,7 @@ uint32_t ni_get_kernel_max_io_size(const char * p_dev) p_file = NULL; //Now get max_hw_sectors_kb memset(file_name, 0, sizeof(file_name)); - strncpy(file_name, SYS_PARAMS_PREFIX_PATH, SYS_PREFIX_SZ); + strcpy(file_name, SYS_PARAMS_PREFIX_PATH); strncat(file_name, (char *)(p_dev + 5), sizeof(file_name) - SYS_PREFIX_SZ); strncat(file_name, KERNEL_NVME_MAX_HW_SEC_KB_PATH, sizeof(file_name) - SYS_PREFIX_SZ - len); @@ -213,13 +315,13 @@ uint32_t ni_get_kernel_max_io_size(const char * p_dev) MAX_IO_TRANSFER_SIZE) { io_size = MAX_IO_TRANSFER_SIZE; - //printf("max_io_size is set to: %d because its bigger than maximum limit of: %d\n",io_size, MAX_IO_TRANSFER_SIZE); + //ni_log(NI_LOG_INFO, "max_io_size is set to: %d because its bigger than maximum limit of: %d\n",io_size, MAX_IO_TRANSFER_SIZE); } else { io_size = ni_min(min_io_size * max_segments, max_hw_sectors_kb * 1024); } - // printf("\nMAX NVMe IO Size of %d was calculated for this platform and will + // ni_log(NI_LOG_INFO, "\nMAX NVMe IO Size of %d was calculated for this platform and will // be used unless overwritten by user settings\n",io_size); fflush(stdout); @@ -297,6 +399,35 @@ void ni_usleep(int64_t usec) #endif } +char *ni_strtok(char *s, const char *delim, char **saveptr) +{ + char *tok; + + if (!s && !(s = *saveptr)) + return NULL; + + /* skip leading delimiters */ + s += strspn(s, delim); + + /* s now points to the first non delimiter char, or to the end of the string */ + if (!*s) { + *saveptr = NULL; + return NULL; + } + tok = s++; + + /* skip non delimiters */ + s += strcspn(s, delim); + if (*s) { + *s = '\0'; + *saveptr = s+1; + } else { + *saveptr = NULL; + } + + return tok; +} + // memory buffer pool operations (one use is for decoder frame buffer pool) // expand buffer pool by a pre-defined size ni_buf_t *ni_buf_pool_expand(ni_buf_pool_t *pool) @@ -391,7 +522,7 @@ void ni_buf_pool_return_buffer(ni_buf_t *buf, ni_buf_pool_t *p_buffer_pool) if (!p_buffer_pool) { ni_log(NI_LOG_DEBUG, "%s: pool already freed, self destroy\n", __func__); - free(buf->buf); + ni_aligned_free(buf->buf); free(buf); return; } @@ -447,7 +578,7 @@ ni_buf_t *ni_buf_pool_allocate_buffer(ni_buf_pool_t *p_buffer_pool, if (ni_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), buffer_size)) { - free(p_buffer); + ni_aligned_free(p_buffer); return NULL; } ni_log(NI_LOG_DEBUG, "%s ptr %p buf %p\n", __func__, p_buf, p_buffer); @@ -483,7 +614,7 @@ int32_t ni_dec_fme_buffer_pool_initialize(ni_session_context_t* p_ctx, int width_aligned; int height_aligned; - ni_log(NI_LOG_TRACE, "%s: enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__); if (QUADRA) { @@ -526,7 +657,7 @@ int32_t ni_dec_fme_buffer_pool_initialize(ni_session_context_t* p_ctx, if (p_ctx->dec_fme_buf_pool != NULL) { - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "Warning init dec_fme Buf pool already with size %u\n", p_ctx->dec_fme_buf_pool->number_of_buffers); @@ -553,7 +684,7 @@ int32_t ni_dec_fme_buffer_pool_initialize(ni_session_context_t* p_ctx, if ((p_ctx->dec_fme_buf_pool = (ni_buf_pool_t *)malloc(sizeof(ni_buf_pool_t))) == NULL) { - ni_log(NI_LOG_ERROR, "Error alloc for dec fme buf pool\n"); + ni_log2(p_ctx, NI_LOG_ERROR, "Error alloc for dec fme buf pool\n"); return -1; } @@ -562,7 +693,7 @@ int32_t ni_dec_fme_buffer_pool_initialize(ni_session_context_t* p_ctx, ni_pthread_mutex_init(&p_ctx->dec_fme_buf_pool->mutex); p_ctx->dec_fme_buf_pool->number_of_buffers = number_of_buffers; - ni_log(NI_LOG_DEBUG, + ni_log2(p_ctx, NI_LOG_DEBUG, "ni_dec_fme_buffer_pool_initialize: entries %d entry size " "%d\n", number_of_buffers, buffer_size); @@ -579,7 +710,7 @@ int32_t ni_dec_fme_buffer_pool_initialize(ni_session_context_t* p_ctx, } } - ni_log(NI_LOG_TRACE, "%s: exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s: exit\n", __func__); return 0; } @@ -614,7 +745,7 @@ void ni_dec_fme_buffer_pool_free(ni_buf_pool_t *p_buffer_pool) while (buf) { p_next = buf->p_next_buffer; - free(buf->buf); + ni_aligned_free(buf->buf); free(buf); buf = p_next; count_free++; @@ -633,7 +764,7 @@ void ni_dec_fme_buffer_pool_free(ni_buf_pool_t *p_buffer_pool) } else { - ni_log(NI_LOG_ERROR, "%s: NOT allocated\n", __func__); + ni_log(NI_LOG_INFO, "%s: NOT allocated\n", __func__); } } @@ -677,7 +808,7 @@ void ni_buffer_pool_free(ni_queue_buffer_pool_t *p_buffer_pool) } else { - ni_log(NI_LOG_ERROR, "%s: NOT allocated\n", __func__); + ni_log(NI_LOG_INFO, "%s: NOT allocated\n", __func__); } } @@ -713,11 +844,11 @@ int32_t ni_buffer_pool_initialize(ni_session_context_t* p_ctx, int32_t number_of { int i; - ni_log(NI_LOG_TRACE, "%s: enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__); if (p_ctx->buffer_pool != NULL) { - ni_log(NI_LOG_DEBUG, "Warn init Buf pool already with size %u\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "Warn init Buf pool already with size %u\n", p_ctx->buffer_pool->number_of_buffers); return -1; } @@ -893,6 +1024,7 @@ static ni_retcode_t ni_search_file(const char *p_dev, char *cmd, char *cmd_ret, int cmd_ret_len) { FILE *cmd_fp; + ni_retcode_t ret = NI_RETCODE_SUCCESS; if (access(p_dev, F_OK) == -1) { @@ -908,12 +1040,115 @@ static ni_retcode_t ni_search_file(const char *p_dev, char *cmd, char *cmd_ret, if (fgets(cmd_ret, cmd_ret_len, cmd_fp) == 0) { - return NI_RETCODE_INVALID_PARAM; + ret = NI_RETCODE_INVALID_PARAM; } + pclose(cmd_fp); - return NI_RETCODE_SUCCESS; + return ret; } #endif +/*!****************************************************************************** +* \brief Remove a string-pattern from a string in-place. +* +* \param[in,out] main_str Null terminated array of characters to operate upon in-place. +* \param[in] pattern Null terminated array of characters to remove from main_str. +* Supports special characters '#' and '+' for digit matching and +* repeated matching respectively. Note, there is no way to \a escape +* the special characters. +* \b Example: +* char a_str[10] = "aaa123qwe"; +* char b_str[5] = "a+#+"; +* remove_substring_pattern(a_str, b_str); +* printf("%s\n", a_str); +* \b Output: +* qwe +* +* \return If characters removed, returns 1 +* If no characters removed, returns 0 +*******************************************************************************/ +NI_UNUSED static uint32_t remove_substring_pattern(char *main_str, const char *pattern) +{ + uint32_t i, j; // for loop counters + uint32_t match_length; // length of matching substring + uint32_t matched_chr; // boolean flag for when match is found for a character in the pattern + char char_match_pattern[11] = ""; // what characters to look for when evaluating a character in main_str + uint32_t pattern_matched = 0; // boolean flag for when who pattern match is found + uint32_t pattern_start = 0; // starting index in main_str of substring matching pattern + const char digit_match_pattern[11] = "0123456789"; // set of numeric digits for expansion of special character '#' + + // do not accept zero length main_str or pattern + if (!main_str || !pattern || !*main_str || !*pattern) + { + return 0; + } + + // iterate over all characters in main_str looking for starting index of matching pattern + for (i = 0; i < strlen(main_str) && !pattern_matched; i++) + { + pattern_matched = 0; + match_length = 0; + // iterate over the characters of the pattern + for (j = 0; j < strlen(pattern); j++) + { + matched_chr = 0; + // set which characters to look for, special cases for special control characters + if (pattern[j] == '+') + { + // immediately fail as entering this branch means either the first character is a '+', or a '+" following a "+' + return 0; + } + else if (pattern[j] == '#') + { + memcpy(char_match_pattern, digit_match_pattern, strlen(digit_match_pattern) + 1); + } + else + { + memcpy(char_match_pattern, pattern + j, 1); + memset(char_match_pattern + 1, 0, 1); + } + // check if char is in match_pattern + if (pattern[j+1] == '+') + { + while (main_str[i + match_length] && strchr(char_match_pattern, (int) main_str[i + match_length])) + { + match_length++; + matched_chr = 1; + } + j++; + } + else if (main_str[i + match_length] && strchr(char_match_pattern, (int) main_str[i + match_length])) + { + match_length++; + matched_chr = 1; + } + // if no matches were found, then this segment is not the sought pattern + if (!matched_chr) + { + break; + } + // if all of pattern has been processed and matched, mark sucessful whole pattern match + else if ((j + 1) >= strlen(pattern)) + { + pattern_matched = 1; + pattern_start = i; + } + } + } + + // remove sub-string if its pattern was found in main_str + if (pattern_matched) + { + uint32_t orig_main_str_len = (uint32_t)strlen(main_str); + memmove(main_str + pattern_start, main_str + pattern_start + match_length, + strlen(main_str + pattern_start + match_length)); + main_str[orig_main_str_len - match_length] = 0; + return 1; + } + else + { + return 0; + } +} /*!****************************************************************************** * \brief Find NVMe name space block from device name @@ -939,94 +1174,110 @@ ni_retcode_t ni_find_blk_name(const char *p_dev, char *p_out_buf, int out_buf_le snprintf(p_out_buf, out_buf_len, "%s", p_dev); return NI_RETCODE_SUCCESS; #elif __APPLE__ + /* + Using smartctl /dev/rdisk4 -i | grep 'PCI Vendor' command check if output + contains Quadra. Model number could be duplicated in other devices so + should use PCI Vendor instead but smartctl is not preinstalled on mac + snprintf(command, sizeof(command) - 1, + "smartctl %s -i | grep 'PCI Vendor'", p_dev); + */ + FILE *cmd_fp; + char cmd_ret[60] = {0}; + char command[128] = {0}; + snprintf(command, sizeof(command) - 1, + "diskutil info %s | grep 'Media Name'", p_dev); + ni_log(NI_LOG_TRACE, "Using %s to find quadra device\n", command); + cmd_fp = popen(command, "r"); + if (cmd_fp == NULL) + { + ni_log(NI_LOG_ERROR, "Failed to execute %s\n", command); + return NI_RETCODE_FAILURE; + } + if (fgets(cmd_ret, sizeof(cmd_ret) - 1, cmd_fp) == NULL) + { + ni_log(NI_LOG_ERROR, "Failed to read %s output.\n", command); + pclose(cmd_fp); + return NI_RETCODE_FAILURE; + } + pclose(cmd_fp); + ni_log(NI_LOG_TRACE, "Got '%s' from the command\n", cmd_ret); + // if (strcasestr(cmd_ret, "0x1d82") != NULL) + if (strcasestr(cmd_ret, "Quadra") != NULL) + { + snprintf(p_out_buf, out_buf_len, "%s", p_dev); + return NI_RETCODE_SUCCESS; + } else + { + //This is a soft error so trace level is fine + ni_log(NI_LOG_TRACE, "%s is not a quadra device\n", p_dev); + return NI_RETCODE_INVALID_PARAM; + } +#elif defined(XCODER_LINUX_VIRTIO_DRIVER_ENABLED) + ni_log(NI_LOG_TRACE, "The device is already considered as a block divice in Linux virtual machine with VirtIO driver.\n"); snprintf(p_out_buf, out_buf_len, "%s", p_dev); return NI_RETCODE_SUCCESS; #else - FILE *cmd_fp; - char cmd_ret[16] = ""; - char udev_cmd[80] = ""; - -#ifdef _ANDROID - // assumes no indexing differences between sysfs and udev on Android (ie. no nvme multi-pathing) - snprintf(udev_cmd, sizeof(udev_cmd) - 1, - "ls /sys/class/nvme/%s/ | grep nvme", &p_dev[5]); -#else - // Note, we are using udevadm through terminal instead of libudev.c to avoid requiring extra kernel dev packges - snprintf(udev_cmd, sizeof(udev_cmd) - 1, - "ls /sys/`udevadm info -q path -n %s` | grep -P \"nvme\\d+n1\"", - p_dev); + ni_log(NI_LOG_DEBUG, "Set NVMe device name equal to NVMe block name\n"); + snprintf(p_out_buf, out_buf_len, "%s", p_dev); + return NI_RETCODE_SUCCESS; #endif +} - // check p_dev exists in /dev/ folder. If not, return NI_INVALID_DEVICE_HANDLE - if (access(p_dev, F_OK) == -1) +/*!****************************************************************************** + * \brief check dev name + * + * \param[in] p_dev Device name represented as c string. ex: "/dev/nvmeXnY" + * + * \return On success returns NI_RETCODE_SUCCESS + * On failure returns NI_RETCODE_FAILURE or NI_RETCODE_INVALID_PARAM + *******************************************************************************/ +ni_retcode_t ni_check_dev_name(const char *p_dev) +{ + if (!p_dev) { - return NI_RETCODE_FAILURE; + return NI_RETCODE_INVALID_PARAM; } - // look for child block in sysfs mapping tree - cmd_fp = popen(udev_cmd, "r"); - if (!cmd_fp) +#ifdef __APPLE__ + /* + Using smartctl /dev/rdisk4 -i | grep 'PCI Vendor' command check if output + contains Quadra. Model number could be duplicated in other devices so + should use PCI Vendor instead but smartctl is not preinstalled on mac + snprintf(command, sizeof(command) - 1, + "smartctl %s -i | grep 'PCI Vendor'", p_dev); + */ + FILE *cmd_fp; + char cmd_ret[60] = {0}; + char command[128] = {0}; + snprintf(command, sizeof(command) - 1, + "diskutil info %s | grep 'Media Name'", p_dev); + ni_log(NI_LOG_TRACE, "Using %s to find quadra device\n", command); + cmd_fp = popen(command, "r"); + if (cmd_fp == NULL) + { + ni_log(NI_LOG_ERROR, "Failed to execute %s\n", command); + return NI_RETCODE_FAILURE; + } + if (fgets(cmd_ret, sizeof(cmd_ret) - 1, cmd_fp) == NULL) { + ni_log(NI_LOG_ERROR, "Failed to read %s output.\n", command); + pclose(cmd_fp); return NI_RETCODE_FAILURE; } - - if (fgets(cmd_ret, sizeof(cmd_ret) / sizeof(cmd_ret[0]), cmd_fp) == 0) + pclose(cmd_fp); + ni_log(NI_LOG_TRACE, "Got '%s' from the command\n", cmd_ret); + // if (strcasestr(cmd_ret, "0x1d82") != NULL) + if (strcasestr(cmd_ret, "Quadra") != NULL) { - ni_log(NI_LOG_DEBUG, - "WARNING: cannot find namespaceID. Using guess.\n"); - snprintf(p_out_buf, out_buf_len, "%sn1", p_dev); + return NI_RETCODE_SUCCESS; } else { - cmd_ret[strcspn(cmd_ret, "\r\n")] = 0; -#ifdef _ANDROID - ni_retcode_t ret = NI_RETCODE_SUCCESS; - snprintf(udev_cmd, sizeof(udev_cmd) - 1, "ls /dev/ | grep %s", - cmd_ret); // cmd_ret is block device name - int cmd_ret_len = sizeof(cmd_ret) / sizeof(cmd_ret[0]); - ret = ni_search_file(p_dev, udev_cmd, cmd_ret, cmd_ret_len); - if (ret == NI_RETCODE_SUCCESS) - { - char *tmp = NULL; - if ((tmp = strstr(cmd_ret, "\n"))) - { - *tmp = '\0'; - } - snprintf(p_out_buf, out_buf_len, "/dev/%s", cmd_ret); - } else if (ret == NI_RETCODE_INVALID_PARAM) - { - snprintf(udev_cmd, sizeof(udev_cmd) - 1, "ls /dev/block/ | grep %s", - cmd_ret); // cmd_ret is block device name - ret = ni_search_file(p_dev, udev_cmd, cmd_ret, cmd_ret_len); - if (ret == NI_RETCODE_SUCCESS) - { - char *tmp = NULL; - if ((tmp = strstr(cmd_ret, "\n"))) - { - *tmp = '\0'; - } - snprintf(p_out_buf, out_buf_len, "/dev/block/%s", cmd_ret); - } else if (ret == NI_RETCODE_INVALID_PARAM) - { - ni_log(NI_LOG_ERROR, - "Error: ni_find_blk_name can not find block device %s\n", - cmd_ret); - } else - { - return ret; - } - } else - { - return ret; - } -#else - snprintf(p_out_buf, out_buf_len, "/dev/%s", cmd_ret); -#endif + //This is a soft error so trace level is fine + ni_log(NI_LOG_TRACE, "%s is not a quadra device\n", p_dev); + return NI_RETCODE_INVALID_PARAM; } - - pclose(cmd_fp); - - return NI_RETCODE_SUCCESS; #endif + return NI_RETCODE_SUCCESS; } /*!****************************************************************************** @@ -1040,16 +1291,16 @@ ni_retcode_t ni_timestamp_init(ni_session_context_t* p_ctx, ni_timestamp_table_t { ni_timestamp_table_t *ptemp; - ni_log(NI_LOG_TRACE, "%s: enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__); if (*pp_table != NULL) { - ni_log(NI_LOG_DEBUG, "%s: previously allocated, reallocating now\n", + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: previously allocated, reallocating now\n", __func__); ni_queue_free(&(*pp_table)->list, p_ctx->buffer_pool); free(*pp_table); } - ni_log(NI_LOG_DEBUG, "%s: Malloc\n", __func__); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: Malloc\n", __func__); ptemp = (ni_timestamp_table_t *)malloc(sizeof(ni_timestamp_table_t)); if (!ptemp) { @@ -1064,7 +1315,7 @@ ni_retcode_t ni_timestamp_init(ni_session_context_t* p_ctx, ni_timestamp_table_t *pp_table = ptemp; - ni_log(NI_LOG_DEBUG, "%s: success\n", __func__); + ni_log2(p_ctx, NI_LOG_DEBUG, "%s: success\n", __func__); return NI_RETCODE_SUCCESS; } @@ -1243,7 +1494,7 @@ ni_retcode_t ni_timestamp_get_v2(ni_timestamp_table_t *p_table, *******************************************************************************/ ni_retcode_t ni_queue_init(ni_session_context_t* p_ctx, ni_queue_t *p_queue, const char *name) { - ni_log(NI_LOG_TRACE, "%s: enter\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__); if (!p_queue || !name) { @@ -1256,7 +1507,7 @@ ni_retcode_t ni_queue_init(ni_session_context_t* p_ctx, ni_queue_t *p_queue, con p_queue->p_last = NULL; p_queue->count = 0; - ni_log(NI_LOG_TRACE, "%s: exit\n", __func__); + ni_log2(p_ctx, NI_LOG_TRACE, "%s: exit\n", __func__); return NI_RETCODE_SUCCESS; } @@ -1402,11 +1653,7 @@ ni_retcode_t ni_queue_pop(ni_queue_t *p_queue, uint64_t frame_info, temp = temp->p_prev; temp_prev = temp->p_prev; - if (!temp_prev) - { - p_queue->p_first = temp->p_next; - temp->p_next->p_prev = NULL; - } else + if (temp_prev) { temp_prev->p_next = temp->p_next; if (temp->p_next) @@ -1416,6 +1663,10 @@ ni_retcode_t ni_queue_pop(ni_queue_t *p_queue, uint64_t frame_info, { p_queue->p_last = temp_prev; } + } else + { + p_queue->p_first = temp->p_next; + temp->p_next->p_prev = NULL; } //free(temp); ni_buffer_pool_return_buffer(temp, p_buffer_pool); @@ -1489,11 +1740,7 @@ ni_retcode_t ni_queue_pop_threshold(ni_queue_t *p_queue, uint64_t frame_info, if (llabs((int)frame_info - (int)temp->frame_info) <= threshold) { *p_timestamp = temp->timestamp; - if (!temp_prev) - { - p_queue->p_first = temp->p_next; - temp->p_next->p_prev = NULL; - } else + if (temp_prev) { temp_prev->p_next = temp->p_next; if (temp->p_next) @@ -1503,6 +1750,10 @@ ni_retcode_t ni_queue_pop_threshold(ni_queue_t *p_queue, uint64_t frame_info, { p_queue->p_last = temp_prev; } + } else + { + p_queue->p_first = temp->p_next; + temp->p_next->p_prev = NULL; } // free(temp); ni_buffer_pool_return_buffer(temp, p_buffer_pool); @@ -1760,38 +2011,36 @@ uint64_t ni_gettime_ns(void) * * \param[in] width source YUV frame width * \param[in] height source YUV frame height - * \param[in] bit_depth_factor 1 for 8 bit, 2 for 10 bit - * \param[in] is_nv12 non-0 for NV12 frame, 0 otherwise + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] is_semiplanar 1 for semiplanar frame, 0 otherwise * \param[out] plane_stride size (in bytes) of each plane width * \param[out] plane_height size of each plane height * * \return Y/Cb/Cr stride and height info * ******************************************************************************/ -void ni_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, - int is_nv12, +void ni_get_hw_yuv420p_dim(int width, int height, int factor, + int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS]) { // strides are multiples of 128 if (width < NI_MIN_WIDTH) { - plane_stride[0] = ((NI_MIN_WIDTH * bit_depth_factor + 127) / 128) * 128; + plane_stride[0] = ((NI_MIN_WIDTH * factor + 127) / 128) * 128; plane_stride[1] = - (((NI_MIN_WIDTH / (is_nv12 ? 1 : 2) * bit_depth_factor) + 127) / - 128) * - 128; - plane_stride[2] = - ((((is_nv12 ? 0 : NI_MIN_WIDTH) / 2 * bit_depth_factor) + 127) / + (((NI_MIN_WIDTH / (is_semiplanar ? 1 : 2) * factor) + 127) / 128) * 128; + plane_stride[2] = (is_semiplanar ? 0 : plane_stride[1]); } else { - plane_stride[0] = ((width * bit_depth_factor + 127) / 128) * 128; + width = ((width + 1) / 2) * 2; // pad odd resolution + plane_stride[0] = ((width * factor + 127) / 128) * 128; plane_stride[1] = - (((width / (is_nv12 ? 1 : 2) * bit_depth_factor) + 127) / 128) * + (((width / (is_semiplanar ? 1 : 2) * factor) + 127) / 128) * 128; - plane_stride[2] = (is_nv12 ? 0 : plane_stride[1]); + plane_stride[2] = (is_semiplanar ? 0 : plane_stride[1]); } // height (in lines) just needs to be even number @@ -1806,141 +2055,516 @@ void ni_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, } /*!***************************************************************************** - * \brief Copy YUV data to Netint HW YUV420p frame layout to be sent + * \brief Get dimension information of frame to be sent + * to encoder for encoding. Caller usually retrieves this info and + * uses it in the call to ni_encoder_frame_buffer_alloc for buffer + * allocation. + * The returned stride and height info will take alignment + * requirements into account. + * + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] pix_fmt ni pixel format + * \param[out] plane_stride size (in bytes) of each plane width + * \param[out] plane_height size of each plane height + * + * \return stride and height info + * + ******************************************************************************/ +void ni_get_frame_dim(int width, int height, + ni_pix_fmt_t pix_fmt, + int plane_stride[NI_MAX_NUM_DATA_POINTERS], + int plane_height[NI_MAX_NUM_DATA_POINTERS]) +{ + plane_height[0] = ((height + 1) / 2) * 2; + plane_height[1] = plane_height[2] = plane_height[0] / 2; + + switch (pix_fmt) + { + /* 8-bit YUV420 planar */ + case NI_PIX_FMT_YUV420P: + plane_stride[0] = NI_VPU_ALIGN128(width); + plane_stride[1] = NI_VPU_ALIGN128((width / 2)); + plane_stride[2] = plane_stride[1]; + plane_stride[3] = 0; + break; + /* 10-bit YUV420 planar, little-endian, least significant bits */ + case NI_PIX_FMT_YUV420P10LE: + plane_stride[0] = NI_VPU_ALIGN128(width * 2); + plane_stride[1] = NI_VPU_ALIGN128(width); + plane_stride[2] = plane_stride[1]; + plane_stride[3] = 0; + break; + /* 8-bit YUV420 semi-planar */ + case NI_PIX_FMT_NV12: + plane_stride[0] = NI_VPU_ALIGN128(width); + plane_stride[1] = plane_stride[0]; + plane_stride[2] = 0; + plane_stride[3] = 0; + break; + /* 8-bit yuv422 semi-planar */ + case NI_PIX_FMT_NV16: + plane_stride[0] = NI_VPU_ALIGN64(width); + plane_stride[1] = plane_stride[0]; + plane_stride[2] = 0; + plane_stride[3] = 0; + break; + /*8-bit yuv422 planar */ + case NI_PIX_FMT_YUYV422: + case NI_PIX_FMT_UYVY422: + plane_stride[0] = NI_VPU_ALIGN16(width) * 2; + plane_stride[1] = 0; + plane_stride[2] = 0; + plane_stride[3] = 0; + break; + /* 10-bit YUV420 semi-planar, little endian, most significant bits */ + case NI_PIX_FMT_P010LE: + plane_stride[0] = NI_VPU_ALIGN128(width * 2); + plane_stride[1] = plane_stride[0]; + plane_stride[2] = 0; + plane_stride[3] = 0; + break; + /* 32-bit RGBA packed */ + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + case NI_PIX_FMT_BGR0: + plane_height[1] = plane_height[2] = 0; + + plane_stride[0] = NI_VPU_ALIGN16(width) * 4; + plane_stride[1] = 0; + plane_stride[2] = 0; + plane_stride[3] = 0; + break; + default: + break; + } + +} + +/*!***************************************************************************** + * \brief Get dimension information of frame to be sent + * to encoder for encoding. Caller usually retrieves this info and + * uses it in the call to ni_encoder_frame_buffer_alloc for buffer + * allocation. + * The returned stride and height info will take into account both min + * resolution and alignment requirements. + * + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] pix_fmt ni pixel format + * \param[out] plane_stride size (in bytes) of each plane width + * \param[out] plane_height size of each plane height + * + * \return stride and height info + * + ******************************************************************************/ +void ni_get_min_frame_dim(int width, int height, + ni_pix_fmt_t pix_fmt, + int plane_stride[NI_MAX_NUM_DATA_POINTERS], + int plane_height[NI_MAX_NUM_DATA_POINTERS]) +{ + + if (height < NI_MIN_HEIGHT) + { + height = NI_MIN_HEIGHT; + } + if (width < NI_MIN_WIDTH) + { + width = NI_MIN_WIDTH; + } + else + { + width = ((width + 1) / 2) * 2; // pad odd resolution + } + + ni_get_frame_dim(width, height, pix_fmt, plane_stride, plane_height); + + ni_log(NI_LOG_DEBUG, + "%s dst_stride %d/%d/%d height %d/%d/%d pix_fmt %d\n", + __func__, plane_stride[0], plane_stride[1], plane_stride[2], + plane_height[0], plane_height[1], plane_height[2], pix_fmt); +} + +/*!***************************************************************************** + * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent * to encoder for encoding. Data buffer (dst) is usually allocated by * ni_encoder_frame_buffer_alloc. * - * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied - * \param[in] p_src pointers of Y/Cb/Cr from which data is copied - * \param[in] width source YUV frame width - * \param[in] height source YUV frame height - * \param[in] bit_depth_factor 1 for 8 bit, 2 for 10 bit - * \param[in] is_nv12 non-0 for NV12 frame, 0 otherwise + * \param[out] p_dst pointers to which data is copied + * \param[in] p_src pointers from which data is copied + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise * \param[in] conf_win_right right offset of conformance window * \param[in] dst_stride size (in bytes) of each plane width in destination * \param[in] dst_height size of each plane height in destination * \param[in] src_stride size (in bytes) of each plane width in source * \param[in] src_height size of each plane height in source + * \param[in] i index to plane to be copied * - * \return Y/Cb/Cr data + * \return copied data * ******************************************************************************/ -void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], - uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], - int frame_width, int frame_height, int bit_depth_factor, - int is_nv12, int conf_win_right, - int dst_stride[NI_MAX_NUM_DATA_POINTERS], - int dst_height[NI_MAX_NUM_DATA_POINTERS], - int src_stride[NI_MAX_NUM_DATA_POINTERS], - int src_height[NI_MAX_NUM_DATA_POINTERS]) +void ni_copy_plane_data(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], + int frame_width, int frame_height, int factor, + int is_semiplanar, int conf_win_right, + int dst_stride[NI_MAX_NUM_DATA_POINTERS], + int dst_height[NI_MAX_NUM_DATA_POINTERS], + int src_stride[NI_MAX_NUM_DATA_POINTERS], + int src_height[NI_MAX_NUM_DATA_POINTERS], + int i) { - // return to avoid self copy - if (p_dst[0] == p_src[0] && p_dst[1] == p_src[1] && p_dst[2] == p_src[2]) + if (i >= NI_MAX_NUM_DATA_POINTERS) + { + ni_log(NI_LOG_ERROR, "%s: error, invalid plane index %d\n", __func__, + i); + return; + } + if (p_dst[i] == p_src[i]) { ni_log(NI_LOG_DEBUG, "%s: src and dst identical, return\n", __func__); return; } - ni_log(NI_LOG_DEBUG, - "%s dst_stride %d/%d/%d src_stride %d/%d/%d dst_height " - "%d/%d/%d src_height %d/%d/%d\n", - __func__, dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0], - src_stride[1], src_stride[2], dst_height[0], dst_height[1], - dst_height[2], src_height[0], src_height[1], src_height[2]); + int height = + (src_height[i] < dst_height[i] ? src_height[i] : dst_height[i]); + uint8_t *dst = p_dst[i]; + const uint8_t *src = (const uint8_t *)p_src[i]; // width padding length in bytes, if needed int pad_len_bytes; - int i; - for (i = 0; i < NI_MAX_NUM_DATA_POINTERS - 1; i++) + if (0 == i || is_semiplanar) // Y + { + pad_len_bytes = dst_stride[i] - frame_width * factor; + } + else { - int height = - (src_height[i] < dst_height[i] ? src_height[i] : dst_height[i]); - uint8_t *dst = p_dst[i]; - const uint8_t *src = (const uint8_t *)p_src[i]; + // U/V share the same padding length + pad_len_bytes = dst_stride[i] - frame_width / 2 * factor; + } - if (0 == i || is_nv12) // Y + if (0 == pad_len_bytes && conf_win_right > 0) + { + if (0 == i) // Y { - pad_len_bytes = dst_stride[i] - frame_width * bit_depth_factor; - } else + pad_len_bytes = conf_win_right * factor; + } + else { // U/V share the same padding length - pad_len_bytes = dst_stride[i] - frame_width / 2 * bit_depth_factor; + pad_len_bytes = conf_win_right * factor / 2; } + } - if (0 == pad_len_bytes && conf_win_right > 0) - { - if (0 == i) // Y - { - pad_len_bytes = conf_win_right * bit_depth_factor; - } else - { - // U/V share the same padding length - pad_len_bytes = conf_win_right * bit_depth_factor / 2; - } - } + ni_log(NI_LOG_DEBUG, + "%s plane %d stride padding: %d pixel (%d bytes), copy height: " + "%d.\n", + __func__, i, pad_len_bytes / factor, pad_len_bytes, + height); - ni_log(NI_LOG_DEBUG, - "%s plane %d stride padding: %d pixel (%d bytes), copy height: " - "%d.\n", - __func__, i, pad_len_bytes / bit_depth_factor, pad_len_bytes, - height); + for (; height > 0; height--) + { + memcpy(dst, src, + (src_stride[i] < dst_stride[i] ? src_stride[i] : dst_stride[i])); + dst += dst_stride[i]; - for (; height > 0; height--) + // dst is now at the line end + if (pad_len_bytes) { - memcpy(dst, src, - (src_stride[i] < dst_stride[i] ? src_stride[i] : - dst_stride[i])); - dst += dst_stride[i]; - - // dst is now at the line end - if (pad_len_bytes) + // repeat last pixel + if (factor > 1) { - // repeat last pixel - if (2 == bit_depth_factor) - { - // for 10 bit it's 2 bytes - int j; - uint8_t *tmp_dst = dst - pad_len_bytes; - for (j = 0; j < pad_len_bytes / 2; j++) - { - memcpy(tmp_dst, dst - pad_len_bytes - 2, 2); - tmp_dst += 2; - } - } else + // for 10 bit it's 2 bytes + int j; + uint8_t *tmp_dst = dst - pad_len_bytes; + for (j = 0; j < pad_len_bytes / factor; j++) { - memset(dst - pad_len_bytes, *(dst - pad_len_bytes - 1), - pad_len_bytes); + memcpy(tmp_dst, dst - pad_len_bytes - factor, factor); + tmp_dst += factor; } } - src += src_stride[i]; + else + { + memset(dst - pad_len_bytes, *(dst - pad_len_bytes - 1), + pad_len_bytes); + } } + src += src_stride[i]; + } - // height padding/cropping if needed - int padding_height = dst_height[i] - src_height[i]; - if (padding_height > 0) + // height padding/cropping if needed + int padding_height = dst_height[i] - src_height[i]; + if (padding_height > 0) + { + ni_log(NI_LOG_DEBUG, "%s plane %d padding height: %d\n", __func__, + i, padding_height); + src = dst - dst_stride[i]; + for (; padding_height > 0; padding_height--) { - ni_log(NI_LOG_DEBUG, "%s plane %d padding height: %d\n", __func__, - i, padding_height); - src = dst - dst_stride[i]; - for (; padding_height > 0; padding_height--) - { - memcpy(dst, src, dst_stride[i]); - dst += dst_stride[i]; - } + memcpy(dst, src, dst_stride[i]); + dst += dst_stride[i]; } } } - -// NAL operations - /*!***************************************************************************** - * \brief Insert emulation prevention byte(s) as needed into the data buffer - * - * \param buf data buffer to be worked on - new byte(s) will be inserted - * size number of bytes starting from buf to check + * \brief Copy YUV data to Netint HW YUV420p frame layout to be sent + * to encoder for encoding. Data buffer (dst) is usually allocated by + * ni_encoder_frame_buffer_alloc. * - * \return the number of emulation prevention bytes inserted into buf, 0 if + * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied + * \param[in] p_src pointers of Y/Cb/Cr from which data is copied + * \param[in] width source YUV frame width + * \param[in] height source YUV frame height + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise + * \param[in] conf_win_right right offset of conformance window + * \param[in] dst_stride size (in bytes) of each plane width in destination + * \param[in] dst_height size of each plane height in destination + * \param[in] src_stride size (in bytes) of each plane width in source + * \param[in] src_height size of each plane height in source + * + * \return Y/Cb/Cr data + * + ******************************************************************************/ +void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], + int frame_width, int frame_height, int factor, + int is_semiplanar, int conf_win_right, + int dst_stride[NI_MAX_NUM_DATA_POINTERS], + int dst_height[NI_MAX_NUM_DATA_POINTERS], + int src_stride[NI_MAX_NUM_DATA_POINTERS], + int src_height[NI_MAX_NUM_DATA_POINTERS]) +{ + ni_log(NI_LOG_DEBUG, + "%s dst_stride %d/%d/%d src_stride %d/%d/%d dst_height " + "%d/%d/%d src_height %d/%d/%d\n", + __func__, dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0], + src_stride[1], src_stride[2], dst_height[0], dst_height[1], + dst_height[2], src_height[0], src_height[1], src_height[2]); + + int i; + + for (i = 0; i < NI_MAX_NUM_DATA_POINTERS - 1; i++) + { + ni_copy_plane_data(p_dst, p_src, frame_width, frame_height, factor, + is_semiplanar, conf_win_right, dst_stride, + dst_height, src_stride, src_height, i); + } +} + +/*!***************************************************************************** + * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent + * to encoder for encoding. Data buffer (dst) is usually allocated by + * ni_encoder_frame_buffer_alloc. + * + * \param[out] p_dst pointers to which data is copied + * \param[in] p_src pointers from which data is copied + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] pix_fmt pixel format to distinguish between planar types and/or components + * \param[in] conf_win_right right offset of conformance window + * \param[in] dst_stride size (in bytes) of each plane width in destination + * \param[in] dst_height size of each plane height in destination + * \param[in] src_stride size (in bytes) of each plane width in source + * \param[in] src_height size of each plane height in source + * + * \return copied data + * + ******************************************************************************/ +void ni_copy_frame_data(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], + int frame_width, int frame_height, + int factor, ni_pix_fmt_t pix_fmt, + int conf_win_right, + int dst_stride[NI_MAX_NUM_DATA_POINTERS], + int dst_height[NI_MAX_NUM_DATA_POINTERS], + int src_stride[NI_MAX_NUM_DATA_POINTERS], + int src_height[NI_MAX_NUM_DATA_POINTERS]) +{ + ni_log(NI_LOG_DEBUG, + "%s frame_width %d frame_height %d factor %d conf_win_right %d " + "dst_stride %d/%d/%d src_stride %d/%d/%d dst_height " + "%d/%d/%d src_height %d/%d/%d pix_fmt %d\n", + __func__, frame_width, frame_height, factor, conf_win_right, + dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0], + src_stride[1], src_stride[2], dst_height[0], dst_height[1], + dst_height[2], src_height[0], src_height[1], src_height[2], + pix_fmt); + + int is_rgba = 0; + int is_semiplanar = 0; + switch (pix_fmt) + { + case NI_PIX_FMT_NV12: + case NI_PIX_FMT_P010LE: + is_semiplanar = 1; + break; + case NI_PIX_FMT_ARGB: + case NI_PIX_FMT_ABGR: + case NI_PIX_FMT_RGBA: + case NI_PIX_FMT_BGRA: + is_rgba = 1; + break; + default: + break; + } + + if (is_rgba) + { + ni_copy_plane_data(p_dst, p_src, + frame_width, frame_height, 4, + is_semiplanar, conf_win_right, + dst_stride, dst_height, + src_stride, src_height, + 0); // just one plane for rgba + } + else + { + ni_copy_hw_yuv420p(p_dst, p_src, frame_width, frame_height, factor, + is_semiplanar, conf_win_right, dst_stride, + dst_height, src_stride, src_height); + } +} + +/*!***************************************************************************** + * \brief Copy yuv444p data to yuv420p frame layout to be sent + * to encoder for encoding. Data buffer (dst) is usually allocated by + * ni_encoder_frame_buffer_alloc. + * + * \param[out] p_dst0 pointers of Y/Cb/Cr as yuv420p output0 + * \param[out] p_dst1 pointers of Y/Cb/Cr as yuv420p output1 + * \param[in] p_src pointers of Y/Cb/Cr as yuv444p intput + * \param[in] width source YUV frame width + * \param[in] height source YUV frame height + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] mode 0 for + * out0 is Y+1/2V, with the original input as the out0, 1/4V + * copy to data[1] 1/4V copy to data[2] + * out1 is U+1/2V, U copy to data[0], 1/4V copy to data[1], 1/4V + * copy to data[2] + * mode 1 for + * out0 is Y+1/2u+1/2v, with the original input as the output0, + * 1/4U copy to data[1] 1/4V copy to data[2] + * out1 is (1/2U+1/2V)+1/4U+1/4V, 1/2U & 1/2V copy to data[0], + * 1/4U copy to data[1], 1/4V copy to data[2] + * + * \return Y/Cb/Cr data + * + ******************************************************************************/ +void ni_copy_yuv_444p_to_420p(uint8_t *p_dst0[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], + int frame_width, int frame_height, + int factor, int mode) +{ + int i, j; + int y_444p_linesize = frame_width * factor; + int uv_444p_linesize = y_444p_linesize; + int y_420p_linesize = NI_VPU_ALIGN128(y_444p_linesize); + int uv_420p_linesize = NI_VPU_ALIGN128(uv_444p_linesize / 2); + + // return to avoid self copy + if (p_dst0[0] == p_dst1[0] && p_dst0[1] == p_dst1[1] && + p_dst0[2] == p_dst1[2]) + { + ni_log(NI_LOG_DEBUG, "%s: src and dst identical, return\n", __func__); + return; + } + + // Y component + for (i = 0; i < frame_height; i++) + { + memcpy(&p_dst0[0][i * y_420p_linesize], &p_src[0][i * y_444p_linesize], + y_444p_linesize); + } + + if (mode == 0) + { + // out0 data[0]: Y data[1]: 0.25V data[2]: 0.25V + // out1 data[0]: U data[1]: 0.25V data[2]: 0.25V + // U component + for (i = 0; i < frame_height; i++) + { + memcpy(&p_dst1[0][i * y_420p_linesize], + &p_src[1][i * y_444p_linesize], y_444p_linesize); + } + + for (i = 0; i < frame_height / 2; i++) + { + for (j = 0; j < frame_width * factor / 2; j += factor) + { + // V component + // even line + memcpy(&p_dst0[1][i * uv_420p_linesize + j], + &p_src[2][2 * i * uv_444p_linesize + 2 * j], + factor); + memcpy(&p_dst0[2][i * uv_420p_linesize + j], + &p_src[2][2 * i * uv_444p_linesize + (2 * j + factor)], + factor); + // odd line + memcpy(&p_dst1[1][i * uv_420p_linesize + j], + &p_src[2][(2 * i + 1) * uv_444p_linesize + 2 * j], + factor); + memcpy(&p_dst1[2][i * uv_420p_linesize + j], + &p_src[2][(2 * i + 1) * uv_444p_linesize + (2 * j + factor)], + factor); + } + } + } else + { + // out0 data[0]: Y data[1]: 0.25U data[2]: 0.25V + // out1 data[0]: 0.5U + 0.5V data[1]: 0.25U data[2]: 0.25V + for (i = 0; i < frame_height / 2; i++) + { + for (j = 0; j < frame_width * factor / 2; j += factor) + { + // U component + // even line 0.25U + memcpy(&p_dst1[1][i * uv_420p_linesize + j], + &p_src[1][2 * i * uv_444p_linesize + (2 * j + factor)], + factor); + // odd line 0.5U + memcpy(&p_dst1[0][2 * i * uv_444p_linesize + 2 * j], + &p_src[1][(2 * i + 1) * uv_444p_linesize + 2 * j], + factor * 2); + // even line 0.25U + memcpy(&p_dst0[1][i * uv_420p_linesize + j], + &p_src[1][2 * i * uv_444p_linesize + 2 * j], + factor); + + // V component + // even line 0.25V + memcpy(&p_dst1[2][i * uv_420p_linesize + j], + &p_src[2][2 * i * uv_444p_linesize + (2 * j + factor)], + factor); + // odd line 0.5V + memcpy(&p_dst1[0][(2 * i + 1) * uv_444p_linesize + 2 * j], + &p_src[2][(2 * i + 1) * uv_444p_linesize + 2 * j], + factor * 2); + // even line 0.25V + memcpy(&p_dst0[2][i * uv_420p_linesize + j], + &p_src[2][2 * i * uv_444p_linesize + 2 * j], + factor); + } + } + } +} + +// NAL operations + +/*!***************************************************************************** + * \brief Insert emulation prevention byte(s) as needed into the data buffer + * + * \param buf data buffer to be worked on - new byte(s) will be inserted + * size number of bytes starting from buf to check + * + * \return the number of emulation prevention bytes inserted into buf, 0 if * none. * * Note: caller *MUST* ensure for newly inserted bytes, buf has enough free @@ -1999,7 +2623,7 @@ int ni_insert_emulation_prevent_bytes(uint8_t *buf, int size) * * Note: buf will be modified if emu prevent byte(s) found and removed. ******************************************************************************/ -LIB_API int ni_remove_emulation_prevent_bytes(uint8_t *buf, int size) +int ni_remove_emulation_prevent_bytes(uint8_t *buf, int size) { int remove_bytes = 0; uint8_t *buf_curr = buf; @@ -2343,9 +2967,11 @@ static unsigned short ni_ai_fp32_to_bfp16_rtne(float in) /* Convert a float point to bfloat16, with round-nearest-to-even as rounding method. */ - uint32_t fp32 = *((unsigned int *)((void *)&in)); unsigned short out; + uint32_t fp32; + memcpy(&fp32, &in, sizeof(uint32_t)); + uint32_t lsb = (fp32 >> 16) & 1; /* Least significant bit of resulting bfloat. */ uint32_t rounding_bias = 0x7fff + lsb; @@ -2473,26 +3099,8 @@ struct tensor_rsrc static int open_tensor_rsrc_file(struct tensor_rsrc *rsrc, void *data, uint32_t num) { - const char *file_name; - FILE *fp; - - file_name = (const char *)data; - fp = fopen(file_name, "r"); - if (!fp) - { - return -1; - } - - rsrc->private = (void *)fp; - - /* to make cppcheck happy */ - if (0) - { - fclose(fp); - rsrc->private = NULL; - } - - return 0; + rsrc->private = (void *)fopen((const char *)data, "r"); + return rsrc->private ? 0 : -1; } static int get_tensor_rsrc_from_file(struct tensor_rsrc *rsrc, float *value) @@ -2971,21 +3579,22 @@ void ni_copy_hw_descriptors(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], * * \return char pointer to libxcoder API version ******************************************************************************/ -LIB_API char* ni_get_libxcoder_api_ver(void) +char* ni_get_libxcoder_api_ver(void) { static char* libxcoder_api_ver = LIBXCODER_API_VERSION; return libxcoder_api_ver; } /*!***************************************************************************** - * \brief Get FW API version libxcoder is compatible with + * \brief Get FW API version libxcoder is compatible with. + * Deprecated in favour of `ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &char_buf[0]);` * * \return char pointer to FW API version libxcoder is compatible with ******************************************************************************/ -LIB_API char* ni_get_compat_fw_api_ver(void) +NI_DEPRECATED char* ni_get_compat_fw_api_ver(void) { - static char compat_fw_api_ver_str[4] = ""; - // init static array one byte at a time to avoid compiler error C2099 + static char compat_fw_api_ver_str[5] = ""; + // init static array one byte at a time to avoid msvc compiler error C2099 if (!compat_fw_api_ver_str[0]) { compat_fw_api_ver_str[0] = \ @@ -2993,17 +3602,94 @@ LIB_API char* ni_get_compat_fw_api_ver(void) compat_fw_api_ver_str[1] = '.'; compat_fw_api_ver_str[2] = \ NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX]; - compat_fw_api_ver_str[3] = 0; + if (ni_cmp_fw_api_ver(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], "6r") >= 0) + compat_fw_api_ver_str[3] = \ + NI_XCODER_REVISION[NI_XCODER_REVISION_API_MINOR_VER_IDX+1]; + else + compat_fw_api_ver_str[3] = 0; + compat_fw_api_ver_str[4] = 0; } return &compat_fw_api_ver_str[0]; } +/*!***************************************************************************** + * \brief Get formatted FW API version string from unformatted FW API version + * string + * + * \param[in] ver_str pointer to string containing FW API. Only up to 3 + * characters will be read + * \param[out] fmt_str pointer to string buffer of at least size 5 to output + * formated version string to + * + * \return none + ******************************************************************************/ +void ni_fmt_fw_api_ver_str(const char ver_str[], char fmt_str[]) +{ + if (!ver_str || !fmt_str) { + return; + } + + fmt_str[0] = ver_str[0]; + fmt_str[1] = '.'; + fmt_str[2] = ver_str[1]; + + if ((ver_str[0] < '6' || (ver_str[0] == '6' && ver_str[1] <= 'q')) || + (ver_str[2] == 0)) { + fmt_str[3] = 0; + } else { + fmt_str[3] = ver_str[2]; + } + fmt_str[4] = 0; +} + +/*!***************************************************************************** + * \brief Compare two 3 character strings containing a FW API version. Handle + * comparision when FW API version format length changed from 2 to 3. + * + * \param[in] ver1 pointer to string containing FW API. Only up to 3 + * characters will be read + * \param[in] ver2 pointer to string containing FW API. Only up to 3 + * characters will be read + * + * \return 0 if ver1 == ver2, 1 if ver1 > ver2, -1 if ver1 < ver2 + ******************************************************************************/ +int ni_cmp_fw_api_ver(const char ver1[], const char ver2[]) +{ + int index; + + index = 0; + + if (ver1[index] > ver2[index]) + return 1; + else if (ver1[index] < ver2[index]) + return -1; + + index++; + + if (ver1[index] > ver2[index]) + return 1; + else if (ver1[index] < ver2[index]) + return -1; + + if ((ver1[index - 1] < '6') || ((ver1[index - 1] == '6') && (ver1[index] <= 'q'))) + return 0; + + index++; + + if (ver1[index] > ver2[index]) + return 1; + else if (ver1[index] < ver2[index]) + return -1; + + return 0; +} + /*!***************************************************************************** * \brief Get libxcoder SW release version * * \return char pointer to libxcoder SW release version ******************************************************************************/ -LIB_API char* ni_get_libxcoder_release_ver(void) +char* ni_get_libxcoder_release_ver(void) { static char release_ver_str[6] = ""; // init static array one byte at a time to avoid compiler error C2099 @@ -3018,3 +3704,657 @@ LIB_API char* ni_get_libxcoder_release_ver(void) } return &release_ver_str[0]; } + +/*!***************************************************************************** + * \brief Get text string for the provided error + * + * \return char pointer for the provided error + ******************************************************************************/ +const char *ni_get_rc_txt(ni_retcode_t rc) +{ + int i; + for (i = 0; + i < sizeof(ni_err_rc_description) / sizeof(ni_err_rc_txt_entry_t); i++) + { + if (rc == ni_err_rc_description[i].rc) + { + return ni_err_rc_description[i].txt; + } + } + return "rc not supported"; +} + +/*!***************************************************************************** + * \brief retrieve key and value from 'key=value' pair + * + * \param[in] p_str pointer to string to extract pair from + * \param[out] key pointer to key + * \param[out] value pointer to value + * + * \return return 0 if successful, otherwise 1 + * + ******************************************************************************/ +int ni_param_get_key_value(char *p_str, char *key, char *value) +{ + if (!p_str || !key || !value) + { + return 1; + } + + char *p = strchr(p_str, '='); + if (!p) + { + return 1; + } else + { + *p = '\0'; + key[0] = '\0'; + value[0] = '\0'; + strcpy(key, p_str); + strcpy(value, p + 1); + return 0; + } +} + +/*!***************************************************************************** + * \brief retrieve encoder config parameter values from --xcoder-params + * + * \param[in] xcoderParams pointer to string containing xcoder params + * \param[out] params pointer to xcoder params to fill out + * \param[out] ctx pointer to session context + * + * \return return 0 if successful, -1 otherwise + * + ******************************************************************************/ +int ni_retrieve_xcoder_params(char xcoderParams[], + ni_xcoder_params_t *params, + ni_session_context_t *ctx) +{ + char key[64], value[64]; + char *curr = xcoderParams, *colon_pos; + int ret = 0; + + while (*curr) + { + colon_pos = strchr(curr, ':'); + + if (colon_pos) + { + *colon_pos = '\0'; + } + + if (strlen(curr) > sizeof(key) + sizeof(value) - 1 || + ni_param_get_key_value(curr, key, value)) + { + ni_log(NI_LOG_ERROR, + "Error: xcoder-params p_config key/value not " + "retrieved: %s\n", + curr); + ret = -1; + break; + } + ret = ni_encoder_params_set_value(params, key, value); + switch (ret) + { + case NI_RETCODE_PARAM_INVALID_NAME: + ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key); + break; + case NI_RETCODE_PARAM_INVALID_VALUE: + ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key, + value); + break; + default: + break; + } + + if (NI_RETCODE_SUCCESS != ret) + { + ni_log(NI_LOG_ERROR, "Error: config parsing failed %d: %s\n", ret, + ni_get_rc_txt(ret)); + break; + } + + if (colon_pos) + { + curr = colon_pos + 1; + } else + { + curr += strlen(curr); + } + } + ctx->keep_alive_timeout = params->cfg_enc_params.keep_alive_timeout; + // reuse decoder_low_delay for low delay encoding to store wait interval + // in send/recv multi-thread mode. + ctx->decoder_low_delay = params->low_delay_mode; + + return ret; +} + +/*!***************************************************************************** + * \brief Retrieve custom gop config values from --xcoder-gop + * + * \param[in] xcoderGop pointer to string containing xcoder gop + * \param[out] params pointer to xcoder params to fill out + * \param[out] ctx pointer to session context + * + * \return return 0 if successful, -1 otherwise + * + ******************************************************************************/ +int ni_retrieve_xcoder_gop(char xcoderGop[], + ni_xcoder_params_t *params, + ni_session_context_t *ctx) +{ + char key[64], value[64]; + char *curr = xcoderGop, *colon_pos; + int ret = 0; + + while (*curr) + { + colon_pos = strchr(curr, ':'); + + if (colon_pos) + { + *colon_pos = '\0'; + } + + if (strlen(curr) > sizeof(key) + sizeof(value) - 1 || + ni_param_get_key_value(curr, key, value)) + { + ni_log(NI_LOG_ERROR, + "Error: xcoder-params p_config key/value not " + "retrieved: %s\n", + curr); + ret = -1; + break; + } + ret = ni_encoder_gop_params_set_value(params, key, value); + switch (ret) + { + case NI_RETCODE_PARAM_INVALID_NAME: + ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key); + break; + case NI_RETCODE_PARAM_INVALID_VALUE: + ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key, + value); + break; + default: + break; + } + + if (NI_RETCODE_SUCCESS != ret) + { + ni_log(NI_LOG_ERROR, "Error: gop config parsing failed %d: %s\n", ret, + ni_get_rc_txt(ret)); + break; + } + + if (colon_pos) + { + curr = colon_pos + 1; + } else + { + curr += strlen(curr); + } + } + + return ret; +} + +/*!***************************************************************************** + * \brief retrieve decoder config parameter values from --decoder-params + * + * \param[in] xcoderParams pointer to string containing xcoder params + * \param[out] params pointer to xcoder params to fill out + * \param[out] ctx pointer to session context + * + * \return return 0 if successful, -1 otherwise + * + ******************************************************************************/ +int ni_retrieve_decoder_params(char xcoderParams[], + ni_xcoder_params_t *params, + ni_session_context_t *ctx) +{ + char key[64], value[64]; + char *curr = xcoderParams, *colon_pos; + int ret = 0; + + while (*curr) + { + colon_pos = strchr(curr, ':'); + + if (colon_pos) + { + *colon_pos = '\0'; + } + + if (strlen(curr) > sizeof(key) + sizeof(value) - 1 || + ni_param_get_key_value(curr, key, value)) + { + ni_log(NI_LOG_ERROR, + "Error: decoder-params p_config key/value not " + "retrieved: %s\n", + curr); + ret = -1; + break; + } + ret = ni_decoder_params_set_value(params, key, value); + switch (ret) + { + case NI_RETCODE_PARAM_INVALID_NAME: + ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key); + break; + case NI_RETCODE_PARAM_INVALID_VALUE: + ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key, + value); + break; + default: + break; + } + + if (NI_RETCODE_SUCCESS != ret) + { + ni_log(NI_LOG_ERROR, "Error: config parsing failed %d: %s\n", ret, + ni_get_rc_txt(ret)); + break; + } + + if (colon_pos) + { + curr = colon_pos + 1; + } else + { + curr += strlen(curr); + } + } + ctx->keep_alive_timeout = params->dec_input_params.keep_alive_timeout; + ctx->decoder_low_delay = params->dec_input_params.decoder_low_delay; + + return ret; +} + +/*!***************************************************************************** + * \brief initialize a mutex + * + * \param[in] thread mutex + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex) +{ +#ifdef _WIN32 + bool rc = false; + // error return zero + rc = InitializeCriticalSectionEx(mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO); + if (rc) + { + return 0; + } + else + { + return -1; + } +#else + int rc; + ni_pthread_mutexattr_t attr; + + rc = pthread_mutexattr_init(&attr); + if (rc != 0) + { + return -1; + } + + /* For some cases to prevent the lock owner locking twice (i.e. internal + * API calls or if user application decides to lock the xcoder_mutex outside + * of API), The recursive mutex is a nice thing to solve the problem. + */ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + return pthread_mutex_init(mutex, &attr); +#endif +} + +/*!***************************************************************************** + * \brief destory a mutex + * + * \param[in] thread mutex + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex) +{ +#ifdef _WIN32 + DeleteCriticalSection(mutex); + return 0; +#else + return pthread_mutex_destroy(mutex); +#endif +} + +/*!***************************************************************************** + * \brief thread mutex lock + * + * \param[in] thread mutex + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex) +{ + int rc = 0; + if (mutex != NULL) + { +#ifdef _WIN32 + EnterCriticalSection(mutex); +#else + rc = pthread_mutex_lock(mutex); +#endif + } else + { + rc = -1; + } + + return rc; +} + +/*!***************************************************************************** + * \brief thread mutex unlock + * + * \param[in] thread mutex + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex) +{ + int rc = 0; + if (mutex != NULL) + { +#ifdef _WIN32 + LeaveCriticalSection(mutex); +#else + rc = pthread_mutex_unlock(mutex); +#endif + } else + { + rc = -1; + } + + return rc; +} + +#ifdef _WIN32 +static unsigned __stdcall __thread_worker(void *arg) +{ + ni_pthread_t *t = (ni_pthread_t *)arg; + t->rc = t->start_routine(t->arg); + return 0; +} +#endif + +/*!***************************************************************************** + * \brief create a new thread + * + * \param[in] thread thread id + * \param[in] attr attributes to the new thread + * \param[in] start_routine entry of the thread routine + * \param[in] arg sole argument of the routine + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_create(ni_pthread_t *thread, const ni_pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ +#ifdef _WIN32 + thread->start_routine = start_routine; + thread->arg = arg; + thread->handle = +#if HAVE_WINRT + (void *)CreateThread(NULL, 0, win32thread_worker, thread, 0, NULL); +#else + (void *)_beginthreadex(NULL, 0, __thread_worker, thread, 0, NULL); +#endif + return !thread->handle; +#else + return pthread_create(thread, attr, start_routine, arg); +#endif +} + +/*!***************************************************************************** + * \brief join with a terminated thread + * + * \param[in] thread thread id + * \param[out] value_ptr return status + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_join(ni_pthread_t thread, void **value_ptr) +{ +#ifdef _WIN32 + DWORD rc = WaitForSingleObject(thread.handle, INFINITE); + if (rc != WAIT_OBJECT_0) + { + if (rc == WAIT_ABANDONED) + return EINVAL; + else + return EDEADLK; + } + if (value_ptr) + *value_ptr = thread.rc; + CloseHandle(thread.handle); + return 0; +#else + return pthread_join(thread, value_ptr); +#endif +} + +/*!***************************************************************************** + * \brief initialize condition variables + * + * \param[in] cond condition variable + * \param[in] attr attribute to the condvar + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_cond_init(ni_pthread_cond_t *cond, + const ni_pthread_condattr_t *attr) +{ +#ifdef _WIN32 + InitializeConditionVariable(cond); + return 0; +#else + return pthread_cond_init(cond, attr); +#endif +} + +/*!***************************************************************************** + * \brief destroy condition variables + * + * \param[in] cond condition variable + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_cond_destroy(ni_pthread_cond_t *cond) +{ +#ifdef _WIN32 + /* native condition variables do not destroy */ + return 0; +#else + return pthread_cond_destroy(cond); +#endif +} + +/*!***************************************************************************** + * \brief broadcast a condition + * + * \param[in] cond condition variable + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond) +{ +#ifdef _WIN32 + WakeAllConditionVariable(cond); + return 0; +#else + return pthread_cond_broadcast(cond); +#endif +} + +/*!***************************************************************************** + * \brief wait on a condition + * + * \param[in] cond condition variable + * \param[in] mutex mutex related to the condvar + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_cond_wait(ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex) +{ +#ifdef _WIN32 + SleepConditionVariableCS(cond, mutex, INFINITE); + return 0; +#else + return pthread_cond_wait(cond, mutex); +#endif +} + +/*!****************************************************************************** + * \brief signal a condition + * + * \param[in] cond condition variable + * + * \return On success returns 0 + * On failure returns <0 + *******************************************************************************/ +int ni_pthread_cond_signal(ni_pthread_cond_t *cond) +{ +#ifdef _WIN32 + WakeConditionVariable(cond); + return 0; +#else + return pthread_cond_signal(cond); +#endif +} + +/*!***************************************************************************** + * \brief wait on a condition + * + * \param[in] cond condition variable + * \param[in] mutex mutex related to the condvar + * \param[in[ abstime abstract value of timeout + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_cond_timedwait(ni_pthread_cond_t *cond, + ni_pthread_mutex_t *mutex, + const struct timespec *abstime) +{ +#ifdef _WIN32 + int64_t abs_ns = abstime->tv_sec * 1000000000LL + abstime->tv_nsec; + DWORD t = (uint32_t)((abs_ns - ni_gettime_ns()) / 1000000); + + if (!SleepConditionVariableCS(cond, mutex, t)) + { + DWORD err = GetLastError(); + if (err == ERROR_TIMEOUT) + return ETIMEDOUT; + else + return EINVAL; + } + return 0; +#else + return pthread_cond_timedwait(cond, mutex, abstime); +#endif +} + +/*!***************************************************************************** + * \brief examine and change mask of blocked signals + * + * \param[in] how behavior of this call, can be value of SIG_BLOCK, + * SIG_UNBLOCK and SIG_SETMASK + * \param[in] set current value of the signal mask. If NULL, the mask keeps + * unchanged. + * \param[in] old_set previous value of the signal mask, can be NULL. + * + * \return On success returns 0 + * On failure returns <0 + ******************************************************************************/ +int ni_pthread_sigmask(int how, const ni_sigset_t *set, ni_sigset_t *oldset) +{ +#ifdef _WIN32 + return 0; +#else + return pthread_sigmask(how, set, oldset); +#endif +} + +/*!***************************************************************************** + * \brief return error string according to error code from firmware + * + * \param[in] rc error code return from firmware + * + * \return error string + ******************************************************************************/ +const char *ni_ai_errno_to_str(int rc) +{ + switch (rc) + { + case NI_AI_STATUS_SUCCESS: + return "Success"; + case NI_AI_STATUS_GENERIC_ERROR: + return "General Error"; + case NI_AI_STATUS_NOT_INITIALIZED: + return "Not Initialized"; + case NI_AI_STATUS_ALREADY_INITIALIZED: + return "Already Initialized"; + case NI_AI_STATUS_IO_BUSY: + return "IO Busy"; + case NI_AI_STATUS_RESOURCE_NOT_AVAILABLE: + return "Resource Not Available"; + case NI_AI_STATUS_CREATE_NETWORK_FAILED: + return "Create Network Failed"; + case NI_AI_STATUS_INPUT_BUFFER_FULL: + return "Input Buffer Full"; + case NI_AI_STATUS_OUTPUT_BUFFER_EMPTY: + return "Output Buffer Empty"; + case NI_AI_STATUS_INVALID_PARAMS: + return "Invalid Params"; + case NI_AI_STATUS_ERROR_START_NETWORK: + return "Error Start Network"; + case NI_AI_STATUS_ERROR_SET_INOUT: + return "Erorr Set Inout"; + case NI_AI_STATUS_BAD_OPTION: + return "Bad Option"; + case NI_AI_STATUS_MAP_ERROR: + return "Map Error"; + case NI_AI_STATUS_CONTEXT_NOT_AVAILABLE: + return "Context Not Available"; + case NI_AI_STATUS_MODEL_NOT_FOUND: + return "Model Not Found"; + case NI_AI_STATUS_IO_ERROR: + return "IO Error"; + case NI_AI_STATUS_INVALID_ADDRESS: + return "Invalid Address"; + case NI_AI_STATUS_OUT_OF_MEMORY: + return "Out Of Memory"; + case NI_AI_STATUS_BAD_INOUT: + return "Bad Inout"; + case NI_AI_STATUS_INVALID_INSTANCE: + return "Invalid Instance"; + case NI_AI_STATUS_IO_NOT_ALLOWED: + return "IO Not Allowed"; + case NI_AI_STATUS_NETWORK_NOT_READY: + return "Network Not Ready"; + default: + return "Other Error"; + } +} diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.h b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.h index 549b36f2..4213e403 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.h +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/ni_util.h @@ -20,18 +20,16 @@ ******************************************************************************/ /*!***************************************************************************** -* \file ni_util.h -* -* \brief Exported utility routines definition -* -*******************************************************************************/ + * \file ni_util.h + * + * \brief Utility definitions + ******************************************************************************/ #pragma once #ifdef _WIN32 -#define _SC_PAGESIZE 0 -#define sysconf(x) 0 -#else +#define _SC_PAGESIZE 4096 +#define sysconf(x) x #endif #include "ni_device_api.h" @@ -73,6 +71,7 @@ static inline float clip3f(float min, float max, float a) return ni_minf(ni_maxf(min, a), max); } +#define NIALIGN(x, a) (((x) + (a)-1) & ~((a)-1)) // Compile time assert macro #define COMPILE_ASSERT(condition) ((void)sizeof(char[1 - 2 * !(condition)])) @@ -108,6 +107,7 @@ void ni_dec_fme_buffer_pool_free(ni_buf_pool_t *p_buffer_pool); void ni_buffer_pool_free(ni_queue_buffer_pool_t *p_buffer_pool); ni_retcode_t ni_find_blk_name(const char *p_dev, char *p_out_buf, int out_buf_len); +ni_retcode_t ni_check_dev_name(const char *p_dev); ni_retcode_t ni_timestamp_init(ni_session_context_t* p_ctx, ni_timestamp_table_t **pp_table, const char *name); ni_retcode_t ni_timestamp_done(ni_timestamp_table_t *p_table, ni_queue_buffer_pool_t *p_buffer_pool); ni_retcode_t ni_timestamp_register(ni_queue_buffer_pool_t *p_buffer_pool, ni_timestamp_table_t *p_table, int64_t timestamp, uint64_t data_info); @@ -143,7 +143,7 @@ int32_t ni_parse_name(const char *arg, const char *const *names, bool *b_error); * \param[in] width source YUV frame width * \param[in] height source YUV frame height * \param[in] bit_depth_factor 1 for 8 bit, 2 for 10 bit - * \param[in] is_nv12 non-0 for NV12 frame, 0 otherwise + * \param[in] is_semiplanar non-0 for semiplnar frame, 0 otherwise * \param[out] plane_stride size (in bytes) of each plane width * \param[out] plane_height size of each plane height * @@ -151,10 +151,54 @@ int32_t ni_parse_name(const char *arg, const char *const *names, bool *b_error); * ******************************************************************************/ LIB_API void ni_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, - int is_nv12, + int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS]); +/*!***************************************************************************** + * \brief Get dimension information of frame to be sent + * to encoder for encoding. Caller usually retrieves this info and + * uses it in the call to ni_encoder_frame_buffer_alloc for buffer + * allocation. + * The returned stride and height info will take alignment + * requirements into account. + * + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] pix_fmt ni pixel format + * \param[out] plane_stride size (in bytes) of each plane width + * \param[out] plane_height size of each plane height + * + * \return stride and height info + * + ******************************************************************************/ +LIB_API void ni_get_frame_dim(int width, int height, + ni_pix_fmt_t pix_fmt, + int plane_stride[NI_MAX_NUM_DATA_POINTERS], + int plane_height[NI_MAX_NUM_DATA_POINTERS]); + +/*!***************************************************************************** + * \brief Get dimension information of frame to be sent + * to encoder for encoding. Caller usually retrieves this info and + * uses it in the call to ni_encoder_frame_buffer_alloc for buffer + * allocation. + * The returned stride and height info will take into account both min + * resolution and alignment requirements. + * + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] pix_fmt ni pixel format + * \param[out] plane_stride size (in bytes) of each plane width + * \param[out] plane_height size of each plane height + * + * \return stride and height info + * + ******************************************************************************/ +LIB_API void ni_get_min_frame_dim(int width, int height, + ni_pix_fmt_t pix_fmt, + int plane_stride[NI_MAX_NUM_DATA_POINTERS], + int plane_height[NI_MAX_NUM_DATA_POINTERS]); + /*!***************************************************************************** * \brief Copy YUV data to Netint HW YUV420p frame layout to be sent * to encoder for encoding. Data buffer (dst) is usually allocated by @@ -165,7 +209,7 @@ LIB_API void ni_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, * \param[in] width source YUV frame width * \param[in] height source YUV frame height * \param[in] bit_depth_factor 1 for 8 bit, 2 for 10 bit - * \param[in] is_nv12 non-0 for NV12 frame, 0 otherwise + * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise * \param[in] conf_win_right right offset of conformance window * \param[in] dst_stride size (in bytes) of each plane width in destination * \param[in] dst_height size of each plane height in destination @@ -178,12 +222,73 @@ LIB_API void ni_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, LIB_API void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int width, int height, int bit_depth_factor, - int is_nv12, int conf_win_right, + int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS]); +/*!***************************************************************************** + * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent + * to encoder for encoding. Data buffer (dst) is usually allocated by + * ni_encoder_frame_buffer_alloc. + * + * \param[out] p_dst pointers to which data is copied + * \param[in] p_src pointers from which data is copied + * \param[in] width source frame width + * \param[in] height source frame height + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] pix_fmt pixel format to distinguish between planar types and/or components + * \param[in] conf_win_right right offset of conformance window + * \param[in] dst_stride size (in bytes) of each plane width in destination + * \param[in] dst_height size of each plane height in destination + * \param[in] src_stride size (in bytes) of each plane width in source + * \param[in] src_height size of each plane height in source + * + * \return copied data + * + ******************************************************************************/ +LIB_API void ni_copy_frame_data(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], + int frame_width, int frame_height, + int factor, ni_pix_fmt_t pix_fmt, + int conf_win_right, + int dst_stride[NI_MAX_NUM_DATA_POINTERS], + int dst_height[NI_MAX_NUM_DATA_POINTERS], + int src_stride[NI_MAX_NUM_DATA_POINTERS], + int src_height[NI_MAX_NUM_DATA_POINTERS]); + +/*!***************************************************************************** + * \brief Copy yuv444p data to yuv420p frame layout to be sent + * to encoder for encoding. Data buffer (dst) is usually allocated by + * ni_encoder_frame_buffer_alloc. + * + * \param[out] p_dst0 pointers of Y/Cb/Cr as yuv420p output0 + * \param[out] p_dst1 pointers of Y/Cb/Cr as yuv420p output1 + * \param[in] p_src pointers of Y/Cb/Cr as yuv444p intput + * \param[in] width source YUV frame width + * \param[in] height source YUV frame height + * \param[in] factor 1 for 8 bit, 2 for 10 bit + * \param[in] mode 0 for + * out0 is Y+1/2V, with the original input as the out0, 1/4V + * copy to data[1] 1/4V copy to data[2] + * out1 is U+1/2V, U copy to data[0], 1/4V copy to data[1], 1/4V + * copy to data[2] + * mode 1 for + * out0 is Y+1/2u+1/2v, with the original input as the output0, + * 1/4U copy to data[1] 1/4V copy to data[2] + * out1 is (1/2U+1/2V)+1/4U+1/4V, 1/2U & 1/2V copy to data[0], + * 1/4U copy to data[1], 1/4V copy to data[2] + * + * \return Y/Cb/Cr data + * + ******************************************************************************/ +LIB_API void ni_copy_yuv_444p_to_420p(uint8_t *p_dst0[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS], + uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], + int width, int height, int factor, + int mode); + // NAL operations /*!***************************************************************************** @@ -224,10 +329,40 @@ LIB_API int ni_remove_emulation_prevent_bytes(uint8_t *buf, int size); ******************************************************************************/ LIB_API int32_t ni_gettimeofday(struct timeval *p_tp, void *p_tzp); -int32_t ni_posix_memalign(void **pp_memptr, size_t alignment, size_t size); +/*!***************************************************************************** + * \brief Allocate aligned memory + * + * \param[in/out] memptr The address of the allocated memory will be a + * multiple of alignment, which must be a power of two + * and a multiple of sizeof(void *). If size is 0, then + * the value placed is either NULL, or a unique pointer + * value that can later be successfully passed to free. + * \param[in] alignment The alignment value of the allocated value. + * \param[in] size The allocated memory size. + * + * \return 0 for success, ENOMEM for error + ******************************************************************************/ +LIB_API int ni_posix_memalign(void **memptr, size_t alignment, size_t size); + uint32_t ni_round_up(uint32_t number_to_round, uint32_t multiple); +#ifdef _WIN32 #define ni_aligned_free(p_memptr) \ +{ \ + _aligned_free(p_memptr); \ + p_memptr = NULL; \ +} +#else +#define ni_aligned_free(p_memptr) \ +{ \ + free(p_memptr); \ + p_memptr = NULL; \ +} +#endif + +// This method is used in device session close function to unset all the +// pointers in the session context. +#define ni_memfree(p_memptr) \ { \ free(p_memptr); \ p_memptr = NULL; \ @@ -239,6 +374,7 @@ uint32_t ni_get_kernel_max_io_size(const char * p_dev); LIB_API uint64_t ni_gettime_ns(void); LIB_API void ni_usleep(int64_t usec); +LIB_API char *ni_strtok(char *s, const char *delim, char **saveptr); LIB_API ni_retcode_t ni_network_layer_convert_output(float *dst, uint32_t num, ni_packet_t *p_packet, ni_network_data_t *p_network, uint32_t layer); @@ -283,7 +419,33 @@ LIB_API char* ni_get_libxcoder_api_ver(void); * * \return char pointer to FW API version libxcoder is compatible with ******************************************************************************/ -LIB_API char* ni_get_compat_fw_api_ver(void); +LIB_API NI_DEPRECATED char* ni_get_compat_fw_api_ver(void); + +/*!***************************************************************************** + * \brief Get formatted FW API version string from unformatted FW API version + * string + * + * \param[in] ver_str pointer to string containing FW API. Only up to 3 + * characters will be read + * \param[out] fmt_str pointer to string buffer of at least size 5 to output + * formated version string to + * + * \return none + ******************************************************************************/ +LIB_API void ni_fmt_fw_api_ver_str(const char ver_str[], char fmt_str[]); + +/*!***************************************************************************** + * \brief Compare two 3 character strings containing a FW API version. Handle + * comparision when FW API version format length changed from 2 to 3. + * + * \param[in] ver1 pointer to string containing FW API. Only up to 3 + * characters will be read + * \param[in] ver2 pointer to string containing FW API. Only up to 3 + * characters will be read + * + * \return 0 if ver1 == ver2, 1 if ver1 > ver2, -1 if ver1 < ver2 + ******************************************************************************/ +LIB_API int ni_cmp_fw_api_ver(const char ver1[], const char ver2[]); /*!***************************************************************************** * \brief Get libxcoder SW release version @@ -292,369 +454,224 @@ LIB_API char* ni_get_compat_fw_api_ver(void); ******************************************************************************/ LIB_API char* ni_get_libxcoder_release_ver(void); -/*!****************************************************************************** +/*!***************************************************************************** * \brief initialize a mutex * - * \param + * \param[in] thread mutex * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex) -{ -#ifdef _WIN32 - InitializeCriticalSection(mutex); - return 0; -#else - int rc; - ni_pthread_mutexattr_t attr; - - rc = pthread_mutexattr_init(&attr); - if (rc != 0) - { - return -1; - } - - /* For some cases to prevent the lock owner locking twice (i.e. internal - * API calls or if user application decides to lock the xcoder_mutex outside - * of API), The recursive mutex is a nice thing to solve the problem. - */ - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - - return pthread_mutex_init(mutex, &attr); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex); -/*!****************************************************************************** +/*!***************************************************************************** * \brief destory a mutex * - * \param + * \param[in] thread mutex * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex) -{ -#ifdef _WIN32 - DeleteCriticalSection(mutex); - return 0; -#else - return pthread_mutex_destroy(mutex); -#endif -} - -/*!****************************************************************************** - * \brief thread mutex alloc&init - * - * \param - * - * \return On success returns true - * On failure returns false - *******************************************************************************/ -static bool ni_pthread_mutex_alloc_and_init(ni_pthread_mutex_t **mutex) -{ - int rc = 0; - *mutex = (ni_pthread_mutex_t *)calloc(1, sizeof(ni_pthread_mutex_t)); - if (!(*mutex)) - { - return false; - } - - rc = ni_pthread_mutex_init(*mutex); - if (rc != 0) - { - free(*mutex); - return false; - } - - return true; -} - -/*!****************************************************************************** - * \brief thread mutex free&destroy - * - * \param - * - * \return On success returns true - * On failure returns false - *******************************************************************************/ -static bool ni_pthread_mutex_free_and_destroy(ni_pthread_mutex_t **mutex) -{ - int rc = 0; - void *p; - static void *const tmp = NULL; - - // Avoid static analyzer inspection - memcpy(&p, mutex, sizeof(p)); - if (p != NULL) - { - rc = ni_pthread_mutex_destroy((ni_pthread_mutex_t *)p); - memcpy(mutex, &tmp, sizeof(p)); - free(p); - } else - { - rc = -1; - } - - return rc == 0; -} + ******************************************************************************/ +LIB_API int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex); -/*!****************************************************************************** +/*!***************************************************************************** * \brief thread mutex lock * - * \param + * \param[in] thread mutex * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex) -{ - int rc = 0; - if (mutex != NULL) - { -#ifdef _WIN32 - EnterCriticalSection(mutex); -#else - rc = pthread_mutex_lock(mutex); -#endif - } else - { - rc = -1; - } - - return rc; -} + ******************************************************************************/ +LIB_API int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex); -/*!****************************************************************************** +/*!***************************************************************************** * \brief thread mutex unlock * - * \param + * \param[in] thread mutex * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex) -{ - int rc = 0; - if (mutex != NULL) - { -#ifdef _WIN32 - LeaveCriticalSection(mutex); -#else - rc = pthread_mutex_unlock(mutex); -#endif - } else - { - rc = -1; - } - - return rc; -} - -#ifdef _WIN32 -static unsigned __stdcall __thread_worker(void *arg) -{ - ni_pthread_t *t = (ni_pthread_t *)arg; - t->rc = t->start_routine(t->arg); - return 0; -} -#endif + ******************************************************************************/ +LIB_API int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex); -/*!****************************************************************************** +/*!***************************************************************************** * \brief create a new thread * - * \param + * \param[in] thread thread id + * \param[in] attr attributes to the new thread + * \param[in] start_routine entry of the thread routine + * \param[in] arg sole argument of the routine * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static int ni_pthread_create(ni_pthread_t *thread, - const ni_pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg) -{ -#ifdef _WIN32 - thread->start_routine = start_routine; - thread->arg = arg; - thread->handle = -#if HAVE_WINRT - (void *)CreateThread(NULL, 0, win32thread_worker, thread, 0, NULL); -#else - (void *)_beginthreadex(NULL, 0, __thread_worker, thread, 0, NULL); -#endif - return !thread->handle; -#else - return pthread_create(thread, attr, start_routine, arg); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_create(ni_pthread_t *thread, + const ni_pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg); -/*!****************************************************************************** +/*!***************************************************************************** * \brief join with a terminated thread * - * \param + * \param[in] thread thread id + * \param[out] value_ptr return status * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static int ni_pthread_join(ni_pthread_t thread, void **value_ptr) -{ -#ifdef _WIN32 - DWORD rc = WaitForSingleObject(thread.handle, INFINITE); - if (rc != WAIT_OBJECT_0) - { - if (rc == WAIT_ABANDONED) - return EINVAL; - else - return EDEADLK; - } - if (value_ptr) - *value_ptr = thread.rc; - CloseHandle(thread.handle); - return 0; -#else - return pthread_join(thread, value_ptr); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_join(ni_pthread_t thread, void **value_ptr); -/*!****************************************************************************** +/*!***************************************************************************** * \brief initialize condition variables * - * \param + * \param[in] cond condition variable + * \param[in] attr attribute to the condvar * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_cond_init(ni_pthread_cond_t *cond, - const ni_pthread_condattr_t *unused_attr) -{ -#ifdef _WIN32 - InitializeConditionVariable(cond); - return 0; -#else - return pthread_cond_init(cond, unused_attr); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_cond_init(ni_pthread_cond_t *cond, + const ni_pthread_condattr_t *attr); -/*!****************************************************************************** +/*!***************************************************************************** * \brief destroy condition variables * - * \param + * \param[in] cond condition variable * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_cond_destroy(ni_pthread_cond_t *cond) -{ -#ifdef _WIN32 - /* native condition variables do not destroy */ - return 0; -#else - return pthread_cond_destroy(cond); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_cond_destroy(ni_pthread_cond_t *cond); -/*!****************************************************************************** +/*!***************************************************************************** * \brief broadcast a condition * - * \param + * \param[in] cond condition variable * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond) -{ -#ifdef _WIN32 - WakeAllConditionVariable(cond); - return 0; -#else - return pthread_cond_broadcast(cond); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond); -/*!****************************************************************************** +/*!***************************************************************************** * \brief wait on a condition * - * \param + * \param[in] cond condition variable + * \param[in] mutex mutex related to the condvar * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_cond_wait(ni_pthread_cond_t *cond, - ni_pthread_mutex_t *mutex) -{ -#ifdef _WIN32 - SleepConditionVariableCS(cond, mutex, INFINITE); - return 0; -#else - return pthread_cond_wait(cond, mutex); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_cond_wait(ni_pthread_cond_t *cond, + ni_pthread_mutex_t *mutex); /*!****************************************************************************** * \brief signal a condition * - * \param + * \param[in] cond condition variable * * \return On success returns 0 * On failure returns <0 *******************************************************************************/ -static inline int ni_pthread_cond_signal(ni_pthread_cond_t *cond) -{ -#ifdef _WIN32 - WakeConditionVariable(cond); - return 0; -#else - return pthread_cond_signal(cond); -#endif -} +LIB_API int ni_pthread_cond_signal(ni_pthread_cond_t *cond); -/*!****************************************************************************** +/*!***************************************************************************** * \brief wait on a condition * - * \param + * \param[in] cond condition variable + * \param[in] mutex mutex related to the condvar + * \param[in[ abstime abstract value of timeout * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static int ni_pthread_cond_timedwait(ni_pthread_cond_t *cond, - ni_pthread_mutex_t *mutex, - const struct timespec *abstime) -{ -#ifdef _WIN32 - int64_t abs_ns = abstime->tv_sec * 1000000000LL + abstime->tv_nsec; - DWORD t = (uint32_t)((abs_ns - ni_gettime_ns()) / 1000000); - - if (!SleepConditionVariableCS(cond, mutex, t)) - { - DWORD err = GetLastError(); - if (err == ERROR_TIMEOUT) - return ETIMEDOUT; - else - return EINVAL; - } - return 0; -#else - return pthread_cond_timedwait(cond, mutex, abstime); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_cond_timedwait(ni_pthread_cond_t *cond, + ni_pthread_mutex_t *mutex, + const struct timespec *abstime); -/*!****************************************************************************** +/*!***************************************************************************** * \brief examine and change mask of blocked signals * - * \param + * \param[in] how behavior of this call, can be value of SIG_BLOCK, + * SIG_UNBLOCK and SIG_SETMASK + * \param[in] set current value of the signal mask. If NULL, the mask keeps + * unchanged. + * \param[in] old_set previous value of the signal mask, can be NULL. * * \return On success returns 0 * On failure returns <0 - *******************************************************************************/ -static inline int ni_pthread_sigmask(int how, const ni_sigset_t *set, - ni_sigset_t *oldset) -{ -#ifdef _WIN32 - return 0; -#else - return pthread_sigmask(how, set, oldset); -#endif -} + ******************************************************************************/ +LIB_API int ni_pthread_sigmask(int how, const ni_sigset_t *set, + ni_sigset_t *oldset); + +/*!***************************************************************************** + * \brief Get text string for the provided error + * + * \return char pointer for the provided error + ******************************************************************************/ +LIB_API const char *ni_get_rc_txt(ni_retcode_t rc); + +/*!***************************************************************************** + * \brief Retrieve key and value from 'key=value' pair + * + * \param[in] p_str pointer to string to extract pair from + * \param[out] key pointer to key + * \param[out] value pointer to value + * + * \return return 0 if successful, otherwise 1 + * + ******************************************************************************/ +LIB_API int ni_param_get_key_value(char *p_str, char *key, char *value); + +/*!***************************************************************************** + * \brief Retrieve encoder config parameter values from --xcoder-params + * + * \param[in] xcoderParams pointer to string containing xcoder params + * \param[out] params pointer to xcoder params to fill out + * \param[out] ctx pointer to session context + * + * \return return 0 if successful, -1 otherwise + * + ******************************************************************************/ +LIB_API int ni_retrieve_xcoder_params(char xcoderParams[], + ni_xcoder_params_t *params, + ni_session_context_t *ctx); +/*!***************************************************************************** + * \brief Retrieve custom gop config values from --xcoder-gop + * + * \param[in] xcoderGop pointer to string containing xcoder gop + * \param[out] params pointer to xcoder params to fill out + * \param[out] ctx pointer to session context + * + * \return return 0 if successful, -1 otherwise + * + ******************************************************************************/ +LIB_API int ni_retrieve_xcoder_gop(char xcoderGop[], + ni_xcoder_params_t *params, + ni_session_context_t *ctx); + +/*!***************************************************************************** + * \brief Retrieve decoder config parameter values from --decoder-params + * + * \param[in] xcoderParams pointer to string containing xcoder params + * \param[out] params pointer to xcoder params to fill out + * \param[out] ctx pointer to session context + * + * \return return 0 if successful, -1 otherwise + * + ******************************************************************************/ +LIB_API int ni_retrieve_decoder_params(char xcoderParams[], + ni_xcoder_params_t *params, + ni_session_context_t *ctx); + +/*!***************************************************************************** + * \brief return error string according to error code from firmware + * + * \param[in] rc error code return from firmware + * + * \return error string + ******************************************************************************/ +LIB_API const char *ni_ai_errno_to_str(int rc); #ifdef __cplusplus } #endif diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test/client.cpp b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test/client.cpp index 09c247b5..bb42e32a 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test/client.cpp +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test/client.cpp @@ -20,11 +20,11 @@ ******************************************************************************/ /*!***************************************************************************** -* \file client.cpp -* -* \brief client test for NI Quadra android service -* -*******************************************************************************/ + * \file client.cpp + * + * \brief client test for NETINT video processing Android service + * + ******************************************************************************/ #include #include @@ -39,7 +39,6 @@ using android::sp; using android::hardware::hidl_handle; -using android::hardware::hidl_string; using android::hardware::nidec::V1_0::INidec; #define UNUSED(x) (void)(x) @@ -65,7 +64,7 @@ int main() return -1; } - service->GetAppFlag(param, [&](int32_t ret, hidl_handle handle) { + service->GetAppFlag(param, [&](int32_t ret, const hidl_handle &handle) { printf("GetAppFlag: ret %d\n", ret); if (ret > 0) { diff --git a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test_rsrc_api.c b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test_rsrc_api.c index 0a0d5db6..387c69ca 100644 --- a/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test_rsrc_api.c +++ b/xcoder/xcoder-quadra/xcoder-quadra-sys/vendor/libxcoder/source/test_rsrc_api.c @@ -19,23 +19,20 @@ * ******************************************************************************/ -/******************************************************************************* - * - * @file test_rsrc_api.p_device_info - * - * @date April 1, 2018 - * - * @brief - * - * @author +/*!***************************************************************************** + * \file test_rsrc_api.c * + * \brief Application for manually managing NETINT video processing devices on + * system. Its code provides examples on how to programatically use + * ni_rsrc_api.h for NETINT resource management ******************************************************************************/ + #ifdef __linux__ #include #endif #include #include -#include +#include #include #include @@ -45,15 +42,15 @@ /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -void getStr(const char *prompt, char *str) +static void getStr(const char *prompt, char *str) { - char para[16]; + char para[64]; printf("%s", prompt); if (fgets(para, sizeof(para), stdin) != 0) { @@ -65,35 +62,35 @@ void getStr(const char *prompt, char *str) } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -int getCmd(const char *prompt) +static int getCmd(const char *prompt) { - char cmd[16] = {'\0'}; + char cmd[64] = {'\0'}; getStr(prompt, cmd); return (int)cmd[0]; } /****************************************************************************** - * @brief + * @brief * - * @param + * @param * * @return ******************************************************************************/ -void change_log_level(void) +static void change_log_level(void) { - char log_str[16]; + char log_str[64]; ni_log_level_t log_level; getStr("set log level to [none, fatal, error, info, debug, trace]: ", log_str); - + log_level = arg_to_ni_log_level(log_str); if (log_level != NI_LOG_INVALID) { @@ -104,65 +101,66 @@ void change_log_level(void) } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -int getInt(const char *prompt) +static int getInt(const char *prompt) { - char para[16]; + char para[64]; getStr(prompt, para); return atoi(para); } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -float getFloat(const char *prompt) +NI_UNUSED static float getFloat(const char *prompt) { - char para[16]; + char para[64]; getStr(prompt, para); return (float)atof(para); } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -long getLong(const char *prompt) +NI_UNUSED static long getLong(const char *prompt) { - char para[32]; + char para[64]; getStr(prompt, para); return atol(para); } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -void listOneTypeCoders(void) +static void listOneTypeCoders(void) { ni_device_type_t type; int i, count = 0; ni_device_info_t coders[NI_MAX_DEVICE_CNT] = {0}; type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); - if (ni_rsrc_list_devices(type, coders, &count) == 0) { + if (ni_rsrc_list_devices(type, coders, &count) == 0) + { for (i = 0; i < count; i++) { ni_rsrc_print_device_info(&coders[i]); @@ -171,21 +169,21 @@ void listOneTypeCoders(void) } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -void listModuleId(void) +static void listModuleId(void) { /* read back the stored coders numbers */ uint32_t i, k; ni_device_queue_t *ptr; ni_device_pool_t *p_device_pool; - + p_device_pool = ni_rsrc_get_device_pool(); - if (p_device_pool) + if (p_device_pool) { #ifdef _WIN32 if (WAIT_ABANDONED == WaitForSingleObject(p_device_pool->lock, INFINITE)) // no time-out interval) @@ -194,18 +192,18 @@ void listModuleId(void) return; } #elif __linux__ - if( lockf(p_device_pool->lock, F_LOCK, 0) ) - { - fprintf(stderr, "ERROR: %s() lockf() failed: %s\n", __func__, - strerror(NI_ERRNO)); - } + if (lockf(p_device_pool->lock, F_LOCK, 0)) + { + fprintf(stderr, "ERROR: %s() lockf() failed: %s\n", __func__, + strerror(NI_ERRNO)); + } #endif /* print out coders in their current order */ ptr = p_device_pool->p_device_queue; for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) { - printf("Num %ss: %u\n", device_type_str[k], ptr->xcoder_cnt[k]); + printf("Num %ss: %u\n", g_device_type_str[k], ptr->xcoder_cnt[k]); for (i = 0; i < ptr->xcoder_cnt[k]; i++) { ni_device_info_t *p_device_info = @@ -220,25 +218,25 @@ void listModuleId(void) } #ifdef _WIN32 - ReleaseMutex(p_device_pool->lock); + ReleaseMutex(p_device_pool->lock); #elif __linux__ - if( lockf(p_device_pool->lock, F_ULOCK, 0) ) - { - fprintf(stderr, "Error lockf() failed\n"); - } + if (lockf(p_device_pool->lock, F_ULOCK, 0)) + { + fprintf(stderr, "Error lockf() failed\n"); + } #endif ni_rsrc_free_device_pool(p_device_pool); } } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -void listAllCodersFull(void) +static void listAllCodersFull(void) { int i, k; ni_device_t *p_coders = NULL; @@ -255,7 +253,7 @@ void listAllCodersFull(void) for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) { /* print out coders in the order based on their guid */ - printf("Num %ss: %d\n", device_type_str[k], + printf("Num %ss: %d\n", g_device_type_str[k], p_coders->xcoder_cnt[k]); for (i = 0; i < p_coders->xcoder_cnt[k]; i++) @@ -268,284 +266,455 @@ void listAllCodersFull(void) } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ -void updateCoderLoad(void) +static void getCoderDetailInfo(void) { ni_device_type_t type; int guid; - int load; - ni_device_context_t *p_device_context; - int i, nb_insts; - ni_sw_instance_info_t sw_insts[8]; + ni_device_info_t *p_device_info; type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); guid = getInt("Coder module ID: "); - load = getInt("load value: "); - nb_insts = getInt("Number of s/w instances: "); - for (i = 0; i < nb_insts; i++) { - sw_insts[i].id = getInt("s/w inst. id: "); - sw_insts[i].status = (ni_sw_instance_status_t)getInt("s/w inst. status, idle (0) active (1): "); - sw_insts[i].codec = (ni_codec_t)getInt("s/w inst. codec, H.264 (0) H.265 (1): "); - sw_insts[i].width = getInt("s/w inst. width: "); - sw_insts[i].height = getInt("s/w inst. height: "); - sw_insts[i].fps = getInt("s/w inst. fps: "); - } - - p_device_context = ni_rsrc_get_device_context(type, guid); - if (p_device_context) { - ni_rsrc_update_device_load(p_device_context, load, nb_insts, sw_insts); - ni_rsrc_free_device_context(p_device_context); - } else { - fprintf(stderr, "ERROR: netint device not found\n"); + printf("type: %d id %d\n", type, guid); + p_device_info = ni_rsrc_get_device_info(type, guid); + if (p_device_info) + { + ni_rsrc_print_device_info(p_device_info); + free(p_device_info); } } -/******************************************************************************* - * @brief +/*!****************************************************************************** + * \brief compare two int32_t for qsort * - * @param + * \param[in] const void *a + * \param[in] const void *b * - * @return + * \return int atoi(numArray) *******************************************************************************/ -void getCoderDetailInfo(void) +static int compareInt32_t(const void *a, const void *b) { - ni_device_type_t type; - int guid; - ni_device_info_t *p_device_info; - - type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); - guid = getInt("Coder module ID: "); - printf("type: %d id %d\n", type, guid); - p_device_info = ni_rsrc_get_device_info(type, guid); - if (p_device_info) { - ni_rsrc_print_device_info(p_device_info); - free(p_device_info); - } + if (*(int32_t *)a < *(int32_t *)b) + { + return -1; + } + else if (*(int32_t *)a > *(int32_t *)b) + { + return 1; + } + else + { + return 0; + } } /****************************************************************************** - * @brief + * @brief * - * @param + * @param * * @return ******************************************************************************/ -void getLeastUsedCoderForVideo(void) +static void displayRsrcMon(void) { - int guid, width, height, fps; - ni_codec_t codec; - ni_device_type_t type; - ni_device_info_t info; + ni_device_pool_t *p_device_pool = NULL; + ni_device_queue_t *coders = NULL; + ni_session_context_t xCtxt = {0}; + int k; - type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); - codec = (ni_codec_t)getInt("codec, H.264 (0) H.265 (1): "); - width = getInt("video width: "); - height = getInt("video height: "); - fps = getInt("video frame rate: "); - guid = ni_rsrc_get_available_device(width, height, fps, codec, type, &info); - if (guid == -1) { - fprintf(stderr, "ERROR: netint device not found\n"); - } else { - ni_rsrc_print_device_info(&info); - } + p_device_pool = ni_rsrc_get_device_pool(); + if (!p_device_pool) + { + fprintf(stderr, "FATAL: cannot get devices info\n"); + return; + } + + printf("**************************************************\n"); + ni_device_session_context_init(&xCtxt); + coders = p_device_pool->p_device_queue; + + for (k = 0; k < NI_DEVICE_TYPE_XCODER_MAX; k++) + { + ni_device_type_t module_type = k; + ni_session_context_t *sessionCtxt = &xCtxt; + int i; // used in later FOR-loop when compiled without c99 + int module_count = 0; + char module_name[8] = {'\0'}; + int32_t *module_id_arr = NULL; + ni_device_context_t *p_device_context = NULL; + + if (!IS_XCODER_DEVICE_TYPE(module_type)) + { + fprintf(stderr, "ERROR: unsupported module_type %d\n", module_type); + break; + } + + module_count = coders->xcoder_cnt[module_type]; + strcpy(module_name, g_device_type_str[module_type]); + + module_id_arr = malloc(sizeof(*module_id_arr) * module_count); + if (!module_id_arr) + { + fprintf(stderr, "ERROR: malloc() failed for module_id_arr\n"); + break; + } + memcpy(module_id_arr, coders->xcoders[module_type], + sizeof(int32_t) * module_count); + + printf("Num %ss: %d\n", g_device_type_str[module_type], module_count); + + // sort module IDs used + qsort(module_id_arr, module_count, sizeof(int32_t), compareInt32_t); + + // Print performance info headings + if (IS_XCODER_DEVICE_TYPE(module_type)) + { + printf("%-5s %-4s %-10s %-4s %-4s %-9s %-7s %-14s\n", "INDEX", + "LOAD", "MODEL_LOAD", "INST", "MEM", "SHARE_MEM", "P2P_MEM", + "DEVICE"); + } + + /*! query each coder and print out their status */ + for (i = 0; i < module_count; i++) + { + p_device_context = + ni_rsrc_get_device_context(module_type, module_id_arr[i]); + + /*! libxcoder query to get status info including load and instances;*/ + if (p_device_context) + { + sessionCtxt->device_handle = + ni_device_open(p_device_context->p_device_info->dev_name, + &sessionCtxt->max_nvme_io_size); + sessionCtxt->blk_io_handle = sessionCtxt->device_handle; + + // Check device can be opened + if (NI_INVALID_DEVICE_HANDLE == sessionCtxt->device_handle) + { + fprintf(stderr, + "ERROR: ni_device_open() failed for %s: %s\n", + p_device_context->p_device_info->dev_name, + strerror(NI_ERRNO)); + ni_rsrc_free_device_context(p_device_context); + continue; + } + + sessionCtxt->hw_id = p_device_context->p_device_info->hw_id; + if (NI_RETCODE_SUCCESS != + ni_device_session_query(sessionCtxt, module_type)) + { + ni_device_close(sessionCtxt->device_handle); + fprintf(stderr, "Error query %s %s.%d\n", module_name, + p_device_context->p_device_info->dev_name, + p_device_context->p_device_info->hw_id); + ni_rsrc_free_device_context(p_device_context); + continue; + } + // printf("Done query %s %s.%d\n", module_name, + // p_device_context->p_device_info->dev_name, + // p_device_context->p_device_info->hw_id); + ni_device_close(sessionCtxt->device_handle); + + if (0 == sessionCtxt->load_query.total_contexts) + { + sessionCtxt->load_query.current_load = 0; + } + + // Print performance info row + if (IS_XCODER_DEVICE_TYPE(module_type)) + { + printf("%-5d %-4u %-10u %-4u %-4u %-9u %-7u %-14s\n", + p_device_context->p_device_info->module_id, + sessionCtxt->load_query.current_load, + sessionCtxt->load_query.fw_model_load, + sessionCtxt->load_query.total_contexts, + sessionCtxt->load_query.fw_video_mem_usage, + sessionCtxt->load_query.fw_share_mem_usage, + sessionCtxt->load_query.fw_p2p_mem_usage, + p_device_context->p_device_info->dev_name); + } + ni_rsrc_free_device_context(p_device_context); + } + } + free(module_id_arr); + } + + ni_device_session_context_clear(&xCtxt); + ni_rsrc_free_device_pool(p_device_pool); + + printf("**************************************************\n"); } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return - *******************************************************************************/ -void allocAuto(void) + ******************************************************************************/ +static void addCoder(void) { - ni_device_context_t *p_device_context; - ni_device_type_t type; - ni_alloc_rule_t rule; - unsigned long model_load; - - type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); - rule = (ni_alloc_rule_t)getInt("auto-alloc rule, least-load (0) load-instance (1): "); - printf("type: %d rule %d\n", type, rule); - - p_device_context = ni_rsrc_allocate_auto(type, rule, EN_H265, 1920, 1080, 30, &model_load); - if (p_device_context) { - printf("Successfully auto-allocated s/w instance on:\n"); - ni_rsrc_print_device_info(p_device_context->p_device_info); - printf("Allocated load: %lu\n", model_load); - ni_rsrc_free_device_context(p_device_context); - } + char dev[64]; + int should_match_rev = 0; + getStr("device name (/dev/*): ", dev); + should_match_rev = getInt("should match current release version, yes (1) no (0): "); + ni_rsrc_add_device(dev, should_match_rev); } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return - *******************************************************************************/ -void allocDirect(void) + ******************************************************************************/ +static void initRsrc(void) { - ni_device_context_t *p_device_context; - ni_device_type_t type; - int guid; - unsigned long model_load; + int should_match_rev = + getInt("should match current release version, yes (1) no (0): "); + int timeout_seconds = getInt("timeout_seconds: "); + ni_rsrc_init(should_match_rev, timeout_seconds); +} - type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); - guid = getInt("Coder module ID: "); - printf("type: %d id %d\n", type, guid); +/****************************************************************************** + * @brief + * + * @param + * + * @return + ******************************************************************************/ +static void niRsrcRefresh(void) +{ + int should_match_rev = + getInt("should match current release version, yes (1) no (0): "); + ni_rsrc_refresh(should_match_rev); +} - p_device_context = ni_rsrc_allocate_direct(type, guid, EN_H264, 1920, 1080, 30, &model_load); - if (p_device_context) { - printf("Successfully allocated directly the s/w instance ..\n"); - ni_rsrc_free_device_context(p_device_context); - } +/****************************************************************************** + * @brief + * + * @param + * + * @return + ******************************************************************************/ +static void checkHwAvailable(void) +{ + int guid = getInt("guid :"); + int deviceType=getInt("deviceType : "); + ni_rsrc_check_hw_available(guid,deviceType); } -/******************************************************************************* - * @brief + +/****************************************************************************** + * @brief * - * @param + * @param * * @return ******************************************************************************/ -void releaseEncRsrc(void) +static void getlocaldevicelist(void) { - unsigned long load; - int guid; - ni_device_context_t *p_device_context; - //ni_device_info_t *p_device_info; - - guid = getInt("Coder module ID: "); - load = (unsigned long)getLong("load value: "); - printf("id %d load: %lu\n", guid, load); - p_device_context = ni_rsrc_get_device_context(NI_DEVICE_TYPE_ENCODER, guid); - if (p_device_context) { - ni_rsrc_release_resource(p_device_context, load); - ni_rsrc_free_device_context(p_device_context); - } else { - fprintf(stderr, "ERROR: netint device not found\n"); - } + ni_rsrc_print_all_devices_capability(); } /****************************************************************************** - * @brief + * @brief * - * @param + * @param * * @return ******************************************************************************/ -void deleteCoder(void) +static void deleteCoder(void) { - char dev[16]; + char dev[64]; getStr("device name (/dev/*): ", dev); ni_rsrc_remove_device(dev); } -/******************************************************************************* - * @brief +/****************************************************************************** + * @brief * - * @param + * @param * * @return ******************************************************************************/ -void addCoder(void) +static void removeAllDevices(void) { - char dev[16]; - int should_match_rev = 0; - getStr("device name (/dev/*): ", dev); - should_match_rev = getInt("should match current release version, yes (1) no (0): "); - ni_rsrc_add_device(dev, should_match_rev); + ni_rsrc_remove_all_devices(); +} + + +static void checkHWInfo(void) +{ + int task_mode = 0, device_type = 0, hw_mode = 0, consider_mem = 0; + printf("Please enter task mode, device type, hw mode and if to consider memory (Divided by spaces)\n"); + int ret_scanf = scanf("%d %d %d %d",&task_mode,&device_type,&hw_mode,&consider_mem); + if(ret_scanf == EOF || ret_scanf < 4) + { + fprintf(stderr, "%s, read parameters failed", __func__); + } + ni_hw_device_info_quadra_t *device_info = NULL; + ni_hw_device_info_quadra_threshold_param_t threshold[4]; + threshold[0].device_type = NI_DEVICE_TYPE_DECODER;//0 + threshold[0].load_threshold = 10; + threshold[0].task_num_threshold = 10; + threshold[1].device_type = NI_DEVICE_TYPE_ENCODER;//1 + threshold[1].load_threshold = 20; + threshold[1].task_num_threshold = 10; + threshold[2].device_type = NI_DEVICE_TYPE_SCALER;//2 + threshold[2].load_threshold = 30; + threshold[2].task_num_threshold = 10; + threshold[3].device_type = NI_DEVICE_TYPE_AI;//3 + threshold[3].load_threshold = 40; + threshold[3].task_num_threshold = 10; + + ni_hw_device_info_quadra_coder_param_t *coder_param = ni_create_hw_device_info_quadra_coder_param(10); + coder_param->encoder_param->w = 7680; + coder_param->encoder_param->h = 4320; + coder_param->encoder_param->lookaheadDepth = 20; + coder_param->decoder_param->w = 7680; + coder_param->decoder_param->h = 4320; + coder_param->decoder_param->hw_frame = 1; + coder_param->scaler_param->h = 7680; + coder_param->scaler_param->w = 1920; + coder_param->scaler_param->bit_8_10 = 8; + int ret = ni_check_hw_info(&device_info,task_mode,threshold,device_type,coder_param,hw_mode,consider_mem); + // int ret = ni_check_hw_info(&device_info, 1, threshold, 1, coder_param, 1, 0); + printf("ret = %d\n",ret); + ni_destory_hw_device_info_quadra_coder_param(coder_param); + ni_hw_device_info_free_quadra(device_info); } /******************************************************************************* - * @brief + * @brief * - * @param + * @param * * @return *******************************************************************************/ +static void allocAuto(void) +{ + ni_device_context_t *p_device_context; + ni_device_type_t type; + ni_alloc_rule_t rule; + uint64_t model_load; + + type = (ni_device_type_t)getInt("coder type, decoder (0) encoder (1): "); + rule = (ni_alloc_rule_t)getInt("auto-alloc rule, least-load (0) load-instance (1): "); + printf("type: %d rule %d\n", type, rule); + + p_device_context = ni_rsrc_allocate_auto(type, rule, EN_H265, 1920, 1080, 30, &model_load); + if (p_device_context) + { + printf("Successfully auto-allocated s/w instance on:\n"); + ni_rsrc_print_device_info(p_device_context->p_device_info); + printf("Allocated load: %"PRIu64"\n", model_load); + ni_rsrc_free_device_context(p_device_context); + } +} + + int main(void) { - int stop = 0; - while (!stop) { - printf("Key function\n" - "? show this help\n" - "v change libxcoder log level\n" - "l list all decoders, or all encoders\n" - "L list all coders detailed info\n" - "o list all coders' module #, in order of position in queue\n" - "g get a coder's info\n" - "G get the least used coder for a video stream\n" - "u update a coder's load/instances value\n" - "A allocate directly a s/w instance on a h/w coder\n" - "a allocate automatically a s/w instance\n" - "r release encoding resource (load) from a h/w instance\n" - "d delete xcoder from host resource pool\n" - "x add xcoder into host resource pool\n" - "q quit\n"); - int control = getCmd("> "); - - switch (control) { - case '?': - continue; - case 'v': - change_log_level(); - break; - case 'V': - printf("Release ver: %s\n" - "API ver: %s\n" - "Date: %s\n" - "ID: %s\n", - NI_XCODER_REVISION, LIBXCODER_API_VERSION, NI_SW_RELEASE_TIME, - NI_SW_RELEASE_ID); - break; - case 'l': - listOneTypeCoders(); - break; - case 'L': - listAllCodersFull(); - break; - case 'o': - listModuleId(); - break; - case 'g': - getCoderDetailInfo(); - break; - case 'G': - getLeastUsedCoderForVideo(); - break; - case 'u': - updateCoderLoad(); - break; - case 'A': - allocDirect(); - break; - case 'a': - allocAuto(); - break; - case 'r': - releaseEncRsrc(); - break; - case 'd': - deleteCoder(); - break; - case 'x': - addCoder(); - break; - - case 'q': - case EOF: - stop = 1; - break; - default: - continue; + int stop = 0; + + while (!stop) + { + printf("Key function\n" + "? show this help\n" + "v change libxcoder log level\n" + "l list all decoders, or all encoders\n" + "L list all coders detailed info\n" + "o list all coders' module #, in order of position in queue\n" + "g get a coder's info\n" +#ifndef _WIN32 + "i Initialize and create all resources required to work with \n" +#endif + "d delete xcoder from host resource pool\n" + "D Remove all NetInt h/w devices from resource pool on the host.\n" + "x add xcoder into host resource pool\n" + "m display ni_rsrc_mom value\n" + "s Scan and refresh all resources on the host, taking into account\n" + " hot-plugged and pulled out cards.\n" + "r check the NetInt h/w device in resource pool on the host.\n" + "p Print detailed capability information of all devices on the system.\n" + "C check hardware device detailed info\n" + "a allocate automatically a s/w instance\n" + "q quit\n"); + + int control = getCmd("> "); + switch (control) + { + case '?': + continue; +#ifndef _WIN32 + case 'i': + initRsrc(); + break; +#endif + case 'D': + removeAllDevices(); + break; + case 'v': + change_log_level(); + break; + case 'V': + printf("Release ver: %s\n" + "API ver: %s\n" + "Date: %s\n" + "ID: %s\n", + NI_XCODER_REVISION, LIBXCODER_API_VERSION, + NI_SW_RELEASE_TIME, NI_SW_RELEASE_ID); + break; + case 'l': + listOneTypeCoders(); + break; + case 'L': + listAllCodersFull(); + break; + case 'o': + listModuleId(); + break; + case 'g': + getCoderDetailInfo(); + break; + case 's': + niRsrcRefresh(); + break; + case 'p': + getlocaldevicelist(); + break; + case 'x': + addCoder(); + break; + case 'd': + deleteCoder(); + break; + case 'r': + checkHwAvailable(); + break; + case 'm': + displayRsrcMon(); + break; + case 'C': + checkHWInfo(); + break; + case 'a': + allocAuto(); + break; + case 'q': + case EOF: + stop = 1; + break; + default: + continue; + } } - } - return 0; + + return 0; }