使用Python FFmpeg子进程读取RTMP源时帧垂直滚动问题求助
解决FFmpeg+OpenCV处理RTMP流时画面垂直滚动的问题
这种画面垂直滚动/上下颠倒的问题我碰到过好多次,本质都是FFmpeg输出的原始帧数据和OpenCV的存储行顺序不匹配导致的——FFmpeg默认输出的rawvideo很多时候是采用「从底部行开始存储」的bottom-up格式,而OpenCV则是「从顶部行开始存储」的top-down格式,两者一结合,画面自然就会出现滚动或者上下翻转的情况。下面给你两种直接可行的解决方案,附完整代码:
方案一:让FFmpeg输出匹配OpenCV的格式(推荐)
直接在FFmpeg命令中指定输出为OpenCV原生支持的bgr24像素格式,同时确保帧的行顺序和OpenCV对齐。这样可以避免后续额外的翻转操作,效率更高。
完整代码示例(含显示+推流)
import subprocess import numpy as np import cv2 # ---------------------- 1. 配置FFmpeg读取RTMP流 ---------------------- # 获取流的宽高(用FFprobe自动获取,避免硬编码) ffprobe_cmd = [ 'ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height', '-of', 'csv=p=0', 'rtmp://your-input-stream-url' # 替换成你的输入RTMP地址 ] stream_info = subprocess.check_output(ffprobe_cmd).decode('utf-8').strip() width, height = map(int, stream_info.split(',')) # FFmpeg命令:读取RTMP流,输出BGR24格式的rawvideo到管道 ffmpeg_read_cmd = [ 'ffmpeg', '-i', 'rtmp://your-input-stream-url', '-f', 'rawvideo', '-pix_fmt', 'bgr24', # 匹配OpenCV的BGR格式 '-vcodec', 'rawvideo', '-an', # 忽略音频 '-sn', # 忽略字幕 '-r', '30', # 帧率和输入流保持一致 '-y', 'pipe:1' ] read_process = subprocess.Popen(ffmpeg_read_cmd, stdout=subprocess.PIPE, bufsize=10**8) # ---------------------- 2. 配置FFmpeg推流到RTMP(可选) ---------------------- ffmpeg_push_cmd = [ 'ffmpeg', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', f'{width}x{height}', '-r', '30', '-i', 'pipe:0', '-c:v', 'libx264', '-preset', 'ultrafast', # 推流优先保证实时性 '-f', 'flv', 'rtmp://your-output-stream-url' # 替换成你的输出RTMP地址 ] push_process = subprocess.Popen(ffmpeg_push_cmd, stdin=subprocess.PIPE) # ---------------------- 3. 帧处理循环 ---------------------- while True: # 读取一帧的原始数据:BGR24格式每个像素占3字节,所以总字节数是width*height*3 raw_frame = read_process.stdout.read(width * height * 3) if not raw_frame: break # 流结束 # 转换为OpenCV可用的numpy数组 frame = np.frombuffer(raw_frame, dtype=np.uint8).reshape((height, width, 3)) # ---------------------- 4. 你的业务处理逻辑 ---------------------- # 示例:画一个绿色矩形 cv2.rectangle(frame, (50, 50), (200, 200), (0, 255, 0), 2) # ---------------------- 5. 显示或推流 ---------------------- # 显示画面 cv2.imshow('Processed Stream', frame) # 推流处理后的帧 push_process.stdin.write(frame.tobytes()) # 按Q键退出循环 if cv2.waitKey(1) & 0xFF == ord('q'): break # ---------------------- 清理资源 ---------------------- read_process.terminate() push_process.terminate() cv2.destroyAllWindows()
方案二:在OpenCV中垂直翻转帧(兜底方案)
如果因为某些原因无法修改FFmpeg的输出格式,那可以在拿到OpenCV帧后,直接用cv2.flip()做垂直翻转,解决行顺序不匹配的问题:
# 在转换为numpy数组后添加这一行 frame = cv2.flip(frame, 0) # 参数0表示垂直翻转(上下颠倒)
常见排查要点
- 确认像素格式匹配:FFmpeg输出的像素格式要和OpenCV处理的格式对应(比如OpenCV默认用BGR,不要输出RGB)
- 检查字节数读取正确:确保每次读取的字节数是
width * height * 每个像素的字节数(BGR24是3,YUV420p是1.5) - 帧率同步:推流时指定的帧率要和输入流一致,否则也可能出现画面卡顿或滚动
内容的提问来源于stack exchange,提问作者nkottapalli
相关产品推荐
相关产品推荐

