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

如何在C#中获取FFmpeg音视频转码任务的处理进度?

实现FFmpeg转码进度监控的可行方案

核心思路

让FFmpeg输出结构化的进度数据,后端实时解析并计算百分比后同步给前端。该方案同时支持音频和视频文件,无需依赖任何FFmpeg封装库。

步骤1:获取输入媒体的总时长

转码进度的核心是当前处理时长 / 总时长,因此需要先获取输入文件的总时长。执行以下FFmpeg命令:

ffmpeg -i "输入文件路径" -show_entries format=duration -v quiet -of csv=p=0

这条命令会直接输出输入媒体的总时长(单位:秒,带小数),音频和视频文件均适用。

在C#中可通过启动临时进程执行该命令,捕获输出并转换为double类型的时长值:

private double GetMediaDuration(string inputPath, string ffmpegPath)
{
    var processStartInfo = new ProcessStartInfo
    {
        FileName = ffmpegPath,
        Arguments = $"-i \"{inputPath}\" -show_entries format=duration -v quiet -of csv=p=0",
        RedirectStandardOutput = true,
        UseShellExecute = false,
        CreateNoWindow = true
    };

    using (var process = Process.Start(processStartInfo))
    {
        string output = process.StandardOutput.ReadToEnd();
        process.WaitForExit();
        if (double.TryParse(output.Trim(), out double duration))
        {
            return duration;
        }
        throw new Exception("无法获取媒体时长");
    }
}

步骤2:启动转码进程并配置进度输出

启动转码时,添加-progress pipe:1参数,让FFmpeg把进度信息输出到标准输出流(而非默认的标准错误流),方便后端实时读取。完整转码参数示例:

ffmpeg -i "输入文件路径" -c:v libx264 -c:a aac "输出文件路径" -progress pipe:1

步骤3:实时解析进度数据

FFmpeg通过-progress输出的是键值对格式的文本,每行一个条目,例如:

frame=1500
fps=29.97
time=00:00:50.02
bitrate=1234.5kbits/s
speed=1.2x
...
progress=end

重点解析time字段,将其转换为秒数后,结合步骤1获取的总时长计算进度百分比。

C#中异步读取并解析的示例代码:

private async Task RunTranscodeWithProgress(string inputPath, string outputPath, string ffmpegPath, double totalDuration, Action<double> onProgressUpdated)
{
    var processStartInfo = new ProcessStartInfo
    {
        FileName = ffmpegPath,
        Arguments = $"-i \"{inputPath}\" -c:v libx264 -c:a aac \"{outputPath}\" -progress pipe:1",
        RedirectStandardOutput = true,
        UseShellExecute = false,
        CreateNoWindow = true
    };

    using (var process = Process.Start(processStartInfo))
    {
        string line;
        while ((line = await process.StandardOutput.ReadLineAsync()) != null)
        {
            if (line.StartsWith("time="))
            {
                string timeStr = line.Split('=')[1].Trim();
                // 将时间字符串(如00:00:50.02)转换为秒数
                double currentTime = ParseTimeString(timeStr);
                double progress = Math.Min((currentTime / totalDuration) * 100, 100);
                onProgressUpdated(progress);
            }
            else if (line == "progress=end")
            {
                onProgressUpdated(100);
                break;
            }
        }
        await process.WaitForExitAsync();
    }
}

private double ParseTimeString(string timeStr)
{
    // 拆分时、分、秒
    string[] parts = timeStr.Split(':');
    double hours = double.Parse(parts[0]);
    double minutes = double.Parse(parts[1]);
    double seconds = double.Parse(parts[2]);
    return hours * 3600 + minutes * 60 + seconds;
}

关键注意事项

  • 异步读取避免阻塞:必须用异步方式读取标准输出,防止主线程被卡死,同时保证进度实时更新。
  • 进度边界处理:计算时要确保进度不会超过100%,转码结束时手动触发100%进度。
  • 异常处理:添加进程启动失败、输出解析失败等异常捕获逻辑,避免崩溃。
  • 跨场景适配:该方案对本地文件、网络流输入均有效(网络流获取时长时可能需要调整FFmpeg参数,但核心逻辑不变)。

方案优势

  • 精度足够:基于媒体时长计算进度,不受编码格式、容器类型影响,音视频通用。
  • 实现简单:无需依赖第三方封装库,仅通过FFmpeg原生参数和进程流读取即可完成。
  • 实时性好:FFmpeg会频繁输出进度数据,前端可以得到流畅的进度更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 13:40:56