GStreamer:如何设置videoconvert输出格式及视频帧编辑问题
解决方案:GStreamer视频帧编辑(无OpenCV)
核心问题分析
- 格式协商优先级问题:
autovideosink会主动协商自身支持的视频格式(如YV12),导致videoconvert直接输出该格式而非你期望的RGB——原流水线中没有强制RGB的环节,格式协商完全由sink主导。 - 事件顺序错误:
Sticky event misordering是因为caps协商时机不当,在stream-start事件前就触发了caps事件,通常是因为probe添加过早或caps未提前约束。
修正后的流水线
filesrc -> decodebin -> videoconvert(转RGB前) -> capsfilter(强制RGB) -> [Pad Probe处理帧] -> videoconvert(转sink兼容格式) -> autovideosink
关键实现步骤
1. 强制RGB格式
在第一个videoconvert后添加capsfilter,明确指定输出RGB格式:
caps = video/x-raw, format=RGB, width=[ANY], height=[ANY], framerate=[ANY]
这一步确保帧处理环节拿到的是标准RGB数据,方便直接编辑像素。
2. 拆分格式转换
用两个videoconvert:
- 第一个负责将解码后的任意原始格式(如I420)转成RGB
- 第二个负责将处理后的RGB转成
autovideosink支持的格式(如YV12),彻底解决caps不兼容问题
3. 正确添加Pad Probe
在capsfilter的src pad上添加probe——此时caps已固定为RGB,不会出现事件顺序混乱,且能保证处理的帧都是RGB格式。
完整代码示例(Python)
import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject Gst.init(None) def on_decodebin_pad_added(decodebin, pad): # 仅处理视频pad if not pad.has_current_caps(): return caps_str = pad.get_current_caps().to_string() if caps_str.startswith('video/x-raw'): videoconvert1 = pipeline.get_by_name('videoconvert1') pad.link(videoconvert1.get_static_pad('sink')) def edit_rgb_frame(pad, info): buf = info.get_buffer() caps = pad.get_current_caps() struct = caps.get_structure(0) # 确认当前格式为RGB if struct.get_string('format') != 'RGB': return Gst.PadProbeReturn.OK width = struct.get_int('width')[1] height = struct.get_int('height')[1] # 映射缓冲区获取可写像素数据 success, map_info = buf.map(Gst.MapFlags.WRITE) if not success: return Gst.PadProbeReturn.OK # 示例:绘制左上角10x10到100x100的红色矩形 for y in range(10, 100): if y >= height: break row_start = y * width * 3 for x in range(10, 100): if x >= width: break pixel_offset = row_start + x * 3 map_info.data[pixel_offset] = 255 # 红色通道 map_info.data[pixel_offset + 1] = 0 # 绿色通道 map_info.data[pixel_offset + 2] = 0 # 蓝色通道 buf.unmap(map_info) return Gst.PadProbeReturn.OK # 创建流水线及元素 pipeline = Gst.Pipeline.new('video-editor') filesrc = Gst.ElementFactory.make('filesrc', 'filesrc') filesrc.set_property('location', 'your-video-file.mp4') # 替换为你的视频路径 decodebin = Gst.ElementFactory.make('decodebin', 'decodebin') decodebin.connect('pad-added', on_decodebin_pad_added) videoconvert1 = Gst.ElementFactory.make('videoconvert', 'videoconvert1') capsfilter = Gst.ElementFactory.make('capsfilter', 'rgb-caps') rgb_caps = Gst.Caps.from_string('video/x-raw, format=RGB, width=[ANY], height=[ANY], framerate=[ANY]') capsfilter.set_property('caps', rgb_caps) videoconvert2 = Gst.ElementFactory.make('videoconvert', 'videoconvert2') autovideosink = Gst.ElementFactory.make('autovideosink', 'videosink') # 添加元素到流水线 for elem in [filesrc, decodebin, videoconvert1, capsfilter, videoconvert2, autovideosink]: pipeline.add(elem) # 链接元素 filesrc.link(decodebin) videoconvert1.link(capsfilter) capsfilter.link(videoconvert2) videoconvert2.link(autovideosink) # 为capsfilter的src pad添加帧处理probe caps_src_pad = capsfilter.get_static_pad('src') caps_src_pad.add_probe(Gst.PadProbeType.BUFFER, edit_rgb_frame) # 启动流水线 pipeline.set_state(Gst.State.PLAYING) # 运行主循环 loop = GObject.MainLoop() try: loop.run() except KeyboardInterrupt: pass # 清理资源 pipeline.set_state(Gst.State.NULL)
错误修复说明
- caps不接受问题:通过第二个
videoconvert将处理后的RGB转换为sink支持的格式,避免直接向sink推送不兼容的RGB帧。 - 事件顺序错误:
capsfilter强制RGB格式后,srcpad的caps提前固定,probe在caps协商完成后添加,确保stream-start事件先于caps事件触发。
内容的提问来源于stack exchange,提问作者CmykCmyk
相关产品推荐
相关产品推荐

