ffmpeg输出管道到Python用cv2.imshow显示画面右移变色问题求助
你的实现思路是正确的,通过ffmpeg硬解码抓屏输出raw帧到管道、再用OpenCV解析显示的方案效率很高,出现的两个问题都是代码细节错误导致的,修复即可。
问题根因
画面滚动重复
你在创建subprocess时设置了stderr=subprocess.STDOUT,会把ffmpeg输出的运行日志也导入到stdout中,和raw视频帧数据混杂。每次你读取w*h*3字节时会读到部分日志内容,导致帧数据错位,自然出现画面偏移、滚动重复的问题。
颜色格式异常
两个常见原因:
- 你使用了已经废弃的
np.fromstring方法处理二进制缓冲区,该方法会优先按字符串规则解析内容,容易破坏raw像素数据的结构 - ffmpeg命令中输出格式指定不严谨,你输出的是无封装的raw视频流,却指定了
-f image2pipe,部分版本ffmpeg会额外插入图片序列的标识数据,破坏像素格式
修复方案
按如下规则修改代码即可:
- 把subprocess的stderr重定向到空设备,不要和stdout混合
- 将ffmpeg命令的
-f image2pipe改为-f rawvideo - 替换
np.fromstring为np.frombuffer专门处理二进制数据 - 增加帧读取长度校验,避免读取到不完整帧时reshape报错
修复后的完整代码:
import cv2 import time import subprocess import numpy as np w,h = 1920, 1080 fps = 15 def ffmpegGrab(): """Generator to read frames from ffmpeg subprocess""" # 替换-f image2pipe为-f rawvideo cmd = f'.\\Resources\\ffmpeg.exe -f gdigrab -framerate {fps} -offset_x 0 -offset_y 0 -video_size {w}x{h} -i desktop -pix_fmt bgr24 -vcodec rawvideo -an -sn -f rawvideo -' # stderr改为重定向到DEVNULL,不混入stdout proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True) frame_size = w*h*3 while True: raw_frame = proc.stdout.read(frame_size) # 加长度校验,读取不完整直接退出或跳过 if len(raw_frame) != frame_size: break # 替换np.fromstring为np.frombuffer frame = np.frombuffer(raw_frame, np.uint8) frame = frame.reshape((h, w, 3)) yield frame # Get frame generator gen = ffmpegGrab() # Get start time start = time.time() # Read video frames from ffmpeg in loop nFrames = 0 while True: # Read next frame from ffmpeg try: frame = next(gen) except StopIteration: break nFrames += 1 frame = cv2.resize(frame, (w // 4, h // 4)) cv2.imshow('screenshot', frame) if cv2.waitKey(1) == ord("q"): break fps = nFrames/(time.time()-start) print(f'FPS: {fps}') cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

