forked from unom/punktfunk
fix(encode): classify libav-NVENC open failures by errno, not English strerror text
The bitrate-probe ladder stepped down on format!("{e:#}").contains(
"Invalid argument") — an English substring over the WHOLE context chain,
which also fired on any other wrapped EINVAL (e.g. a CUDA-context errno)
and gated a ~10-step ladder on strerror wording. The root ffmpeg::Error
survives the anyhow chain; downcast and match Error::Other{errno:EINVAL}
instead. Same fix for the intra-refresh ENOSYS probe in the open path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -468,7 +468,15 @@ impl NvencEncoder {
|
||||
// sessions) and reopen this session without intra-refresh; any other failure — and
|
||||
// any failure when IR wasn't requested — propagates untouched (the bitrate probe
|
||||
// keys on EINVAL, which must not trip the latch).
|
||||
Err(e) if intra_refresh && format!("{e:#}").contains("Function not implemented") => {
|
||||
Err(e)
|
||||
if intra_refresh
|
||||
&& matches!(
|
||||
e,
|
||||
ffmpeg::Error::Other {
|
||||
errno: ffmpeg::util::error::ENOSYS
|
||||
}
|
||||
) =>
|
||||
{
|
||||
tracing::warn!(
|
||||
encoder = name,
|
||||
"NVENC intra-refresh not supported by this GPU — falling back to IDR-only \
|
||||
|
||||
@@ -897,13 +897,29 @@ fn open_nvenc_probed(
|
||||
}
|
||||
// EINVAL = above this GPU's level ceiling → step down. Any other failure (no GPU,
|
||||
// bad mode, OOM) is real — surface it rather than masking it with bitrate retries.
|
||||
Err(e) if format!("{e:#}").contains("Invalid argument") => last = Some(e),
|
||||
Err(e) if nvenc_open_einval(&e) => last = Some(e),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Err(last.unwrap_or_else(|| anyhow::anyhow!("encoder open failed at every probed bitrate")))
|
||||
}
|
||||
|
||||
/// Whether a libav NVENC open failed with EINVAL — the "bitrate above this GPU's level ceiling"
|
||||
/// signal [`open_nvenc_probed`]'s ladder steps down on. Typed: the root `ffmpeg::Error` survives
|
||||
/// the `anyhow` context chain, so match it there instead of substring-matching the English
|
||||
/// strerror rendering of the whole chain — which also fired on any OTHER wrapped EINVAL (e.g. a
|
||||
/// CUDA-context errno) and steered the ladder on failures that have nothing to do with bitrate.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn nvenc_open_einval(e: &anyhow::Error) -> bool {
|
||||
use ffmpeg_next as ffmpeg;
|
||||
matches!(
|
||||
e.downcast_ref::<ffmpeg::Error>(),
|
||||
Some(ffmpeg::Error::Other {
|
||||
errno: ffmpeg::util::error::EINVAL
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/// Whether the direct-SDK NVENC path is active. **Default ON** — on-glass validated 2026-07-12:
|
||||
/// real RFI landed 73/73 as clean P-frame recovery anchors (never IDR) on an RTX host with a real
|
||||
/// Steam Deck client (design/linux-direct-nvenc.md §9). `PUNKTFUNK_NVENC_DIRECT=0` (also `false`/
|
||||
|
||||
Reference in New Issue
Block a user