Wrap FFmpeg's AVHWDeviceType and av_hwdevice_iterate_types
This commit is contained in:
parent
3235a0425a
commit
99595eeeed
5 changed files with 173 additions and 0 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -1065,6 +1065,7 @@ dependencies = [
|
|||
"i18n-embed",
|
||||
"i18n-embed-fl",
|
||||
"lazy_static",
|
||||
"lexopt",
|
||||
"libcosmic",
|
||||
"log",
|
||||
"paste",
|
||||
|
|
@ -2840,6 +2841,12 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "lexopt"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ rust-embed = "6"
|
|||
# Logging
|
||||
env_logger = "0.10"
|
||||
log = "0.4"
|
||||
lexopt = "0.3"
|
||||
|
||||
[dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic.git"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use cosmic::{
|
|||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::wrappers::HWDeviceType;
|
||||
|
||||
pub const CONFIG_VERSION: u64 = 1;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
|
|
@ -28,12 +30,14 @@ impl AppTheme {
|
|||
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct Config {
|
||||
pub app_theme: AppTheme,
|
||||
pub hw_decoder: HWDeviceType,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
app_theme: AppTheme::System,
|
||||
hw_decoder: HWDeviceType::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ mod localize;
|
|||
use player::{PlayerMessage, VideoFrame, VideoQueue};
|
||||
mod player;
|
||||
|
||||
mod wrappers;
|
||||
|
||||
/// Runs application with these settings
|
||||
#[rustfmt::skip]
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
|
|||
159
src/wrappers.rs
Normal file
159
src/wrappers.rs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use ffmpeg_next::ffi::{av_hwdevice_iterate_types, AVHWDeviceType};
|
||||
use serde::{
|
||||
de::{value::Error as DeError, Error as DeErrorTrait, Unexpected},
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
|
||||
/// Delegate type for [`ffmpeg_next::ffi::AVHWDeviceType`] for configs.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum HWDeviceType {
|
||||
None,
|
||||
/// Compute Unified Device Architecture
|
||||
/// Nvidia only.
|
||||
/// https://developer.nvidia.com/video-codec-sdk
|
||||
Cuda,
|
||||
/// Direct3D 11 Video API
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/medfound/direct3d-11-video-apis
|
||||
D3d11va,
|
||||
/// Direct3D 12 Video API
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-overview
|
||||
D3d12va,
|
||||
/// DirectX Video Acceleration 2.0
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/medfound/about-dxva-2-0
|
||||
Dxva2,
|
||||
Drm,
|
||||
/// MediaCodec
|
||||
/// Android only
|
||||
/// https://developer.android.com/reference/android/media/MediaCodec
|
||||
MediaCodec,
|
||||
/// OpenCL
|
||||
/// Only used in filters
|
||||
/// https://www.khronos.org/opencl/
|
||||
OpenCl,
|
||||
/// Intel Quick Sync Video
|
||||
/// https://www.intel.com/content/www/us/en/developer/tools/vpl/overview.html
|
||||
Qsv,
|
||||
/// Video Acceleration API
|
||||
/// https://www.intel.com/content/www/us/en/developer/articles/technical/linuxmedia-vaapi.html
|
||||
Vaapi,
|
||||
/// Video Decode and Presentation API for Unix
|
||||
/// https://www.freedesktop.org/wiki/Software/VDPAU/
|
||||
Vdpau,
|
||||
/// Video Toolbox
|
||||
/// https://developer.apple.com/documentation/videotoolbox
|
||||
VideoToolbox,
|
||||
/// Vulkan
|
||||
Vulkan,
|
||||
}
|
||||
|
||||
impl HWDeviceType {
|
||||
/// Hardware device names for user facing interfaces (logging, configs).
|
||||
pub const fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::None => "None",
|
||||
Self::Cuda => "CUDA",
|
||||
Self::Dxva2 => "DirectX Video Acceleration 2.0",
|
||||
Self::D3d11va => "DirectX 11 Video Acceleration",
|
||||
Self::D3d12va => "DirectX 12 Video Acceleration",
|
||||
Self::Drm => "Direct Rendering Manager (DRM)",
|
||||
Self::MediaCodec => "MediaCodec",
|
||||
Self::OpenCl => "OpenCL",
|
||||
Self::Qsv => "Intel Quick Video Sync",
|
||||
Self::Vaapi => "VA-API",
|
||||
Self::Vdpau => "VDPAU",
|
||||
Self::VideoToolbox => "VideoToolbox",
|
||||
Self::Vulkan => "Vulkan",
|
||||
}
|
||||
}
|
||||
|
||||
/// Supported hardware decoders
|
||||
pub fn supported_devices() -> SupportedDeviceIter {
|
||||
SupportedDeviceIter::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for HWDeviceType {
|
||||
type Err = DeError;
|
||||
|
||||
// av_hwdevice_find_type_by_name returns None for invalid device type names, but this type
|
||||
// is used for deserializing configs (etc.) so the error is preserved.
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"none" => Ok(Self::None),
|
||||
"cuda" => Ok(Self::Cuda),
|
||||
"dxva2" => Ok(Self::Dxva2),
|
||||
"d3d11va" => Ok(Self::D3d11va),
|
||||
"d3d12va" => Ok(Self::D3d12va),
|
||||
"drm" => Ok(Self::Drm),
|
||||
"mediacodec" => Ok(Self::MediaCodec),
|
||||
"opencl" => Ok(Self::OpenCl),
|
||||
"qsv" => Ok(Self::Qsv),
|
||||
"vaapi" => Ok(Self::Vaapi),
|
||||
"vdpau" => Ok(Self::Vdpau),
|
||||
"videotoolbox" => Ok(Self::VideoToolbox),
|
||||
"vulkan" => Ok(Self::Vulkan),
|
||||
_ => Err(DeError::invalid_value(
|
||||
Unexpected::Str(s),
|
||||
&"valid hardware decoder",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AVHWDeviceType> for HWDeviceType {
|
||||
fn from(value: AVHWDeviceType) -> Self {
|
||||
match value {
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_NONE => Self::None,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_CUDA => Self::Cuda,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_DXVA2 => Self::Dxva2,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_D3D11VA => Self::D3d11va,
|
||||
// This variant exists in ffmpeg's C lib but not in Rust's crate yet.
|
||||
// AVHWDeviceType::AV_HWDEVICE_TYPE_D3D12VA => Self::D3d12va
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_DRM => Self::Drm,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_MEDIACODEC => Self::MediaCodec,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_OPENCL => Self::OpenCl,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_QSV => Self::Qsv,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_VAAPI => Self::Vaapi,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_VDPAU => Self::Vdpau,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_VIDEOTOOLBOX => Self::VideoToolbox,
|
||||
AVHWDeviceType::AV_HWDEVICE_TYPE_VULKAN => Self::Vulkan,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HWDeviceType {
|
||||
fn default() -> Self {
|
||||
Self::Vaapi
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SupportedDeviceIter {
|
||||
current: AVHWDeviceType,
|
||||
}
|
||||
|
||||
impl Default for SupportedDeviceIter {
|
||||
fn default() -> Self {
|
||||
// SAFETY: FFmpeg's documentation states that the iterator is delimited by AV_HWDEVICE_TYPE_NONE.
|
||||
let current = unsafe { av_hwdevice_iterate_types(AVHWDeviceType::AV_HWDEVICE_TYPE_NONE) };
|
||||
Self { current }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for SupportedDeviceIter {
|
||||
type Item = HWDeviceType;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current == AVHWDeviceType::AV_HWDEVICE_TYPE_NONE {
|
||||
None
|
||||
} else {
|
||||
let prev = self.current;
|
||||
self.current = unsafe { av_hwdevice_iterate_types(prev) };
|
||||
|
||||
Some(prev.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue