通过subprocess调用FFmpeg报错:pipe:: Invalid data found when processing input
解决FFmpeg管道输入报错"pipe:: Invalid data found when processing input"的问题
嘿,作为刚接触FFmpeg的新手,遇到这个问题太正常了!咱们先拆解下错误原因:你直接把OpenCV读取的裸BGR像素帧塞给了FFmpeg,但FFmpeg根本不知道怎么解析这种无格式的原始数据——它需要明确知道输入的视频格式、像素格式、分辨率这些信息才行。另外你的代码还有几个逻辑错误,咱们一步步改:
你的代码里的核心问题
proc.communicate()是致命错误:这个方法会一次性给FFmpeg喂完所有输入,然后等待进程结束,还会自动关闭stdin/stdout,导致后面的循环完全没法正常喂帧。- 裸帧数据不被FFmpeg识别:
frame.tostring()输出的是OpenCV默认的BGR格式裸像素,FFmpeg没有收到任何格式说明,自然会报错"无效数据"。 - 循环里重复关闭管道/等待进程:每次循环都调用
proc.stdin.close()和proc.wait(),直接把FFmpeg进程关掉了,后续帧根本发不出去。
修正后的完整代码
import cv2 import subprocess import threading def read_ffmpeg_stderr(proc): # 开线程读取FFmpeg的stderr,避免缓冲区满导致进程阻塞 for line in iter(proc.stderr.readline, b''): print(f"FFmpeg stderr: {line.decode('utf-8').strip()}") # 1. 初始化视频捕获 cap = cv2.VideoCapture("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov") # 获取原视频的分辨率和帧率(也可以手动指定) frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = int(cap.get(cv2.CAP_PROP_FPS)) or 30 # 防止获取失败用默认30 # 2. 修改FFmpeg命令:明确指定输入为RAW视频,像素格式是BGR24(OpenCV的帧格式) command = [ "ffmpeg", # 输入参数:告诉FFmpeg输入是RAW视频,像素格式BGR24,分辨率、帧率 "-f", "rawvideo", "-pix_fmt", "bgr24", "-s", f"{frame_width}x{frame_height}", "-r", str(fps), "-i", "-", # 从stdin读取 # 输出参数:保持你原来的设置 "-f", "mpegts", "-vcodec", "mpeg1video", "-s", "960x540", "-b:v", "1000K", "-r", "30", "-bf", "0", "-codec:a", "mp2", # 注意:这里如果你的输出URL需要音频,但原RTSP流可能没有音频,FFmpeg会报错,后面说解决办法 "http://127.0.0.1:8888/yoursecret", "-y" # 覆盖输出(如果需要的话) ] # 3. 启动FFmpeg进程,不要用communicate proc = subprocess.Popen( command, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=10**8 # 设置大缓冲区避免频繁IO阻塞 ) # 启动线程读取FFmpeg的stderr,防止缓冲区满卡死 stderr_thread = threading.Thread(target=read_ffmpeg_stderr, args=(proc,)) stderr_thread.daemon = True stderr_thread.start() try: while True: ret, frame = cap.read() if not ret: print("视频流读取结束或出错") break # 把BGR帧的字节数据写给FFmpeg的stdin proc.stdin.write(frame.tobytes()) # 可选:刷新缓冲区,确保数据立即发送 proc.stdin.flush() # print("帧已发送") except KeyboardInterrupt: print("用户中断程序") finally: # 清理资源 cap.release() proc.stdin.close() proc.wait() print("进程已关闭")
额外注意事项
- 音频问题:如果你的原RTSP流没有音频,但FFmpeg输出要求音频(比如你指定了
mp2音频编码),FFmpeg会报错。解决办法是在FFmpeg命令里加上-an参数(禁用音频),或者如果需要音频,可以添加一个静音音频流(比如用-f lavfi -i anullsrc)。 - 帧率和分辨率匹配:尽量让输入的帧率/分辨率和FFmpeg的设置匹配,避免不必要的转码开销。
- 缓冲区设置:设置较大的
bufsize可以减少IO阻塞,提升实时性。
内容的提问来源于stack exchange,提问作者mamba9999
相关产品推荐
相关产品推荐

