如何使用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
相关产品推荐
相关产品推荐

