Skip to main content

lumen_ffmpeg/encode/
hardware.rs

1use crate::gpu::GpuBackend;
2use crate::video::VideoCodec;
3
4use super::codec::encoder_by_name;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct GpuTextureEncodeSupport {
8    pub backend: GpuBackend,
9    pub codec: VideoCodec,
10    pub encoder_name: Option<&'static str>,
11    pub available: bool,
12    pub direct_texture_path: bool,
13    pub reason: Option<String>,
14}
15
16pub(crate) fn hardware_texture_encoder_name(
17    backend: GpuBackend,
18    codec: VideoCodec,
19) -> Option<&'static str> {
20    match (backend, codec) {
21        (GpuBackend::Cuda, VideoCodec::H264) => Some("h264_nvenc"),
22        (GpuBackend::Cuda, VideoCodec::Hevc) => Some("hevc_nvenc"),
23        (GpuBackend::Cuda, VideoCodec::Av1) => Some("av1_nvenc"),
24        (GpuBackend::Metal, VideoCodec::H264) => Some("h264_videotoolbox"),
25        (GpuBackend::Metal, VideoCodec::Hevc) => Some("hevc_videotoolbox"),
26        _ => None,
27    }
28}
29
30pub fn gpu_texture_encode_support(
31    codec: VideoCodec,
32    backend: GpuBackend,
33) -> GpuTextureEncodeSupport {
34    let encoder_name = hardware_texture_encoder_name(backend, codec);
35    let texture_path_wired = matches!(backend, GpuBackend::Cuda | GpuBackend::Metal);
36    let encoder_available =
37        texture_path_wired && encoder_name.is_some_and(|name| encoder_by_name(name).is_ok());
38    let reason = if !encoder_available {
39        Some(match (texture_path_wired, encoder_name) {
40            (false, _) => format!("{backend:?} hardware texture encode is not available yet"),
41            (true, Some(name)) => format!("FFmpeg encoder `{name}` is unavailable"),
42            (true, None) => format!("{backend:?} texture encode is unavailable for {codec:?}"),
43        })
44    } else {
45        None
46    };
47
48    GpuTextureEncodeSupport {
49        backend,
50        codec,
51        encoder_name,
52        available: encoder_available,
53        direct_texture_path: false,
54        reason,
55    }
56}