feat: Implement Wayland DMA-BUF to VAAPI zero-copy encode via AVDRMFrameDescriptor
This commit is contained in:
parent
e423f742b3
commit
ad509c439b
1 changed files with 60 additions and 2 deletions
|
|
@ -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 } => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue