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)]
|
||||
|
||||
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::{ChromaFormat, Codec, EncodedFrame, Encoder, EncoderCaps};
|
||||
@@ -599,34 +599,6 @@ impl NvencCudaEncoder {
|
||||
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`.
|
||||
/// 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> {
|
||||
@@ -654,7 +626,15 @@ impl NvencCudaEncoder {
|
||||
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() {
|
||||
Ok(()) => Ok(enc),
|
||||
@@ -1225,7 +1205,15 @@ impl Encoder for NvencCudaEncoder {
|
||||
};
|
||||
let mut params = nv::NV_ENC_RECONFIGURE_PARAMS {
|
||||
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()
|
||||
};
|
||||
// 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,
|
||||
}
|
||||
|
||||
/// 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 +
|
||||
/// 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
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#![deny(clippy::undocumented_unsafe_blocks)]
|
||||
|
||||
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::{ChromaFormat, Codec, EncodedFrame, Encoder, EncoderCaps};
|
||||
@@ -742,39 +742,6 @@ impl NvencD3d11Encoder {
|
||||
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
|
||||
/// 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.
|
||||
@@ -809,7 +776,15 @@ impl NvencD3d11Encoder {
|
||||
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() {
|
||||
Ok(()) => Ok(enc),
|
||||
@@ -1541,7 +1516,11 @@ impl Encoder for NvencD3d11Encoder {
|
||||
};
|
||||
let mut params = nv::NV_ENC_RECONFIGURE_PARAMS {
|
||||
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,
|
||||
self.split_mode,
|
||||
self.session_async,
|
||||
|
||||
Reference in New Issue
Block a user