如何用GStreamer实现两个VP9 WebM视频的Alpha合成/叠加?
GStreamer视频叠加问题解决:nvcompositor找不到及实现方案
错误原因
nvcompositor是NVIDIA专属的硬件加速GStreamer插件,不属于标准GStreamer默认组件:
- 你没安装NVIDIA的GStreamer硬件加速套件(比如DeepStream SDK、NVIDIA Container Toolkit附带的GStreamer组件);
- 即使装了,也可能没把NVIDIA插件目录加到
GST_PLUGIN_PATH环境变量里,导致GStreamer扫描不到这个元素。
实现视频叠加的两种方案
方案一:用标准GStreamer组件(无N卡也能用)
用通用的compositor元素完成叠加,全程软件处理,兼容性强。流程:文件读取 → VP9解码 → 格式转换 → 合成 → VP9编码 → WebM封装 → 输出
Python代码示例:
import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject Gst.init(None) # 构建管道 pipeline = Gst.Pipeline() # 1. 读取背景视频 bg_src = Gst.ElementFactory.make("filesrc", "bg-src") bg_src.set_property("location", "background.webm") bg_demux = Gst.ElementFactory.make("matroskademux", "bg-demux") bg_vp9_dec = Gst.ElementFactory.make("vp9dec", "bg-vp9-dec") bg_vconvert = Gst.ElementFactory.make("videoconvert", "bg-vconvert") bg_capsfilter = Gst.ElementFactory.make("capsfilter", "bg-caps") bg_capsfilter.set_property("caps", Gst.Caps.from_string("video/x-raw,format=RGBA")) # 2. 读取前景视频(带Alpha通道) fg_src = Gst.ElementFactory.make("filesrc", "fg-src") fg_src.set_property("location", "foreground.webm") fg_demux = Gst.ElementFactory.make("matroskademux", "fg-demux") fg_vp9_dec = Gst.ElementFactory.make("vp9dec", "fg-vp9-dec") fg_vconvert = Gst.ElementFactory.make("videoconvert", "fg-vconvert") fg_capsfilter = Gst.ElementFactory.make("capsfilter", "fg-caps") fg_capsfilter.set_property("caps", Gst.Caps.from_string("video/x-raw,format=RGBA")) # 3. 合成器 compositor = Gst.ElementFactory.make("compositor", "compositor") # 链接背景和前景的pad sink_pad_bg = compositor.get_request_pad("sink_0") src_pad_bg = bg_capsfilter.get_static_pad("src") src_pad_bg.link(sink_pad_bg) sink_pad_fg = compositor.get_request_pad("sink_1") src_pad_fg = fg_capsfilter.get_static_pad("src") src_pad_fg.link(sink_pad_fg) # 4. 编码和封装 vp9_enc = Gst.ElementFactory.make("vp9enc", "vp9-enc") webm_mux = Gst.ElementFactory.make("webmmux", "webm-mux") file_sink = Gst.ElementFactory.make("filesink", "file-sink") file_sink.set_property("location", "foreground_over_background.webm") # 添加所有元素到管道 elements = [bg_src, bg_demux, bg_vp9_dec, bg_vconvert, bg_capsfilter, fg_src, fg_demux, fg_vp9_dec, fg_vconvert, fg_capsfilter, compositor, vp9_enc, webm_mux, file_sink] for elem in elements: pipeline.add(elem) # 链接元素(处理demux的动态pad) Gst.Element.link_many(bg_src, bg_demux) Gst.Element.link_many(bg_vp9_dec, bg_vconvert, bg_capsfilter) Gst.Element.link_many(fg_src, fg_demux) Gst.Element.link_many(fg_vp9_dec, fg_vconvert, fg_capsfilter) Gst.Element.link_many(compositor, vp9_enc, webm_mux, file_sink) # 处理demux的动态pad回调 def pad_added_handler(src, new_pad): if new_pad.get_current_caps().to_string().startswith("video/x-vp9"): sink_pad = bg_vp9_dec.get_static_pad("sink") if src == bg_demux else fg_vp9_dec.get_static_pad("sink") if not sink_pad.is_linked(): new_pad.link(sink_pad) bg_demux.connect("pad-added", pad_added_handler) fg_demux.connect("pad-added", pad_added_handler) # 启动管道 pipeline.set_state(Gst.State.PLAYING) # 等待处理结束 bus = pipeline.get_bus() msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) # 清理资源 pipeline.set_state(Gst.State.NULL)
方案二:用NVIDIA硬件加速组件(有N卡时用)
先确保安装好NVIDIA的GStreamer套件(比如DeepStream SDK,可通过NVIDIA官网下载安装),然后配置环境变量:
export GST_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/gstreamer-1.0:/usr/lib/nvidia/gstreamer-1.0
替换方案一中的解码、转换、合成、编码元素为硬件加速版本,核心代码调整:
# 替换为NVIDIA硬件加速元素 bg_vp9_dec = Gst.ElementFactory.make("nvvp9dec", "bg-vp9-dec") bg_vconvert = Gst.ElementFactory.make("nvvidconv", "bg-vconvert") bg_capsfilter.set_property("caps", Gst.Caps.from_string("video/x-raw(memory:NVMM),format=RGBA")) fg_vp9_dec = Gst.ElementFactory.make("nvvp9dec", "fg-vp9-dec") fg_vconvert = Gst.ElementFactory.make("nvvidconv", "fg-vconvert") fg_capsfilter.set_property("caps", Gst.Caps.from_string("video/x-raw(memory:NVMM),format=RGBA")) compositor = Gst.ElementFactory.make("nvcompositor", "compositor") vp9_enc = Gst.ElementFactory.make("nvvp9enc", "vp9-enc")
关于RTSP Server结合的问题
如果要把合成后的流推到RTSP服务器,只需将输出端的filesink替换为RTSP相关逻辑:
- 用
gst-rtsp-server库构建本地RTSP服务器,将compositor输出的流通过appsink读取后喂给服务器的媒体工厂; - 或者直接用
rtspsink元素将流推送到外部RTSP服务器地址。
内容的提问来源于stack exchange,提问作者OneWorld
相关产品推荐
相关产品推荐

