Skip to main content

mediadecode_ffmpeg/
backend.rs

1use ffmpeg_next::ffi::{AVHWDeviceType, AVPixelFormat};
2
3/// Hardware decoding backend.
4///
5/// `hwdecode` only manages **hardware** decoders — software fallback is
6/// out of scope. If no backend in [`probe_order`] for the current platform
7/// can decode a stream, [`crate::VideoDecoder::open`] returns
8/// [`crate::Error::AllBackendsFailed`] and the caller decides how to fall
9/// back (e.g. by opening an `ffmpeg::decoder::Video` directly).
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11pub enum Backend {
12  /// Apple VideoToolbox (macOS, iOS, iPadOS, tvOS, visionOS).
13  VideoToolbox,
14  /// Linux Video Acceleration API (Intel / AMD GPUs).
15  Vaapi,
16  /// NVIDIA NVDEC via CUDA (Linux / Windows on NVIDIA hardware).
17  Cuda,
18  /// Microsoft Direct3D 11 Video Acceleration (Windows).
19  D3d11va,
20}
21
22impl Backend {
23  /// `AVHWDeviceType` corresponding to this backend.
24  pub(crate) fn av_hwdevice_type(self) -> AVHWDeviceType {
25    match self {
26      Self::VideoToolbox => AVHWDeviceType::AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
27      Self::Vaapi => AVHWDeviceType::AV_HWDEVICE_TYPE_VAAPI,
28      Self::Cuda => AVHWDeviceType::AV_HWDEVICE_TYPE_CUDA,
29      Self::D3d11va => AVHWDeviceType::AV_HWDEVICE_TYPE_D3D11VA,
30    }
31  }
32
33  /// Hardware pixel format the codec is expected to produce when this
34  /// backend is in use. (The post-`av_hwframe_transfer_data` CPU format is
35  /// typically `NV12` or `P010LE`; this is the *pre-transfer* sentinel.)
36  ///
37  /// Returns a `AVPixelFormat` value constructed from a hardcoded constant
38  /// in our bindings — never reads an enum value supplied by FFmpeg, so
39  /// no enum-discriminant UB risk.
40  pub(crate) fn hw_pixel_format(self) -> AVPixelFormat {
41    match self {
42      Self::VideoToolbox => AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX,
43      Self::Vaapi => AVPixelFormat::AV_PIX_FMT_VAAPI,
44      Self::Cuda => AVPixelFormat::AV_PIX_FMT_CUDA,
45      Self::D3d11va => AVPixelFormat::AV_PIX_FMT_D3D11,
46    }
47  }
48}
49
50/// Probe order for `VideoDecoder::open` on the current target. Hardware
51/// backends only, in preference order. Empty for platforms with no known
52/// HW backend; on those `open()` returns `AllBackendsFailed` immediately.
53pub(crate) fn probe_order() -> &'static [Backend] {
54  #[cfg(target_vendor = "apple")]
55  {
56    &[Backend::VideoToolbox]
57  }
58  #[cfg(target_os = "linux")]
59  {
60    &[Backend::Vaapi, Backend::Cuda]
61  }
62  #[cfg(target_os = "windows")]
63  {
64    &[Backend::D3d11va, Backend::Cuda]
65  }
66  #[cfg(not(any(target_vendor = "apple", target_os = "linux", target_os = "windows",)))]
67  {
68    &[]
69  }
70}
71
72#[cfg(test)]
73mod tests {
74  use super::*;
75
76  #[test]
77  fn all_backends_have_hwdevice_type_and_pix_fmt() {
78    for b in [
79      Backend::VideoToolbox,
80      Backend::Vaapi,
81      Backend::Cuda,
82      Backend::D3d11va,
83    ] {
84      let _ = b.av_hwdevice_type();
85      let _ = b.hw_pixel_format();
86    }
87  }
88
89  #[cfg(any(
90    target_os = "macos",
91    target_os = "ios",
92    target_os = "tvos",
93    target_os = "visionos",
94  ))]
95  #[test]
96  fn apple_probe_order() {
97    assert_eq!(probe_order(), &[Backend::VideoToolbox]);
98  }
99
100  #[cfg(target_os = "linux")]
101  #[test]
102  fn linux_probe_order() {
103    assert_eq!(probe_order(), &[Backend::Vaapi, Backend::Cuda]);
104  }
105
106  #[cfg(target_os = "windows")]
107  #[test]
108  fn windows_probe_order() {
109    assert_eq!(probe_order(), &[Backend::D3d11va, Backend::Cuda]);
110  }
111}