如何通过GObject Introspection在Python中实现GStreamer视频录存MP4
解决GStreamer Python中MP4录存文件损坏及
-e参数报错问题 问题根源解析
-e参数报错原因:-e是gst-launch-1.0命令行工具的专属参数,作用是程序退出前自动发送EOS(流结束)事件,让容器封装器(如mp4mux)正确写入文件索引。而Gst.parse_launch()仅解析GStreamer管道语法,不识别命令行参数,所以直接在管道字符串中加入-e会触发语法错误。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
相关产品推荐
相关产品推荐

