feat: Implement Wayland DMA-BUF to VAAPI zero-copy encode via AVDRMFrameDescriptor

This commit is contained in:
katR 2026-09-01 20:29:36 +05:30
parent e423f742b3
commit ad509c439b

View file

@ -140,8 +140,66 @@ impl VaapiEncoder {
av_frame_free(&mut nv12_frame);
av_frame_free(&mut bgra_frame);
}
Frame::DmaBuf { width: _, height: _, format: _, fd, stride: _, offset: _ } => {
println!("VAAPI: Mock encoding DMA-BUF frame (Wayland zero-copy). FD: {}", fd);
Frame::DmaBuf { width: dma_width, height: dma_height, format, fd, stride, offset } => {
let mut drm_desc = AVDRMFrameDescriptor {
nb_objects: 1,
objects: [AVDRMObjectDescriptor {
fd: *fd,
size: 0, // usually ignored or mapped by driver
format_modifier: 0, // DRM_FORMAT_MOD_LINEAR (or read from PipeWire format)
}, std::mem::zeroed(), std::mem::zeroed(), std::mem::zeroed()],
nb_layers: 1,
layers: [AVDRMLayerDescriptor {
format: *format,
nb_planes: 1,
planes: [AVDRMPlaneDescriptor {
object_index: 0,
offset: *offset as isize,
pitch: *stride as isize,
}, std::mem::zeroed(), std::mem::zeroed(), std::mem::zeroed()],
}, std::mem::zeroed(), std::mem::zeroed(), std::mem::zeroed()],
};
let mut drm_frame = av_frame_alloc();
(*drm_frame).format = AVPixelFormat::AV_PIX_FMT_DRM_PRIME as i32;
(*drm_frame).width = *dma_width as i32;
(*drm_frame).height = *dma_height as i32;
(*drm_frame).data[0] = &mut drm_desc as *mut _ as *mut u8;
let mut hw_frame = av_frame_alloc();
(*hw_frame).format = AVPixelFormat::AV_PIX_FMT_VAAPI as i32;
// Map the DRM frame to VAAPI
// Since it's hardware mapping, av_hwframe_map expects the device context or frames context.
// Wait, av_hwframe_map uses the destination's hw_frames_ctx if we preallocate, OR
// if we just pass a device context to hw_frame.hw_frames_ctx?
// Let's allocate the hw_frame from our VAAPI frames context.
let ret = av_hwframe_get_buffer(self.hw_frames_ctx, hw_frame, 0);
if ret >= 0 {
let map_ret = av_hwframe_map(hw_frame, drm_frame, 0);
if map_ret >= 0 {
(*hw_frame).pts = self.next_pts;
self.next_pts += 1;
if avcodec_send_frame(self.codec_ctx, hw_frame) >= 0 {
let mut pkt = av_packet_alloc();
while avcodec_receive_packet(self.codec_ctx, pkt) >= 0 {
let new_pkt = av_packet_alloc();
av_packet_move_ref(new_pkt, pkt);
packets.push(crate::ring::Packet::new(new_pkt));
}
av_packet_free(&mut pkt);
}
} else {
eprintln!("Failed to map DRM prime to VAAPI: {}", map_ret);
}
}
// For AV_PIX_FMT_DRM_PRIME, we don't own the data, so don't av_frame_unref the data buffer,
// av_frame_free is safe because data[0] wasn't allocated by ffmpeg.
// Wait, av_frame_free will try to free data[0] if buf[0] is set. But we didn't set buf[0].
av_frame_free(&mut hw_frame);
av_frame_free(&mut drm_frame);
}
#[cfg(target_os = "windows")]
Frame::D3D11Texture { handle } => {