Python中如何将树莓派摄像头输出管道分流给两个不同进程使用
问题原因
管道是Linux下的单向字节流对象,多个进程同时读取同一个管道时,数据会被随机拆分分配给不同读取进程,两个进程都无法拿到完整的视频流数据,因此你当前的写法无法正常运行。
解决方案
Python中可以通过自定义分流线程实现类似tee的功能,将单个输入流复制分发到多个输出流,方案逻辑如下:
实现代码示例
import subprocess from subprocess import Popen import threading # 分流工作函数:从源输入流读数据,同时写入多个目标输出流 def tee_worker(source, *targets): try: while True: # 按合适的块大小读数据,这里设为4096,可根据单帧大小调整 data = source.read(4096) if not data: break # 复制写入所有目标流 for t in targets: try: t.write(data) t.flush() # 实时刷入避免缓冲延迟 except BrokenPipeError: # 对应进程已退出,可按需处理 pass finally: # 退出时关闭所有流 source.close() for t in targets: try: t.close() except: pass # 1. 启动 raspivid 采集进程,和你原有逻辑一致 width, height, fps, video_bitrate, keyframerate = 1280,720,30, 2000000, 30 extraparams = "" raspivid_comm = ["raspivid", "-w", str(width), "-h", str(height), "-fps", str(fps), "-b", str(video_bitrate), "-g", str(keyframerate), "-t", "0"] raspivid_comm.extend(extraparams.split()) raspivid_comm.extend(["-o", "-"]) raspivid_task = Popen(raspivid_comm, stdout=subprocess.PIPE, stdin=None, stderr=None, close_fds=True, shell=False, bufsize=4096) # 调整bufsize匹配读取块大小 # 2. 启动两个下游进程,注意stdin设置为PIPE,不再直接绑定raspivid的stdout send_task = Popen(send_via_rf, stdout=None, stdin=subprocess.PIPE, stderr=None, close_fds=True, shell=False, bufsize=4096) improc_task = Popen(improc, stdout=None, stdin=subprocess.PIPE, stderr=None, close_fds=True, shell=False, bufsize=4096) # 3. 启动分流线程,完成流复制 tee_thread = threading.Thread(target=tee_worker, args=(raspivid_task.stdout, send_task.stdin, improc_task.stdin), daemon=True) tee_thread.start()
注意事项
- 可以根据实际单帧视频大小调整读取块大小,降低IO次数提升性能
- 如果某一个下游进程处理速度远慢于采集速度,可以在分流逻辑中添加丢帧逻辑,避免缓冲区积压导致实时性下降
- 进程退出时建议按顺序停止:先停采集进程,等待分流线程读完剩余数据,再停止两个下游进程,避免出现僵尸进程
内容的提问来源于stack exchange,提问作者hex0r
相关产品推荐
相关产品推荐

