You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GStreamer中通过零拷贝将DMABuf帧编码为视频流?

问题描述

通过Intel i915驱动的ioctl VFIO_DEVICE_QUERY_GFX_PLANE拿到了带帧缓冲区的dmabuf文件描述符,想在GStreamer里用零拷贝方式把它编码成H.264、H.265这类视频流,目前是用appsrc把单帧推送到管道里。考虑到用Intel硬件,选VAAPI是合理的,但VAAPI的sink pad只支持video/x-raw和video/x-raw(memory:VASurface)格式,而我手里的是video/x-raw(memory:DMABuf)格式。

想问两个问题:

  1. 有没有零拷贝的方法把video/x-raw(memory:DMABuf)转成video/x-raw(memory:VASurface),或者直接把DMABuf导入成video/x-raw(memory:VASurface)?
  2. 有没有比VAAPI更合适的框架?

当前推送帧的代码:

GstMemory* mem = gst_dmabuf_allocator_alloc(vedpy->gdata.allocator, dmabuf->fd, dmabuf->width * dmabuf->height * (dmabuf->stride/1024));
vedpy->gdata.buffer = gst_buffer_new();
gst_buffer_append_memory(vedpy->gdata.buffer, mem );

gsize offset[GST_VIDEO_MAX_PLANES] = {0, 0, 0, 0};
gint stride[GST_VIDEO_MAX_PLANES] = {dmabuf->stride, 0, 0, 0};
gst_buffer_add_video_meta_full( vedpy->gdata.buffer, GST_VIDEO_FRAME_FLAG_NONE,
                                GST_VIDEO_FORMAT_ENCODED,
                                dmabuf->width, dmabuf->height, 1, offset, stride);
GstFlowReturn ret;
vfio_encode_dpy *vedpy = container_of(dcl, vfio_encode_dpy, dcl);
g_signal_emit_by_name (vedpy->gdata.source, "push-buffer", vedpy->gdata.buffer, &ret);

当前管道代码:

char launch_stream[]  = "appsrc name=source ! "
    " video/x-raw(memory:DMABuf),width=1024,height=768,framerate=0/1,format={BGRx,BGRx:0x0100000000000001} ! "
    " vaapipostproc !"
    " vaapih265enc ! 
    ...

显然这个管道跑不起来,因为vaapipostproc没法和前一个元素链接。

解决方案

一、零拷贝转换DMABuf到VASurface

GStreamer的VAAPI插件里有vaapidmabufupload元素,专门用来做DMABuf到VAAPI VASurface的零拷贝上传——它直接复用DMABuf的内存,不需要额外数据拷贝,完美解决格式不兼容的问题。

修改后的管道代码如下:

char launch_stream[]  = "appsrc name=source ! "
    " video/x-raw(memory:DMABuf),width=1024,height=768,framerate=0/1,format=BGRx ! "
    " vaapidmabufupload ! "
    " vaapih265enc ! "
    ...

注意:要确保你的GStreamer VAAPI插件版本在1.18以上,这个元素是较新版本才加入的。

另外,你推送帧的代码里有个错误:GST_VIDEO_FORMAT_ENCODED是给编码后帧用的,你推送的是原始帧,应该改成对应原始格式,比如GST_VIDEO_FORMAT_BGRx,修正后这部分代码:

gst_buffer_add_video_meta_full( vedpy->gdata.buffer, GST_VIDEO_FRAME_FLAG_NONE,
                                GST_VIDEO_FORMAT_BGRx, // 替换为实际的原始格式
                                dmabuf->width, dmabuf->height, 1, offset, stride);

二、替代VAAPI的框架

如果VAAPI不符合你的需求,还有两个靠谱的选择:

  • oneVPL(原Intel Media SDK):Intel官方的媒体处理SDK,对自家硬件优化更彻底,支持DMABuf直接导入,配套的GStreamermsdk系列插件(比如msdkh265enc)也支持零拷贝。管道可以改成:
    char launch_stream[]  = "appsrc name=source ! "
        " video/x-raw(memory:DMABuf),width=1024,height=768,framerate=0/1,format=BGRx ! "
        " msdkupload ! "
        " msdkh265enc ! "
        ...
    
  • FFmpeg + libva:直接用FFmpeg的底层API处理,通过av_hwframe_ctx_create_derived把DMABuf导入到VAAPI上下文后再编码,这种方式更灵活,适合定制化需求较多的场景。

额外注意点

  • 确认DMABuf的格式是VAAPI/oneVPL支持的,BGRx属于兼容格式,如果是特殊格式可能需要提前处理,但vaapidmabufupload和msdkupload都能处理大部分常见格式的零拷贝转换。
  • 确保GStreamer进程有权限访问DMABuf的文件描述符,避免权限不足导致的失败。
  • 推送帧时记得设置正确的时间戳,不然编码后的视频可能出现播放卡顿、时序混乱等问题。

内容的提问来源于stack exchange,提问作者Xaterus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:41:45