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

GStreamer:如何设置videoconvert输出格式及视频帧编辑问题

解决方案:GStreamer视频帧编辑(无OpenCV)

核心问题分析

  1. 格式协商优先级问题:autovideosink会主动协商自身支持的视频格式(如YV12),导致videoconvert直接输出该格式而非你期望的RGB——原流水线中没有强制RGB的环节,格式协商完全由sink主导。
  2. 事件顺序错误: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格式后,src pad的caps提前固定,probe在caps协商完成后添加,确保stream-start事件先于caps事件触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:43:18