树莓派中使用FFmpeg同时录制双摄像头的Python脚本故障及画面拼接报错问题
解决树莓派上FFmpeg双摄像头录制的两个问题
让我们一步步拆解并解决你遇到的这两个问题:
问题1:同时启动两个FFmpeg子进程无法正常运行
同时启动两个FFmpeg进程失败,大概率是树莓派的硬件资源限制(USB带宽、CPU性能)或者子进程执行方式导致的,给你几个可行的优化方案:
1. 优化USB带宽与摄像头参数
树莓派的USB总线带宽有限,两个USB摄像头同时高分辨率/高帧率录制很容易占满带宽。你可以:
- 给每个FFmpeg命令添加分辨率和帧率限制,降低资源消耗:
ffmpeg -nostdin -i /dev/video0 -s 640x480 -framerate 15 -c:v copy -an -sn -dn -segment_time 30 -f segment path1/%03d.avi - 如果树莓派有分开的USB接口组(比如USB2和USB3),把两个摄像头插在不同组的接口上,避免带宽冲突。
2. 改进子进程调用方式
你当前用shell=True执行命令,不仅不安全,还可能因为shell解析问题导致意外阻塞。建议改用列表形式传递命令参数,同时处理FFmpeg的输出缓冲区:
import os import datetime import subprocess ROOT_PATH = os.getenv("ROOT_PATH", "/home/pi") ENCODING = os.getenv("ENCODING", "copy") new_dir = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S") RECORDINGS_PATH1 = os.getenv("RECORDINGS_PATH", "RecordingsCam1") RECORDINGS_PATH2 = os.getenv("RECORDINGS_PATH", "RecordingsCam2") recording_path1 = os.path.join(ROOT_PATH, RECORDINGS_PATH1, new_dir) recording_path2 = os.path.join(ROOT_PATH, RECORDINGS_PATH2, new_dir) # 用makedirs并设置exist_ok=True,避免目录已存在报错 os.makedirs(recording_path1, exist_ok=True) os.makedirs(recording_path2, exist_ok=True) segments_path1 = os.path.join(recording_path1, "%03d.avi") segments_path2 = os.path.join(recording_path2, "%03d.avi") # 用列表形式定义命令,避免shell=True的安全隐患与解析问题 cmd1 = [ "ffmpeg", "-nostdin", "-i", "/dev/video0", "-c:v", ENCODING, "-an", "-sn", "-dn", "-segment_time", "30", "-f", "segment", segments_path1, "-loglevel", "error" # 减少日志输出,避免缓冲区阻塞 ] cmd2 = [ "ffmpeg", "-nostdin", "-i", "/dev/video2", "-c:v", ENCODING, "-an", "-sn", "-dn", "-segment_time", "30", "-f", "segment", segments_path2, "-loglevel", "error" ] # 重定向输出到DEVNULL,避免缓冲区满导致进程阻塞 proc1 = subprocess.Popen(cmd1, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) proc2 = subprocess.Popen(cmd2, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # 如果需要等待录制结束,可以添加 proc1.wait() 和 proc2.wait()
3. 降低FFmpeg资源占用
给FFmpeg添加线程限制,避免两个进程抢占过多CPU资源:
# 在cmd1和cmd2末尾添加线程限制参数 cmd1.extend(["-threads", "1"]) cmd2.extend(["-threads", "1"])
问题2:画面并排时出现Filtering and streamcopy cannot be used together报错
这个错误的逻辑很清晰:当使用滤镜(比如hstack/vstack拼接画面)时,不能用-c:v copy参数。因为copy是直接复制原始视频流,不做任何编码处理;而滤镜需要修改视频帧,必须重新编码视频。
解决方案:替换为实际的视频编码器
把-c:v copy改成树莓派支持的编码器,优先用硬件加速编码器(效率更高),比如h264_v4l2m2m,也可以用软件编码器libx264。
这里给你一个双画面并排录制的Python示例:
import os import datetime import subprocess ROOT_PATH = os.getenv("ROOT_PATH", "/home/pi") new_dir = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S") RECORDINGS_PATH = os.getenv("RECORDINGS_PATH", "RecordingsCombined") recording_path = os.path.join(ROOT_PATH, RECORDINGS_PATH, new_dir) os.makedirs(recording_path, exist_ok=True) segments_path = os.path.join(recording_path, "%03d.avi") # 使用hstack滤镜水平拼接两个摄像头画面,用树莓派硬件加速编码 cmd = [ "ffmpeg", "-nostdin", "-i", "/dev/video0", "-i", "/dev/video2", "-filter_complex", "[0:v][1:v]hstack=inputs=2[v]", # hstack水平拼接,vstack为垂直拼接 "-map", "[v]", "-c:v", "h264_v4l2m2m", # 树莓派硬件H.264编码器,大幅降低CPU占用 "-preset", "ultrafast", "-crf", "23", # 控制视频质量,值越小质量越高(18-28是合理范围) "-an", "-sn", "-dn", "-segment_time", "30", "-f", "segment", segments_path, "-loglevel", "error" ] proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
关键说明:
- 如果硬件编码
h264_v4l2m2m出现兼容性问题,可以改用软件编码器libx264,但要保留-preset ultrafast参数提升编码速度。 - 滤镜参数
hstack=inputs=2支持调整拼接比例,比如hstack=inputs=2:shortest=1可以让输出时长和较短的视频流一致。
内容的提问来源于stack exchange,提问作者user11614098
相关产品推荐
相关产品推荐

