use std::collections::HashSet;
use std::fmt::Debug;
use std::os::fd::AsRawFd;
use anyhow::anyhow;
use libva::Display;
use libva::VAConfigAttrib;
use libva::VAConfigAttribType;
use crate::utils::DmabufFrame;
use crate::utils::UserPtrFrame;
use crate::DecodedFormat;
pub mod decoder;
pub mod encoder;
pub mod surface_pool;
#[allow(dead_code)]
fn va_rt_format_to_string(va_rt_format: u32) -> String {
String::from(match va_rt_format {
libva::VA_RT_FORMAT_YUV420 => "YUV420",
libva::VA_RT_FORMAT_YUV422 => "YUV422",
libva::VA_RT_FORMAT_YUV444 => "YUV444",
libva::VA_RT_FORMAT_YUV420_10 => "YUV420_10",
libva::VA_RT_FORMAT_YUV420_12 => "YUV420_12",
libva::VA_RT_FORMAT_YUV422_10 => "YUV422_10",
libva::VA_RT_FORMAT_YUV422_12 => "YUV422_12",
libva::VA_RT_FORMAT_YUV444_10 => "YUV444_10",
libva::VA_RT_FORMAT_YUV444_12 => "YUV444_12",
other => return format!("unknown VA rt_format {}", other),
})
}
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
struct FormatMap {
pub rt_format: u32,
pub va_fourcc: u32,
pub decoded_format: DecodedFormat,
}
#[allow(dead_code)]
const FORMAT_MAP: [FormatMap; 10] = [
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV420,
va_fourcc: libva::VA_FOURCC_NV12,
decoded_format: DecodedFormat::NV12,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV420,
va_fourcc: libva::VA_FOURCC_I420,
decoded_format: DecodedFormat::I420,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV422,
va_fourcc: libva::VA_FOURCC_422H,
decoded_format: DecodedFormat::I422,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV444,
va_fourcc: libva::VA_FOURCC_444P,
decoded_format: DecodedFormat::I444,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV420_10,
va_fourcc: libva::VA_FOURCC_P010,
decoded_format: DecodedFormat::I010,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV420_12,
va_fourcc: libva::VA_FOURCC_P012,
decoded_format: DecodedFormat::I012,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV422_10,
va_fourcc: libva::VA_FOURCC_Y210,
decoded_format: DecodedFormat::I210,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV422_12,
va_fourcc: libva::VA_FOURCC_Y212,
decoded_format: DecodedFormat::I212,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV444_10,
va_fourcc: libva::VA_FOURCC_Y410,
decoded_format: DecodedFormat::I410,
},
FormatMap {
rt_format: libva::VA_RT_FORMAT_YUV444_12,
va_fourcc: libva::VA_FOURCC_Y412,
decoded_format: DecodedFormat::I412,
},
];
#[allow(dead_code)]
fn supported_formats_for_rt_format(
display: &Display,
rt_format: u32,
profile: i32,
entrypoint: u32,
image_formats: &[libva::VAImageFormat],
) -> anyhow::Result<HashSet<FormatMap>> {
let mut attrs =
vec![VAConfigAttrib { type_: VAConfigAttribType::VAConfigAttribRTFormat, value: 0 }];
display.get_config_attributes(profile, entrypoint, &mut attrs)?;
if attrs[0].value == libva::VA_ATTRIB_NOT_SUPPORTED || attrs[0].value & rt_format == 0 {
return Err(anyhow!(
"rt_format {:?} not supported for profile {:?} and entrypoint {:?}",
rt_format,
profile,
entrypoint
));
}
let mut supported_formats = HashSet::new();
for format in FORMAT_MAP {
if format.rt_format == rt_format {
supported_formats.insert(format);
}
}
supported_formats
.retain(|&entry| image_formats.iter().any(|fmt| fmt.fourcc == entry.va_fourcc));
Ok(supported_formats)
}
impl TryFrom<&libva::VAImageFormat> for DecodedFormat {
type Error = anyhow::Error;
fn try_from(value: &libva::VAImageFormat) -> Result<Self, Self::Error> {
match value.fourcc {
libva::VA_FOURCC_I420 => Ok(DecodedFormat::I420),
libva::VA_FOURCC_NV12 => Ok(DecodedFormat::NV12),
libva::VA_FOURCC_P010 => Ok(DecodedFormat::I010),
libva::VA_FOURCC_P012 => Ok(DecodedFormat::I012),
libva::VA_FOURCC_Y210 => Ok(DecodedFormat::I210),
libva::VA_FOURCC_Y212 => Ok(DecodedFormat::I212),
libva::VA_FOURCC_Y410 => Ok(DecodedFormat::I410),
libva::VA_FOURCC_Y412 => Ok(DecodedFormat::I412),
_ => Err(anyhow!("Unsupported format")),
}
}
}
impl libva::ExternalBufferDescriptor for UserPtrFrame {
const MEMORY_TYPE: libva::MemoryType = libva::MemoryType::UserPtr;
type DescriptorAttribute = libva::VASurfaceAttribExternalBuffers;
fn va_surface_attribute(&mut self) -> Self::DescriptorAttribute {
let pitches = self
.layout
.planes
.iter()
.map(|p| p.stride as u32)
.chain(std::iter::repeat(0))
.take(4)
.collect::<Vec<_>>()
.try_into()
.unwrap();
let offsets = self
.layout
.planes
.iter()
.map(|p| p.offset as u32)
.chain(std::iter::repeat(0))
.take(4)
.collect::<Vec<_>>()
.try_into()
.unwrap();
libva::VASurfaceAttribExternalBuffers {
pixel_format: self.layout.format.0.into(),
width: self.layout.size.width,
height: self.layout.size.height,
data_size: self.mem_layout.size() as u32,
num_planes: self.layout.planes.len() as u32,
pitches,
offsets,
buffers: self.buffers.as_mut_ptr() as *mut _,
num_buffers: self.buffers.len() as u32,
flags: 0,
private_data: std::ptr::null_mut(),
}
}
}
impl libva::ExternalBufferDescriptor for DmabufFrame {
const MEMORY_TYPE: libva::MemoryType = libva::MemoryType::DrmPrime2;
type DescriptorAttribute = libva::VADRMPRIMESurfaceDescriptor;
fn va_surface_attribute(&mut self) -> Self::DescriptorAttribute {
let objects = self
.fds
.iter()
.map(|fd| libva::VADRMPRIMESurfaceDescriptorObject {
fd: fd.as_raw_fd(),
size: nix::sys::stat::fstat(fd.as_raw_fd())
.map(|stat| stat.st_size as u32)
.unwrap_or(0),
drm_format_modifier: self.layout.format.1,
})
.chain(std::iter::repeat(Default::default()))
.take(4)
.collect::<Vec<_>>()
.try_into()
.unwrap();
let layers = [
libva::VADRMPRIMESurfaceDescriptorLayer {
drm_format: self.layout.format.0.into(),
num_planes: self.layout.planes.len() as u32,
object_index: [0, 0, 0, 0],
offset: self
.layout
.planes
.iter()
.map(|p| p.offset as u32)
.chain(std::iter::repeat(0))
.take(4)
.collect::<Vec<_>>()
.try_into()
.unwrap(),
pitch: self
.layout
.planes
.iter()
.map(|p| p.stride as u32)
.chain(std::iter::repeat(0))
.take(4)
.collect::<Vec<_>>()
.try_into()
.unwrap(),
},
Default::default(),
Default::default(),
Default::default(),
];
libva::VADRMPRIMESurfaceDescriptor {
fourcc: self.layout.format.0.into(),
width: self.layout.size.width,
height: self.layout.size.height,
num_objects: 1,
objects,
num_layers: 1,
layers,
}
}
}