refactor(host): hoist the direct-NVENC init-params authoring into nvenc_core
Both backends' build_init_params authored an identical NV_ENC_INITIALIZE_PARAMS (P1/ULL preset, PTD, session dimensions/rate, split-encode mode) — the only difference was the Windows-only enableEncodeAsync flag (Linux is sync-only). Hoist it to nvenc_core::build_init_params(codec_guid, w, h, fps, cfg, split_mode, enable_async); Linux's two call sites pass enable_async=false (the field stays 0 as before), Windows passes its session_async through. Keeps open and in-place reconfigure presenting the SAME init params, now guaranteed identical across platforms too. Verified on BOTH platforms: Linux clippy 0/0 (nvenc,vulkan-encode,pyrowave, RTX 5070 Ti) and Windows clippy 0/0 (nvenc,amf-qsv, RTX 4090 / .173). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
#![deny(clippy::undocumented_unsafe_blocks)]
|
#![deny(clippy::undocumented_unsafe_blocks)]
|
||||||
|
|
||||||
use super::nvenc_core::{
|
use super::nvenc_core::{
|
||||||
apply_low_latency_config, codec_guid, LowLatencyConfig, NvStatusExt, RFI_DPB,
|
apply_low_latency_config, build_init_params, codec_guid, LowLatencyConfig, NvStatusExt, RFI_DPB,
|
||||||
};
|
};
|
||||||
use super::nvenc_status;
|
use super::nvenc_status;
|
||||||
use super::{ChromaFormat, Codec, EncodedFrame, Encoder, EncoderCaps};
|
use super::{ChromaFormat, Codec, EncodedFrame, Encoder, EncoderCaps};
|
||||||
@@ -599,34 +599,6 @@ impl NvencCudaEncoder {
|
|||||||
Ok(cfg)
|
Ok(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Author the `NV_ENC_INITIALIZE_PARAMS` pointing at `cfg`. Shared by [`try_open_session`]
|
|
||||||
/// and [`Encoder::reconfigure_bitrate`] — a reconfigure must present the SAME init params as
|
|
||||||
/// the open. The returned struct borrows `cfg` raw; the caller keeps `cfg` alive across the
|
|
||||||
/// NVENC call it feeds this into.
|
|
||||||
fn build_init_params(
|
|
||||||
&self,
|
|
||||||
cfg: &mut nv::NV_ENC_CONFIG,
|
|
||||||
split_mode: u32,
|
|
||||||
) -> nv::NV_ENC_INITIALIZE_PARAMS {
|
|
||||||
let mut init = nv::NV_ENC_INITIALIZE_PARAMS {
|
|
||||||
version: nv::NV_ENC_INITIALIZE_PARAMS_VER,
|
|
||||||
encodeGUID: self.codec_guid,
|
|
||||||
presetGUID: nv::NV_ENC_PRESET_P1_GUID,
|
|
||||||
tuningInfo: nv::NV_ENC_TUNING_INFO::NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY,
|
|
||||||
encodeWidth: self.width,
|
|
||||||
encodeHeight: self.height,
|
|
||||||
darWidth: self.width,
|
|
||||||
darHeight: self.height,
|
|
||||||
frameRateNum: self.fps,
|
|
||||||
frameRateDen: 1,
|
|
||||||
enablePTD: 1,
|
|
||||||
encodeConfig: cfg,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
init.set_splitEncodeMode(split_mode);
|
|
||||||
init
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Open + configure + initialize ONE NVENC CUDA session at `bitrate` (bps) and `split_mode`.
|
/// Open + configure + initialize ONE NVENC CUDA session at `bitrate` (bps) and `split_mode`.
|
||||||
/// Returns the session handle, or destroys it and returns the error.
|
/// Returns the session handle, or destroys it and returns the error.
|
||||||
unsafe fn try_open_session(&self, bitrate: u64, split_mode: u32) -> Result<*mut c_void> {
|
unsafe fn try_open_session(&self, bitrate: u64, split_mode: u32) -> Result<*mut c_void> {
|
||||||
@@ -654,7 +626,15 @@ impl NvencCudaEncoder {
|
|||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut init = self.build_init_params(&mut cfg, split_mode);
|
let mut init = build_init_params(
|
||||||
|
self.codec_guid,
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
self.fps,
|
||||||
|
&mut cfg,
|
||||||
|
split_mode,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
match (api().initialize_encoder)(enc, &mut init).nv_ok() {
|
match (api().initialize_encoder)(enc, &mut init).nv_ok() {
|
||||||
Ok(()) => Ok(enc),
|
Ok(()) => Ok(enc),
|
||||||
@@ -1225,7 +1205,15 @@ impl Encoder for NvencCudaEncoder {
|
|||||||
};
|
};
|
||||||
let mut params = nv::NV_ENC_RECONFIGURE_PARAMS {
|
let mut params = nv::NV_ENC_RECONFIGURE_PARAMS {
|
||||||
version: nv::NV_ENC_RECONFIGURE_PARAMS_VER,
|
version: nv::NV_ENC_RECONFIGURE_PARAMS_VER,
|
||||||
reInitEncodeParams: self.build_init_params(&mut cfg, self.split_mode),
|
reInitEncodeParams: build_init_params(
|
||||||
|
self.codec_guid,
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
self.fps,
|
||||||
|
&mut cfg,
|
||||||
|
self.split_mode,
|
||||||
|
false,
|
||||||
|
),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
// Keep the encoder's RC state and reference chain: no reset, no IDR — the in-flight
|
// Keep the encoder's RC state and reference chain: no reset, no IDR — the in-flight
|
||||||
|
|||||||
@@ -68,6 +68,42 @@ pub(super) struct LowLatencyConfig {
|
|||||||
pub rfi_supported: bool,
|
pub rfi_supported: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Author the shared `NV_ENC_INITIALIZE_PARAMS` (P1/ULL preset, PTD, the session dimensions/rate)
|
||||||
|
/// pointing at `cfg`. `enable_async` drives the Windows two-thread async retrieve — Linux is
|
||||||
|
/// sync-only and passes `false`, leaving `enableEncodeAsync` at 0 as before. The returned struct
|
||||||
|
/// borrows `cfg` as a raw pointer; the caller must keep `cfg` alive across the NVENC call it feeds
|
||||||
|
/// this into. Used at open and at in-place reconfigure, which must present the SAME init params.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(super) fn build_init_params(
|
||||||
|
codec_guid: nv::GUID,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
fps: u32,
|
||||||
|
cfg: &mut nv::NV_ENC_CONFIG,
|
||||||
|
split_mode: u32,
|
||||||
|
enable_async: bool,
|
||||||
|
) -> nv::NV_ENC_INITIALIZE_PARAMS {
|
||||||
|
let mut init = nv::NV_ENC_INITIALIZE_PARAMS {
|
||||||
|
version: nv::NV_ENC_INITIALIZE_PARAMS_VER,
|
||||||
|
encodeGUID: codec_guid,
|
||||||
|
presetGUID: nv::NV_ENC_PRESET_P1_GUID,
|
||||||
|
tuningInfo: nv::NV_ENC_TUNING_INFO::NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY,
|
||||||
|
encodeWidth: width,
|
||||||
|
encodeHeight: height,
|
||||||
|
darWidth: width,
|
||||||
|
darHeight: height,
|
||||||
|
frameRateNum: fps,
|
||||||
|
frameRateDen: 1,
|
||||||
|
enablePTD: 1,
|
||||||
|
enableEncodeAsync: enable_async as u32,
|
||||||
|
encodeConfig: cfg,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
// splitEncodeMode is a C bitfield — set via the generated accessor, not a struct field.
|
||||||
|
init.set_splitEncodeMode(split_mode);
|
||||||
|
init
|
||||||
|
}
|
||||||
|
|
||||||
/// Author the shared low-latency NVENC config onto a **preset-seeded** `cfg`: CBR + infinite GOP +
|
/// Author the shared low-latency NVENC config onto a **preset-seeded** `cfg`: CBR + infinite GOP +
|
||||||
/// P-only + ~1-frame VBV, per-codec tier/level, chroma + bit depth, unconditional colour signaling,
|
/// P-only + ~1-frame VBV, per-codec tier/level, chroma + bit depth, unconditional colour signaling,
|
||||||
/// and the RFI DPB. The caller seeds `cfg` from the P1/ULL preset first (that call needs the
|
/// and the RFI DPB. The caller seeds `cfg` from the P1/ULL preset first (that call needs the
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#![deny(clippy::undocumented_unsafe_blocks)]
|
#![deny(clippy::undocumented_unsafe_blocks)]
|
||||||
|
|
||||||
use super::nvenc_core::{
|
use super::nvenc_core::{
|
||||||
apply_low_latency_config, codec_guid, LowLatencyConfig, NvStatusExt, RFI_DPB,
|
apply_low_latency_config, build_init_params, codec_guid, LowLatencyConfig, NvStatusExt, RFI_DPB,
|
||||||
};
|
};
|
||||||
use super::nvenc_status;
|
use super::nvenc_status;
|
||||||
use super::{ChromaFormat, Codec, EncodedFrame, Encoder, EncoderCaps};
|
use super::{ChromaFormat, Codec, EncodedFrame, Encoder, EncoderCaps};
|
||||||
@@ -742,39 +742,6 @@ impl NvencD3d11Encoder {
|
|||||||
Ok(cfg)
|
Ok(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Author the `NV_ENC_INITIALIZE_PARAMS` pointing at `cfg`. Shared by [`try_open_session`]
|
|
||||||
/// and [`Encoder::reconfigure_bitrate`] — a reconfigure must present the SAME init params as
|
|
||||||
/// the open. The returned struct borrows `cfg` raw; the caller keeps `cfg` alive across the
|
|
||||||
/// NVENC call it feeds this into.
|
|
||||||
fn build_init_params(
|
|
||||||
&self,
|
|
||||||
cfg: &mut nv::NV_ENC_CONFIG,
|
|
||||||
split_mode: u32,
|
|
||||||
enable_async: bool,
|
|
||||||
) -> nv::NV_ENC_INITIALIZE_PARAMS {
|
|
||||||
let mut init = nv::NV_ENC_INITIALIZE_PARAMS {
|
|
||||||
version: nv::NV_ENC_INITIALIZE_PARAMS_VER,
|
|
||||||
encodeGUID: self.codec_guid,
|
|
||||||
presetGUID: nv::NV_ENC_PRESET_P1_GUID,
|
|
||||||
tuningInfo: nv::NV_ENC_TUNING_INFO::NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY,
|
|
||||||
encodeWidth: self.width,
|
|
||||||
encodeHeight: self.height,
|
|
||||||
darWidth: self.width,
|
|
||||||
darHeight: self.height,
|
|
||||||
frameRateNum: self.fps,
|
|
||||||
frameRateDen: 1,
|
|
||||||
enablePTD: 1,
|
|
||||||
// Two-thread async retrieve (§5.B): completion events signal the retrieve thread
|
|
||||||
// instead of `lock_bitstream` blocking the submit thread.
|
|
||||||
enableEncodeAsync: enable_async as u32,
|
|
||||||
encodeConfig: cfg,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
// splitEncodeMode is a C bitfield — set via the generated accessor, not a struct field.
|
|
||||||
init.set_splitEncodeMode(split_mode);
|
|
||||||
init
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Open + configure + initialize ONE NVENC session at `bitrate` (bps) and `split_mode`. Returns
|
/// Open + configure + initialize ONE NVENC session at `bitrate` (bps) and `split_mode`. Returns
|
||||||
/// the session handle, or destroys it and returns the error. NVENC has no re-init after a failed
|
/// the session handle, or destroys it and returns the error. NVENC has no re-init after a failed
|
||||||
/// `initialize_encoder`, so the bitrate-clamp search in `init_session` calls this once per probe.
|
/// `initialize_encoder`, so the bitrate-clamp search in `init_session` calls this once per probe.
|
||||||
@@ -809,7 +776,15 @@ impl NvencD3d11Encoder {
|
|||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut init = self.build_init_params(&mut cfg, split_mode, enable_async);
|
let mut init = build_init_params(
|
||||||
|
self.codec_guid,
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
self.fps,
|
||||||
|
&mut cfg,
|
||||||
|
split_mode,
|
||||||
|
enable_async,
|
||||||
|
);
|
||||||
|
|
||||||
match (api().initialize_encoder)(enc, &mut init).nv_ok() {
|
match (api().initialize_encoder)(enc, &mut init).nv_ok() {
|
||||||
Ok(()) => Ok(enc),
|
Ok(()) => Ok(enc),
|
||||||
@@ -1541,7 +1516,11 @@ impl Encoder for NvencD3d11Encoder {
|
|||||||
};
|
};
|
||||||
let mut params = nv::NV_ENC_RECONFIGURE_PARAMS {
|
let mut params = nv::NV_ENC_RECONFIGURE_PARAMS {
|
||||||
version: nv::NV_ENC_RECONFIGURE_PARAMS_VER,
|
version: nv::NV_ENC_RECONFIGURE_PARAMS_VER,
|
||||||
reInitEncodeParams: self.build_init_params(
|
reInitEncodeParams: build_init_params(
|
||||||
|
self.codec_guid,
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
self.fps,
|
||||||
&mut cfg,
|
&mut cfg,
|
||||||
self.split_mode,
|
self.split_mode,
|
||||||
self.session_async,
|
self.session_async,
|
||||||
|
|||||||
Reference in New Issue
Block a user