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

如何通过Windows Batch实时提取FFmpeg的frame与fps值到变量

实时提取FFmpeg转码输出中的frame和fps值(Windows批处理方案)

你遇到的核心问题是FFmpeg的状态输出走的是STDERR,而且是实时流,没法直接用常规的文件读取方式处理。其实不用拆分批处理或者依赖临时文件,我们可以通过STDERR重定向+管道+实时解析的方式,直接把输出抓出来并存入变量,完全适配实时场景。

实现思路

  1. 把FFmpeg的STDERR输出重定向到STDOUT(用2>&1),这样管道能捕获到转码状态信息;
  2. 用findstr过滤出包含frame=的行,只处理我们关心的状态行;
  3. 用for /f解析每行内容,提取frame=和fps=对应的值,存入变量;
  4. 启用变量延迟扩展,确保循环内的变量能实时更新。

完整可运行的批处理代码

@echo off
setlocal enabledelayedexpansion

:: 替换成你的FFmpeg转码命令
set "FFMPEG_CMD=ffmpeg -i "D:\Videos\youtube.mp4" -c:v libx265 -c:a copy "D:\Videos\youtube.mkv""

:: 提前用ffprobe获取原视频总帧数(用于后续进度计算)
for /f %%f in ('ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 "D:\Videos\youtube.mp4"') do set "TOTAL_FRAMES=%%f"

:: 实时捕获并解析FFmpeg输出
%FFMPEG_CMD% 2>&1 | findstr "frame=" | (
    :: 记录转码开始时间
    set "START_TIME=%time%"

    :PROCESS_LINE
    set "CURRENT_LINE="
    set /p CURRENT_LINE=
    if not defined CURRENT_LINE goto :END_PROCESS

    :: 提取frame值(tokens=2对应frame=后面的数值)
    for /f "tokens=2 delims== " %%a in ("!CURRENT_LINE!") do set "CURRENT_FRAME=%%a"
    :: 提取fps值(tokens=4对应fps=后面的数值)
    for /f "tokens=4 delims== " %%b in ("!CURRENT_LINE!") do set "CURRENT_FPS=%%b"

    :: 这里可以加入你的进度计算和ETA逻辑,示例如下
    if not "!TOTAL_FRAMES!"=="" (
        set /a "PROGRESS=CURRENT_FRAME*100/TOTAL_FRAMES"
        echo 当前进度: !PROGRESS!%, 已处理帧: !CURRENT_FRAME!, 当前帧率: !CURRENT_FPS!
        :: ETA计算可以基于已用时间和进度,这里省略具体实现,你可以用时间差来计算
    ) else (
        echo 已处理帧: !CURRENT_FRAME!, 当前帧率: !CURRENT_FPS!
    )

    goto :PROCESS_LINE
)

:END_PROCESS
echo 转码完成!
endlocal

关键细节解释

  • STDERR重定向:2>&1是Windows批处理中把错误输出(FFmpeg的状态信息默认走这里)转到标准输出的语法,这样管道才能捕获到内容;
  • 变量延迟扩展:setlocal enabledelayedexpansion必须开启,否则循环内的变量无法实时更新(要用!变量!代替%变量%来引用);
  • 解析参数调整:如果你的FFmpeg输出行格式有变化(比如frame=和fps=的位置不同),需要调整for /f里的tokens参数。比如原输出行是frame= 19 fps=0.0 q=-0.0 ...,tokens=2对应frame值,tokens=4对应fps值;
  • 总帧数获取:用ffprobe(FFmpeg套件自带工具)提前获取原视频的总帧数,这是计算进度百分比的基础,如果没有ffprobe,也可以通过视频时长×帧率估算总帧数。

关于周期性检查

如果不需要每一行都处理,而是想固定间隔(比如每1秒)检查一次状态,可以在goto :PROCESS_LINE前加入timeout /t 1 /nobreak >nul,但要注意这可能会错过部分输出行,所以优先推荐实时捕获的方式,因为FFmpeg的状态输出本身就是周期性的(默认大概每秒几次)。

内容的提问来源于stack exchange,提问作者HASJ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:24:59