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

如何将BGR NumPy数组直接传入支持CUDA的FFMPEG处理

实现方案

ffmpeg-python 参数传递规则

FFMPEG命令参数按执行位置分为三类,对应ffmpeg-python不同传参入口:

  • 全局参数:位于输入源参数(-i)之前的配置,如硬件加速、自动覆盖输出等,通过.global_args()方法按顺序传入
  • 输入参数:绑定到对应输入源的配置,如帧率、输入格式、分辨率、像素格式等,直接作为.input()的关键字参数传入,参数名把原命令中的中划线替换为下划线即可
  • 输出参数:编码、滤镜、码率、质量等输出相关配置,直接作为.output()的关键字参数传入,规则同输入参数;无值的开关型参数传None即可
  • 自定义FFMPEG二进制路径:在调用.run_async()时通过cmd参数传入,可直接指定你下载的预编译版本路径

注意:-stream_loop仅支持本地文件输入,管道为顺序流式传输无法回退重读,需要循环帧序列时直接在Python侧控制帧重复写入次数即可,无需传该参数。

完整可运行代码

import ffmpeg
import numpy as np
import io

def vidwrite(
    outfile: str,
    images: list[np.ndarray],
    fps: int = 60,
    loops: int = 1,
    quality: int = 23,
    bitrate: str = "5M",
    ffmpeg_path: str = r"C:\path\to\your\ffmpeg.exe",
    target_width: int = None,
    target_height: int = None
):
    # 输入帧格式校验
    if not isinstance(images, np.ndarray):
        images = np.asarray(images, dtype=np.uint8)
    n_frames, height, width, channels = images.shape
    if channels != 3:
        raise ValueError("输入帧必须为3通道RGB格式")
    # 输出分辨率默认匹配输入帧
    target_width = target_width if target_width else width
    target_height = target_height if target_height else height

    # 组装FFMPEG进程
    process = (
        ffmpeg
        # 全局硬件加速配置
        .global_args(
            "-y",
            "-hwaccel", "cuda",
            "-hwaccel_output_format", "cuda"
        )
        # 管道输入配置:rawvideo RGB流
        .input(
            "pipe:",
            format="rawvideo",
            pix_fmt="rgb24",
            s=f"{width}x{height}",
            r=fps
        )
        # NVENC编码配置,和参考命令参数完全对齐
        .output(
            outfile,
            vf=f"scale_cuda={target_width}:{target_height}",
            c_v="hevc_nvenc",
            preset=18,
            tune=1,
            rc="vbr",
            cq=quality,
            multipass=2,
            b_v=bitrate,
            pix_fmt="yuv420p",
            r=fps
        )
        .overwrite_output()
        # 加载自定义FFMPEG二进制,开启管道
        .run_async(
            pipe_stdin=True,
            pipe_stderr=True,
            cmd=ffmpeg_path
        )
    )

    # 按循环次数写入所有帧
    for _ in range(loops):
        for frame in images:
            try:
                process.stdin.write(frame.tobytes())
            except Exception as e:
                # 出错时打印FFMPEG原生报错
                stderr = io.TextIOWrapper(process.stderr, encoding="utf-8")
                for line in stderr:
                    print(line.strip())
                process.stdin.close()
                process.wait()
                raise RuntimeError("FFMPEG编码失败") from e

    # 写入完成发送EOF,等待进程退出
    process.stdin.close()
    return_code = process.wait()
    if return_code != 0:
        stderr = io.TextIOWrapper(process.stderr, encoding="utf-8")
        for line in stderr:
            print(line.strip())
        raise RuntimeError(f"FFMPEG异常退出,返回码:{return_code}")

适配说明

  • 代码匹配你的运行环境:Windows 10 x64、GTX 1050Ti、带CUDA支持的Windows预编译FFMPEG,替换ffmpeg_path后可直接运行
  • 编码参数与你给出的参考命令完全对齐,需要增减参数直接在.output()中追加关键字参数即可,例如指定显卡序号加gpu=0、设置B帧数量加bf=2
  • 缩放滤镜使用scale_cuda替代CPU端scale,全流程在GPU完成,避免不必要的CPU-GPU数据拷贝
  • 输入帧必须为np.uint8类型、[h,w,3]维度的RGB格式;如果是cv2默认读取的BGR帧,需先通过cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)转换后再写入,否则颜色通道错位
  • 写入完成后必须关闭stdin管道再等待进程退出,否则FFMPEG会因未收到EOF信号挂起
  • 相比先存本地图片再编码的方案,管道传输无磁盘IO开销,GTX 1050Ti上1080P 60fps视频编码速度可达到实时的3~4倍

内容的提问来源于stack exchange,提问作者Ξένη Γήινος

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 12:48:18