diff --git a/src/encoder.rs b/src/encoder.rs index bb55011..c8e861e 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -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 } => {