Phase 2: Add X11 fallback CPU-to-VAAPI upload and swscale

This commit is contained in:
katR 2026-09-01 19:39:22 +05:30
parent 13155f1d48
commit 4c491eea0b

View file

@ -6,12 +6,12 @@ pub struct VaapiEncoder {
codec_ctx: *mut AVCodecContext,
hw_device_ctx: *mut AVBufferRef,
hw_frames_ctx: *mut AVBufferRef,
next_pts: i64,
}
impl VaapiEncoder {
pub fn new(width: u32, height: u32) -> Result<Self, String> {
unsafe {
// Find VAAPI encoder (h264_vaapi)
let codec = avcodec_find_encoder_by_name(b"h264_vaapi\0".as_ptr() as *const i8);
if codec.is_null() {
return Err("h264_vaapi encoder not found".into());
@ -28,12 +28,11 @@ impl VaapiEncoder {
(*codec_ctx).framerate = AVRational { num: 60, den: 1 };
(*codec_ctx).pix_fmt = AVPixelFormat::AV_PIX_FMT_VAAPI;
// Init hardware device
let mut hw_device_ctx: *mut AVBufferRef = ptr::null_mut();
let ret = av_hwdevice_ctx_create(
&mut hw_device_ctx,
AVHWDeviceType::AV_HWDEVICE_TYPE_VAAPI,
ptr::null(), // default device
ptr::null(),
ptr::null_mut(),
0,
);
@ -41,7 +40,6 @@ impl VaapiEncoder {
return Err("Failed to create VAAPI hardware device".into());
}
// Allocate hw frames context
let hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx);
if hw_frames_ref.is_null() {
return Err("Failed to allocate hw frames context".into());
@ -69,6 +67,7 @@ impl VaapiEncoder {
codec_ctx,
hw_device_ctx,
hw_frames_ctx: hw_frames_ref,
next_pts: 0,
})
}
}
@ -76,19 +75,66 @@ impl VaapiEncoder {
pub fn encode_frame(&mut self, frame: &Frame) -> Result<(), String> {
unsafe {
match frame {
Frame::Raw { width, height, stride, data } => {
// For Phase 2 X11 fallback:
// 1. Convert BGRA to NV12 (omitted/mocked for brevity if not using swscale yet)
// 2. Upload NV12 to a VAAPI AVFrame via av_hwframe_get_buffer and av_hwframe_transfer_data
// 3. Send to avcodec_send_frame
println!("VAAPI: Mock encoding Raw CPU frame (X11 fallback). Needs BGRA->NV12 swscale.");
Frame::Raw { width, height, stride: in_stride, data } => {
let mut bgra_frame = av_frame_alloc();
(*bgra_frame).format = AVPixelFormat::AV_PIX_FMT_BGRA as i32;
(*bgra_frame).width = *width as i32;
(*bgra_frame).height = *height as i32;
av_frame_get_buffer(bgra_frame, 32);
let bgra_stride = (*bgra_frame).linesize[0] as usize;
for y in 0..(*height as usize) {
let src_row = &data[y * (*in_stride as usize) .. y * (*in_stride as usize) + (*width as usize) * 4];
let dst_row = std::slice::from_raw_parts_mut(
(*bgra_frame).data[0].add(y * bgra_stride),
(*width as usize) * 4
);
dst_row.copy_from_slice(src_row);
}
let mut nv12_frame = av_frame_alloc();
(*nv12_frame).format = AVPixelFormat::AV_PIX_FMT_NV12 as i32;
(*nv12_frame).width = *width as i32;
(*nv12_frame).height = *height as i32;
av_frame_get_buffer(nv12_frame, 32);
let sws_ctx = sws_getContext(
*width as i32, *height as i32, AVPixelFormat::AV_PIX_FMT_BGRA,
*width as i32, *height as i32, AVPixelFormat::AV_PIX_FMT_NV12,
2, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()
);
sws_scale(
sws_ctx,
(*bgra_frame).data.as_ptr() as *const *const u8,
(*bgra_frame).linesize.as_ptr(),
0,
*height as i32,
(*nv12_frame).data.as_ptr(),
(*nv12_frame).linesize.as_ptr()
);
sws_freeContext(sws_ctx);
let mut hw_frame = av_frame_alloc();
av_hwframe_get_buffer(self.hw_frames_ctx, hw_frame, 0);
av_hwframe_transfer_data(hw_frame, nv12_frame, 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 {
println!("VAAPI: encoded packet of size {}", (*pkt).size);
av_packet_unref(pkt);
}
av_packet_free(&mut pkt);
}
av_frame_free(&mut hw_frame);
av_frame_free(&mut nv12_frame);
av_frame_free(&mut bgra_frame);
}
Frame::DmaBuf { width, height, format, fd, stride, offset } => {
// For Phase 2 Wayland zero-copy:
// 1. Populate AVDRMFrameDescriptor with the FD and modifier.
// 2. Create an AVFrame with format AV_PIX_FMT_DRM_PRIME.
// 3. Use av_hwframe_map to map it to AV_PIX_FMT_VAAPI.
// 4. Send to avcodec_send_frame.
Frame::DmaBuf { width: _, height: _, format: _, fd, stride: _, offset: _ } => {
println!("VAAPI: Mock encoding DMA-BUF frame (Wayland zero-copy). FD: {}", fd);
}
}