use std::os::fd::{AsRawFd, BorrowedFd, OwnedFd, RawFd};
use std::rc::Rc;
use cros_libva::{
Display, ExternalBufferDescriptor, MemoryType, Surface, UsageHint, VA_FOURCC_NV12,
VA_RT_FORMAT_YUV420, VADRMPRIMESurfaceDescriptor,
};
use mediaway_common::{DmaBufDescriptor, NativeHandle};
use crate::EncodeError;
pub(crate) struct DmaBufImportDescriptor {
fourcc: u32,
width: u32,
height: u32,
modifier: u64,
fd0: Option<OwnedFd>,
fd1: Option<OwnedFd>,
planes: [mediaway_common::DmaBufPlane; 2],
plane_count: u8,
}
impl ExternalBufferDescriptor for DmaBufImportDescriptor {
const MEMORY_TYPE: MemoryType = MemoryType::DrmPrime2;
type DescriptorAttribute = VADRMPRIMESurfaceDescriptor;
fn va_surface_attribute(&mut self) -> Self::DescriptorAttribute {
let mut desc = VADRMPRIMESurfaceDescriptor {
fourcc: self.fourcc,
width: self.width,
height: self.height,
num_objects: u32::from(self.fd1.is_some()) + 1,
num_layers: 1,
..Default::default()
};
if let Some(fd0) = &self.fd0 {
desc.objects[0].fd = fd0.as_raw_fd();
desc.objects[0].drm_format_modifier = self.modifier;
}
if let Some(fd1) = &self.fd1 {
desc.objects[1].fd = fd1.as_raw_fd();
desc.objects[1].drm_format_modifier = self.modifier;
}
desc.layers[0].drm_format = self.fourcc;
desc.layers[0].num_planes = u32::from(self.plane_count);
for i in 0..usize::from(self.plane_count) {
let plane = self.planes[i];
desc.layers[0].object_index[i] = u32::from(plane.object_index);
desc.layers[0].offset[i] = plane.offset;
desc.layers[0].pitch[i] = plane.pitch;
}
desc
}
}
pub(crate) fn import_surface(
display: &Rc<Display>,
desc: &DmaBufDescriptor,
width: u32,
height: u32,
) -> Result<Surface<DmaBufImportDescriptor>, EncodeError> {
if desc.fourcc != VA_FOURCC_NV12 {
return Err(EncodeError::InvalidInput);
}
if desc.plane_count == 0 || desc.plane_count > 2 {
return Err(EncodeError::InvalidInput);
}
let fd0 = dup_from_native(desc.fd0)?;
let fd1 = desc.fd1.map(dup_from_native).transpose()?;
let descriptor = DmaBufImportDescriptor {
fourcc: desc.fourcc,
width: desc.width,
height: desc.height,
modifier: desc.modifier,
fd0: Some(fd0),
fd1,
planes: desc.planes,
plane_count: desc.plane_count,
};
let mut surfaces = display
.create_surfaces(
VA_RT_FORMAT_YUV420,
Some(VA_FOURCC_NV12),
width,
height,
Some(UsageHint::USAGE_HINT_ENCODER),
vec![descriptor],
)
.map_err(|_| EncodeError::Backend)?;
let mut surface = surfaces.pop().ok_or(EncodeError::Backend)?;
let held = surface.as_mut();
held.fd0 = None;
held.fd1 = None;
Ok(surface)
}
fn dup_from_native(handle: NativeHandle) -> Result<OwnedFd, EncodeError> {
let bits = handle
.get()
.checked_sub(1)
.ok_or(EncodeError::InvalidInput)?;
let raw = RawFd::try_from(bits).map_err(|_| EncodeError::InvalidInput)?;
let borrowed = unsafe { BorrowedFd::borrow_raw(raw) };
borrowed
.try_clone_to_owned()
.map_err(|_| EncodeError::Backend)
}
#[cfg(test)]
#[path = "dmabuf_tests.rs"]
mod tests;