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

如何通过GObject Introspection在Python中实现GStreamer视频录存MP4

解决GStreamer Python中MP4录存文件损坏及-e参数报错问题

问题根源解析

  1. -e参数报错原因:-e是gst-launch-1.0命令行工具的专属参数,作用是程序退出前自动发送EOS(流结束)事件,让容器封装器(如mp4mux)正确写入文件索引。而Gst.parse_launch()仅解析GStreamer管道语法,不识别命令行参数,所以直接在管道字符串中加入-e会触发语法错误。

  2. MP4文件损坏原因:MP4是带索引的封装格式,必须收到EOS事件才能完成索引写入。去掉-e后,Python程序退出时未主动发送EOS,导致mp4mux来不及写入文件索引,最终生成的文件无有效播放流。


正确实现方案

1. 本地MP4文件源:播放+录存

使用qtdemux解析输入MP4,通过tee分路同时处理播放和录存,必须分开处理视频/音频流,并确保程序结束时发送EOS。

管道字符串

filesrc location=input.mp4 ! qtdemux name=demux
demux.video_0 ! h264parse ! tee name=t
t. ! queue ! avdec_h264 ! autovideosink
t. ! queue ! h264parse ! mp4mux ! filesink location=output.mp4
demux.audio_0 ! aacparse ! faad ! autoaudiosink

2. 摄像头源:实时播放+录存

使用v4l2src读取摄像头数据,编码后分路处理,同样需要处理EOS事件。

管道字符串

v4l2src device=/dev/video0 ! videoconvert ! x264enc bitrate=500000 ! tee name=t
t. ! queue ! autovideosink
t. ! queue ! mp4mux ! filesink location=output.mp4

完整Python代码实现

import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GLib

Gst.init(None)

# 选择要使用的管道:本地文件源/摄像头源
# 本地文件源
pipe_str = """
filesrc location=input.mp4 ! qtdemux name=demux
demux.video_0 ! h264parse ! tee name=t
t. ! queue ! avdec_h264 ! autovideosink
t. ! queue ! h264parse ! mp4mux ! filesink location=output.mp4
demux.audio_0 ! aacparse ! faad ! autoaudiosink
"""

# 摄像头源(取消注释并替换设备路径)
# pipe_str = """
# v4l2src device=/dev/video0 ! videoconvert ! x264enc bitrate=500000 ! tee name=t
# t. ! queue ! autovideosink
# t. ! queue ! mp4mux ! filesink location=output.mp4
# """

pipeline = Gst.parse_launch(pipe_str)
bus = pipeline.get_bus()
bus.add_signal_watch()

loop = GLib.MainLoop()

def on_bus_message(bus, message):
    msg_type = message.type
    if msg_type == Gst.MessageType.EOS:
        print("流处理完成,正在退出...")
        loop.quit()
    elif msg_type == Gst.MessageType.ERROR:
        err, debug_info = message.parse_error()
        print(f"管道错误: {err.message}\n调试信息: {debug_info}")
        loop.quit()
    elif msg_type == Gst.MessageType.STATE_CHANGED:
        if message.src == pipeline:
            old_state, new_state, _ = message.parse_state_changed()
            if new_state == Gst.State.PLAYING:
                print("管道已启动")

bus.connect("message", on_bus_message)

# 启动管道
pipeline.set_state(Gst.State.PLAYING)

try:
    loop.run()
except KeyboardInterrupt:
    print("收到中断信号,正在发送EOS收尾...")
    # 发送EOS事件,让mp4mux完成文件索引写入
    pipeline.send_event(Gst.Event.new_eos())
    loop.run()

# 清理管道
pipeline.set_state(Gst.State.NULL)

关键注意事项

  • EOS事件处理:无论是本地文件播放完成,还是用户手动中断,都必须发送EOS事件并等待管道处理完成,否则mp4mux无法生成完整的MP4文件。
  • 多流处理:本地MP4包含视频和音频流时,需通过qtdemux分别解析并处理,避免流丢失。
  • 队列配置:queue元素用于隔离不同流的处理线程,避免阻塞,可根据需求调整max-size-buffers等参数,但核心还是EOS事件的处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:42:45