use crate::{CudaLibrary, Decoder, DecoderCodec, Encoder, EncoderCodec, Error};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoCodecType {
H264,
Hevc,
Av1,
Vp8,
Vp9,
Jpeg,
}
impl VideoCodecType {
fn all() -> &'static [Self] {
&[
Self::H264,
Self::Hevc,
Self::Av1,
Self::Vp8,
Self::Vp9,
Self::Jpeg,
]
}
fn to_decoder_codec(self) -> DecoderCodec {
match self {
Self::H264 => DecoderCodec::H264,
Self::Hevc => DecoderCodec::Hevc,
Self::Av1 => DecoderCodec::Av1,
Self::Vp8 => DecoderCodec::Vp8,
Self::Vp9 => DecoderCodec::Vp9,
Self::Jpeg => DecoderCodec::Jpeg,
}
}
fn to_encoder_codec(self) -> Option<EncoderCodec> {
match self {
Self::H264 => Some(EncoderCodec::H264),
Self::Hevc => Some(EncoderCodec::Hevc),
Self::Av1 => Some(EncoderCodec::Av1),
Self::Vp8 | Self::Vp9 | Self::Jpeg => None,
}
}
}
#[derive(Debug, Clone)]
pub struct CodecInfo {
pub codec: VideoCodecType,
pub decoding: DecodingInfo,
pub encoding: EncodingInfo,
}
#[derive(Debug, Clone)]
pub struct DecodingInfo {
pub supported: bool,
pub hardware_accelerated: bool,
pub max_width: u32,
pub max_height: u32,
pub min_width: u32,
pub min_height: u32,
pub max_mb_count: u32,
}
#[derive(Debug, Clone)]
pub struct EncodingInfo {
pub supported: bool,
pub hardware_accelerated: bool,
pub profiles: EncodingProfiles,
pub max_width: i32,
pub max_height: i32,
pub min_width: i32,
pub min_height: i32,
pub num_max_bframes: i32,
pub supports_yuv444: bool,
pub supports_yuv422: bool,
pub supports_10bit: bool,
pub supports_lossless: bool,
pub supports_lookahead: bool,
pub supports_temporal_aq: bool,
pub supported_ratecontrol_modes: i32,
}
impl EncodingInfo {
fn unsupported() -> Self {
Self {
supported: false,
hardware_accelerated: false,
profiles: EncodingProfiles::None,
max_width: 0,
max_height: 0,
min_width: 0,
min_height: 0,
num_max_bframes: 0,
supports_yuv444: false,
supports_yuv422: false,
supports_10bit: false,
supports_lossless: false,
supports_lookahead: false,
supports_temporal_aq: false,
supported_ratecontrol_modes: 0,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EncodingProfiles {
H264(Vec<H264EncodingProfile>),
Hevc(Vec<HevcEncodingProfile>),
Av1(Vec<Av1EncodingProfile>),
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum H264EncodingProfile {
Baseline,
Main,
High,
High10,
High422,
High444,
Stereo,
ProgressiveHigh,
ConstrainedHigh,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HevcEncodingProfile {
Main,
Main10,
Frext,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Av1EncodingProfile {
Main,
}
pub fn supported_codecs(device_id: i32) -> Result<Vec<CodecInfo>, Error> {
let _lib = CudaLibrary::load()?;
let codecs = VideoCodecType::all()
.iter()
.map(|&codec| CodecInfo {
codec,
decoding: probe_decoding(codec, device_id),
encoding: probe_encoding(codec, device_id),
})
.collect();
Ok(codecs)
}
fn probe_decoding(codec: VideoCodecType, device_id: i32) -> DecodingInfo {
let decoder_codec = codec.to_decoder_codec();
match Decoder::query_caps(decoder_codec, device_id) {
Ok(caps) => DecodingInfo {
supported: caps.is_supported,
hardware_accelerated: caps.is_supported,
max_width: caps.max_width,
max_height: caps.max_height,
min_width: caps.min_width,
min_height: caps.min_height,
max_mb_count: caps.max_mb_count,
},
Err(_) => DecodingInfo {
supported: false,
hardware_accelerated: false,
max_width: 0,
max_height: 0,
min_width: 0,
min_height: 0,
max_mb_count: 0,
},
}
}
fn probe_encoding(codec: VideoCodecType, device_id: i32) -> EncodingInfo {
let encoder_codec = match codec.to_encoder_codec() {
Some(c) => c,
None => return EncodingInfo::unsupported(),
};
match Encoder::query_caps(encoder_codec, device_id) {
Ok(caps) => {
let supported = caps.width_max > 0;
EncodingInfo {
supported,
hardware_accelerated: supported,
profiles: if supported {
profiles_for_codec(codec)
} else {
EncodingProfiles::None
},
max_width: caps.width_max,
max_height: caps.height_max,
min_width: caps.width_min,
min_height: caps.height_min,
num_max_bframes: caps.num_max_bframes,
supports_yuv444: caps.support_yuv444_encode,
supports_yuv422: caps.support_yuv422_encode,
supports_10bit: caps.support_10bit_encode,
supports_lossless: caps.support_lossless_encode,
supports_lookahead: caps.support_lookahead,
supports_temporal_aq: caps.support_temporal_aq,
supported_ratecontrol_modes: caps.supported_ratecontrol_modes,
}
}
Err(_) => EncodingInfo::unsupported(),
}
}
fn profiles_for_codec(codec: VideoCodecType) -> EncodingProfiles {
match codec {
VideoCodecType::H264 => EncodingProfiles::H264(vec![
H264EncodingProfile::Baseline,
H264EncodingProfile::Main,
H264EncodingProfile::High,
H264EncodingProfile::High10,
H264EncodingProfile::High422,
H264EncodingProfile::High444,
H264EncodingProfile::Stereo,
H264EncodingProfile::ProgressiveHigh,
H264EncodingProfile::ConstrainedHigh,
]),
VideoCodecType::Hevc => EncodingProfiles::Hevc(vec![
HevcEncodingProfile::Main,
HevcEncodingProfile::Main10,
HevcEncodingProfile::Frext,
]),
VideoCodecType::Av1 => EncodingProfiles::Av1(vec![Av1EncodingProfile::Main]),
_ => EncodingProfiles::None,
}
}