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

如何使用GStreamer实现帧中矩形透明以显示下层DRM图层?

实现局部矩形透明的解决方案

1. 先确保视频流支持Alpha通道

透明效果依赖Alpha通道,所以必须让管线处理带Alpha的像素格式(比如RGBA)。给每一路解码后的视频流添加videoconvert,强制转换为RGBA格式再送入compositor:

udpsrc -> rtpdepay -> decoder -> videoconvert ! video/x-raw,format=RGBA -> compositor.sink_0
udpsrc -> rtpdepay -> decoder -> videoconvert ! video/x-raw,format=RGBA -> compositor.sink_1
# 其他多路流同理

同时保证compositor的输出格式为RGBA,后续连接到处理步骤再到kmssink。

2. 添加局部透明处理逻辑

有两种实用方式可以在合成后的帧上创建透明矩形:

方式一:自定义C++滤镜元素

因为你用C++开发,直接写一个GStreamer基础滤镜,修改帧像素数据的Alpha通道:
核心代码片段(简化实现):

GstFlowReturn filter_frame(GstBaseTransform *trans, GstBuffer *buf) {
  GstMapInfo map;
  if (!gst_buffer_map(buf, &map, GST_MAP_WRITE)) {
    gst_buffer_unref(buf);
    return GST_FLOW_ERROR;
  }

  GstVideoInfo info;
  gst_video_info_from_caps(&info, gst_base_transform_get_pad_caps(trans, GST_PAD_SINK));
  
  // 自定义透明矩形参数:x起始坐标、y起始坐标、宽度、高度
  const int rect_x = 100, rect_y = 100, rect_w = 200, rect_h = 200;
  // 确保矩形不超出帧范围
  const int clamp_x = CLAMP(rect_x, 0, info.width);
  const int clamp_y = CLAMP(rect_y, 0, info.height);
  const int clamp_w = CLAMP(rect_w, 0, info.width - clamp_x);
  const int clamp_h = CLAMP(rect_h, 0, info.height - clamp_y);

  guint8 *frame_data = map.data;
  const int stride = info.stride[0]; // RGBA每行的字节数

  for (int row = clamp_y; row < clamp_y + clamp_h; row++) {
    guint8 *row_ptr = frame_data + row * stride + clamp_x * 4; // 跳转到目标行的起始像素
    for (int col = 0; col < clamp_w; col++) {
      row_ptr[3] = 0; // 将Alpha通道设为0(完全透明)
      row_ptr += 4; // 移动到下一个RGBA像素
    }
  }

  gst_buffer_unmap(buf, &map);
  return gst_base_transform_push_frame(trans, buf);
}

把这个自定义滤镜插入到compositor之后、videoconvert之前:

compositor -> custom_alpha_filter -> videoconvert -> kmssink

方式二:用glfiltercustom实现(无需编译自定义代码)

如果不想写自定义滤镜,可用GStreamer的glfiltercustom元素,通过GLSL着色器实现局部透明:
管线中添加该元素:

compositor -> glfiltercustom ! shader="你的GLSL片段着色器代码" -> videoconvert -> kmssink

对应的GLSL片段着色器:

#version 120
uniform sampler2D tex;
uniform vec2 frame_size; // 视频帧的宽高,比如vec2(1920,1080)
uniform vec4 rect_params; // 透明矩形参数:x, y, width, height(像素值)

void main() {
  vec2 uv = gl_TexCoord[0].st;
  vec4 pixel_color = texture2D(tex, uv);
  
  // 将UV坐标转换为像素坐标
  vec2 pixel_pos = uv * frame_size;
  bool is_in_rect = (pixel_pos.x >= rect_params.x) && (pixel_pos.x <= rect_params.x + rect_params.z) &&
                    (pixel_pos.y >= rect_params.y) && (pixel_pos.y <= rect_params.y + rect_params.w);
  
  if (is_in_rect) {
    pixel_color.a = 0.0; // 设置为完全透明
  }
  
  gl_FragColor = pixel_color;
}

在C++代码中,通过g_object_set给glfiltercustom传递参数:

// 假设帧大小是1920x1080,矩形是(100,100)到(300,300)
g_object_set(glfiltercustom, 
             "frame-size", g_value_new_vec2(1920.0f, 1080.0f),
             "rect-params", g_value_new_vec4(100.0f, 100.0f, 200.0f, 200.0f),
             NULL);

3. 配置kmssink支持透明

必须开启kmssink的Alpha混合模式,否则透明区域会显示为黑色:

g_object_set(kmssink, "alpha-mode", "blend", NULL);

注意:需要你的DRM硬件支持平面Alpha混合,现代主流GPU都支持该特性。

关键注意点

  • 所有进入compositor的视频流必须是RGBA格式,否则无法处理Alpha通道
  • 透明矩形的坐标和大小要根据实际屏幕分辨率调整,避免超出帧范围
  • 使用glfiltercustom需要确保GStreamer安装了gst-plugins-gl插件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 07:57:36