refactor(host): hoist shared libav glue into encode/libav.rs (pixel_to_av + swscale consts)
First step of the W2 libav de-dup (plan §2.2, the missing Tier-2 mid-layer). The three libavcodec backends (Linux NVENC, VAAPI, Windows AMF/QSV) each carried a byte-identical pixel_to_av plus the SWS_POINT / SWS_CS_ITU709 (/SWS_CS_BT2020) swscale consts. Hoist them into a new encode/libav.rs and import from super::libav. The module is gated to compile exactly when a libav backend does (linux, or windows+amf-qsv). Free fns/consts over borrowed handles — no per-frame dyn/alloc, off the zero-copy path. Verified: Linux cargo check green (linux/mod.rs + vaapi.rs compile against it); ffmpeg_win.rs is Windows-cfg — same mechanical swap, covered by Windows CI on push. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1033,6 +1033,10 @@ mod nvenc_cuda;
|
||||
#[cfg(all(any(target_os = "linux", target_os = "windows"), feature = "nvenc"))]
|
||||
#[path = "encode/nvenc_status.rs"]
|
||||
mod nvenc_status;
|
||||
// Shared libavcodec glue (`pixel_to_av`, swscale consts) for the three libav backends — Linux
|
||||
// NVENC + VAAPI and Windows AMF/QSV — so the byte-identical pieces live once (plan §2.2, Tier 2).
|
||||
#[cfg(any(target_os = "linux", all(target_os = "windows", feature = "amf-qsv")))]
|
||||
mod libav;
|
||||
// Software (openh264) H.264 encoder — the GPU-less path on BOTH Windows and Linux (a headless /
|
||||
// GPU-less test box, or a fallback when no hardware encoder is available). Platform-agnostic: it
|
||||
// consumes CPU RGB `CapturedFrame`s and the statically-bundled openh264 build.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//! Shared libavcodec (FFmpeg) glue for the three libav encode backends — Linux NVENC
|
||||
//! (`encode/linux/mod.rs`), VAAPI (`encode/linux/vaapi.rs`), and Windows AMF/QSV
|
||||
//! (`encode/windows/ffmpeg_win.rs`) — so the byte-identical pieces live once (plan §2.2, the Tier-2
|
||||
//! gap). Free functions and consts over borrowed handles; nothing here is per-frame `dyn`,
|
||||
//! allocating, or on the zero-copy ingest path.
|
||||
use ffmpeg_next::ffi; // = ffmpeg_sys_next
|
||||
use ffmpeg_next::format::Pixel;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// swscale: nearest-neighbour scaler flag (`SWS_POINT`). We never rescale (src dims == dst dims), so
|
||||
/// the resampler choice only governs the colour-conversion path; POINT is the cheapest.
|
||||
pub(crate) const SWS_POINT: c_int = 0x10;
|
||||
/// swscale colorspace id for ITU-R BT.709 (`SWS_CS_ITU709`) — the CSC coefficients for our RGB→YUV.
|
||||
pub(crate) const SWS_CS_ITU709: c_int = 1;
|
||||
/// swscale colorspace id for ITU-R BT.2020 non-constant-luminance (`SWS_CS_BT2020`) — the CSC
|
||||
/// coefficients for the HDR X2BGR10→P010 path (Windows only today).
|
||||
pub(crate) const SWS_CS_BT2020: c_int = 9;
|
||||
|
||||
/// `Pixel` → `AVPixelFormat`. `Pixel` is `#[repr(i32)]`-compatible with `AVPixelFormat` (the bindgen
|
||||
/// enum) via this documented conversion in ffmpeg-next.
|
||||
pub(crate) fn pixel_to_av(p: Pixel) -> ffi::AVPixelFormat {
|
||||
ffi::AVPixelFormat::from(p)
|
||||
}
|
||||
@@ -21,14 +21,9 @@ use ffmpeg_next as ffmpeg;
|
||||
use std::os::raw::c_int;
|
||||
use std::ptr;
|
||||
|
||||
use super::libav::{pixel_to_av, SWS_CS_ITU709, SWS_POINT};
|
||||
use ffmpeg::ffi; // = ffmpeg_sys_next
|
||||
|
||||
/// swscale: nearest-neighbour scaler flag (`SWS_POINT`). We never rescale (src dims == dst dims), so
|
||||
/// the resampler choice only governs the colour-conversion path; POINT is the cheapest.
|
||||
const SWS_POINT: c_int = 0x10;
|
||||
/// swscale colorspace id for ITU-R BT.709 (`SWS_CS_ITU709`) — the CSC coefficients for our RGB→YUV.
|
||||
const SWS_CS_ITU709: c_int = 1;
|
||||
|
||||
/// The swscale *source* pixel format for a captured packed RGB/BGR layout (the real byte order, not
|
||||
/// the NVENC-padded `*0` form). Used by the 4:4:4 RGB→YUV444P conversion path. Mirrors the VAAPI
|
||||
/// CPU-input mapping; YUV/10-bit inputs can't feed this path (the 4:4:4 session forces packed RGB).
|
||||
@@ -118,13 +113,6 @@ impl Drop for CudaHw {
|
||||
}
|
||||
}
|
||||
|
||||
/// `ffmpeg::format::Pixel` → raw `AVPixelFormat`.
|
||||
fn pixel_to_av(p: Pixel) -> ffi::AVPixelFormat {
|
||||
// `Pixel` is `#[repr(i32)]`-compatible with `AVPixelFormat` (the bindgen enum) via this
|
||||
// documented conversion in ffmpeg-next.
|
||||
ffi::AVPixelFormat::from(p)
|
||||
}
|
||||
|
||||
/// Map a captured layout to the NVENC input pixel format, and whether a 3→4 byte expand is
|
||||
/// needed (packed RGB/BGR have no padding byte; the NVENC `*0` formats do).
|
||||
fn nvenc_input(format: PixelFormat) -> (Pixel, bool) {
|
||||
|
||||
@@ -34,18 +34,9 @@ use std::os::raw::c_int;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use super::libav::{pixel_to_av, SWS_CS_ITU709, SWS_POINT};
|
||||
use ffmpeg::ffi; // = ffmpeg_sys_next
|
||||
|
||||
// libswscale scaler-flag + colour-space constants (not exported as Rust consts by the bindings;
|
||||
// these are the stable `<libswscale/swscale.h>` #defines). No-rescale → POINT is cheapest.
|
||||
const SWS_POINT: c_int = 0x10;
|
||||
const SWS_CS_ITU709: c_int = 1;
|
||||
|
||||
/// `ffmpeg::format::Pixel` → raw `AVPixelFormat` (the documented ffmpeg-next conversion).
|
||||
fn pixel_to_av(p: Pixel) -> ffi::AVPixelFormat {
|
||||
ffi::AVPixelFormat::from(p)
|
||||
}
|
||||
|
||||
/// `fourcc(a,b,c,d)` — DRM FourCC packing (`a | b<<8 | c<<16 | d<<24`).
|
||||
const fn fourcc(a: u8, b: u8, c: u8, d: u8) -> u32 {
|
||||
(a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24)
|
||||
|
||||
@@ -60,14 +60,9 @@ use windows::Win32::Graphics::Dxgi::Common::{
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_SAMPLE_DESC,
|
||||
};
|
||||
|
||||
use super::libav::{pixel_to_av, SWS_CS_BT2020, SWS_CS_ITU709, SWS_POINT};
|
||||
use ffmpeg::ffi; // = ffmpeg_sys_next
|
||||
|
||||
// libswscale scaler-flag + colour-space constants (not exported as Rust consts by the bindings —
|
||||
// the stable `<libswscale/swscale.h>` #defines, same as the VAAPI path uses).
|
||||
const SWS_POINT: c_int = 0x10;
|
||||
const SWS_CS_ITU709: c_int = 1;
|
||||
const SWS_CS_BT2020: c_int = 9;
|
||||
|
||||
/// `AVD3D11VADeviceContext` (libavutil/hwcontext_d3d11va.h) — mirrored (the ffmpeg-sys bindings
|
||||
/// don't allowlist that header). We set `device` to the capturer's `ID3D11Device` so AMF/QSV share
|
||||
/// it; `av_hwdevice_ctx_init` fills `device_context`/`video_device`/`video_context`/the default
|
||||
@@ -149,11 +144,6 @@ fn is_10bit_format(format: PixelFormat, bit_depth: u8) -> bool {
|
||||
bit_depth >= 10 || matches!(format, PixelFormat::P010 | PixelFormat::Rgb10a2)
|
||||
}
|
||||
|
||||
/// `ffmpeg::format::Pixel` → raw `AVPixelFormat`.
|
||||
fn pixel_to_av(p: Pixel) -> ffi::AVPixelFormat {
|
||||
ffi::AVPixelFormat::from(p)
|
||||
}
|
||||
|
||||
/// Build the FFmpeg encoder context shared by both inner paths: name, mode, low-latency RC,
|
||||
/// infinite GOP, the BT.709-limited (SDR) or BT.2020-PQ (HDR) VUI, the given `pix_fmt`, and the
|
||||
/// optional hw device/frames contexts (null for the system path). Returns the opened encoder.
|
||||
|
||||
Reference in New Issue
Block a user