如何通过管道实现两个Python脚本间的视频流(连续图像)传递?
程序卡滞的核心原因拆解
- 读取逻辑永久阻塞:
sys.stdin.buffer.read()不带参数调用时,会持续等待管道写入端完全关闭、收到文件结束信号才会返回所有接收内容,不会在每收到一小段数据时提前返回。你在write端加的flush仅作用于写入侧的缓冲区,和接收端的阻塞逻辑没有关系,自然解决不了卡住的问题。 - 缺失帧边界分隔:连续输出的JPEG字节流没有任何标识,接收端无法从连续字节流中区分单张图像的起止位置,就算解决了阻塞问题,也会出现多帧数据拼接解码失败的问题。
- 显示逻辑卡滞:原read.py中
cv2.waitKey(0)是无限等待用户按键的逻辑,每按一次键才会推进一次程序流程,和实时视频的显示需求不匹配。
修复后可直接运行的代码
write.py
import sys import time import cv2 # 提前加载测试图,避免循环内重复读磁盘增加不必要开销 test_img = cv2.imread('cat.jpg') _, encoded_jpg = cv2.imencode('.jpg', test_img) frame_bytes = encoded_jpg.tobytes() while True: sys.stdout.buffer.write(frame_bytes) sys.stdout.flush() time.sleep(1)
read.py
import sys import cv2 import numpy as np # 临时缓冲区存储接收到的字节,依靠JPEG固定标记切分单帧 recv_buffer = b'' while True: # 每次读取固定大小的块,不会触发永久阻塞 chunk = sys.stdin.buffer.read(1024) # 收到写入端的结束信号时退出 if not chunk: break recv_buffer += chunk # 从缓冲区中提取所有完整的JPEG帧 while True: # JPEG帧固定以0xFFD8作为起始标记 start_idx = recv_buffer.find(b'\xff\xd8') if start_idx == -1: # 未匹配到有效帧头,清空残留数据等待下一轮接收 recv_buffer = b'' break # JPEG帧固定以0xFFD9作为结束标记 end_idx = recv_buffer.find(b'\xff\xd9', start_idx) if end_idx == -1: # 尚未攒够完整帧,保留已匹配到的帧头部分等待后续接收 recv_buffer = recv_buffer[start_idx:] break # 提取完整的单帧字节 full_frame = recv_buffer[start_idx:end_idx + 2] # 移除已处理完成的帧数据 recv_buffer = recv_buffer[end_idx + 2:] # 解码并显示画面 decoded_img = cv2.imdecode(np.frombuffer(full_frame, np.uint8), cv2.IMREAD_UNCHANGED) if decoded_img is not None: cv2.imshow('pipe_video_stream', decoded_img) # 短延时刷新窗口,按下q键即可退出程序 if cv2.waitKey(1) & 0xFF == ord('q'): cv2.destroyAllWindows() sys.exit(0)
运行说明
- 直接使用原有的管道命令启动即可:
python3 write.py | python3 read.py - 后续如果需要传输摄像头、视频文件的实时流,只需要将write.py中固定测试图的逻辑替换为从视频源逐帧读取的逻辑,接收端的切帧、解码逻辑完全兼容。
内容的提问来源于stack exchange,提问作者Ivan Viti
相关产品推荐
相关产品推荐

