You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过subprocess调用FFmpeg报错:pipe:: Invalid data found when processing input

解决FFmpeg管道输入报错"pipe:: Invalid data found when processing input"的问题

嘿,作为刚接触FFmpeg的新手,遇到这个问题太正常了!咱们先拆解下错误原因:你直接把OpenCV读取的裸BGR像素帧塞给了FFmpeg,但FFmpeg根本不知道怎么解析这种无格式的原始数据——它需要明确知道输入的视频格式、像素格式、分辨率这些信息才行。另外你的代码还有几个逻辑错误,咱们一步步改:

你的代码里的核心问题

  1. proc.communicate()是致命错误:这个方法会一次性给FFmpeg喂完所有输入,然后等待进程结束,还会自动关闭stdin/stdout,导致后面的循环完全没法正常喂帧。
  2. 裸帧数据不被FFmpeg识别:frame.tostring()输出的是OpenCV默认的BGR格式裸像素,FFmpeg没有收到任何格式说明,自然会报错"无效数据"。
  3. 循环里重复关闭管道/等待进程:每次循环都调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:42:42