You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让Zenity(或Yad、KDialog)实时同步显示FFmpeg处理进程的进度?

如何让Zenity(或Yad、KDialog)实时同步显示FFmpeg处理进程的进度?

嗨,我完全懂你的困扰——之前要么是进度条提前走完、要么只能用脉动效果假装在跑,根本没法和FFmpeg的实际进度同步对吧?其实核心解决思路就是捕获FFmpeg的实时输出,解析出真实进度值,再把这些值传给Zenity,这样就能实现真正的同步进度条了。

我给你整理了修改后的完整脚本,还会拆解关键步骤,你可以直接套用:

#!/bin/bash

# 用KDialog选择输入媒体文件
INPUT=$(kdialog --getopenfilename ~/Videos/ '*.m4a *.ogg *.mp3 *.mp4 *.avi *.aac *.flac *.mkv')
[[ -z $INPUT ]] && exit 1

# 用Yad弹出参数设置窗口,获取开始时间、结束时间和输出路径
eval $(yad --width=400 --form --field=start --field=end --field=output:SFL "00:00:00" "00:00:00" "${INPUT/%.*}-out.${INPUT##*.}" | awk -F'|' '{printf "START=%s\nEND=%s\nOUTPUT=\"%s\"\n", $1, $2, $3}')
[[ -z $START || -z $END || -z $OUTPUT ]] && exit 1

# 计算处理的总时长(转成秒,方便后续计算进度)
START_SEC=$(date +%s --date="$START")
END_SEC=$(date +%s --date="$END")
TOTAL_DURATION=$((END_SEC - START_SEC))
[[ $TOTAL_DURATION -le 0 ]] && { kdialog --msgbox "结束时间不能早于开始时间哦!"; exit 1; }

# 启动Zenity进度条,同时运行FFmpeg并实时解析进度
(
    # 初始化进度条
    echo "0"
    echo "# 正在准备FFmpeg处理..."
    sleep 0.5

    # 运行FFmpeg,把stderr重定向到stdout(FFmpeg默认把进度输出到stderr),用awk解析进度
    LC_ALL=C ffmpeg -ss "$START" -t "$TOTAL_DURATION" -i "$INPUT" -c copy "$OUTPUT" 2>&1 | awk -v total="$TOTAL_DURATION" '
        # 匹配FFmpeg输出里的time行(比如:time=00:01:23.45)
        /time=/ {
            # 提取时间字符串,拆分出时、分、秒
            split(substr($0, index($0,"time=")+5), time_parts, /:/);
            # 把当前处理时间转成总秒数
            current_sec = time_parts[1]*3600 + time_parts[2]*60 + int(time_parts[3]);
            # 计算进度百分比,防止超过100%
            progress = int((current_sec / total) * 100);
            if (progress > 100) progress = 100;
            # 把进度值和提示文本传给Zenity
            print progress;
            print "# 已完成: " progress "%";
            fflush(); # 强制刷新输出,确保Zenity实时收到进度
        }
        # 处理完成后输出100%
        END {
            print "100";
            print "# 处理完成啦!";
        }
    '
) | zenity --progress --width=400 --auto-close --auto-kill --text="FFmpeg正在处理媒体文件..." --percentage=0

# 根据Zenity的退出状态判断结果
if [ $? -eq 0 ]; then
    kdialog --msgbox "媒体文件处理成功完成!"
else
    kdialog --msgbox "处理过程中出现错误,请检查参数或输入文件!"
fi

关键细节说明:

  1. 捕获FFmpeg的进度输出
    FFmpeg默认会把进度信息输出到标准错误(stderr),所以我们用2>&1把stderr重定向到标准输出(stdout),这样awk才能读到这些内容。另外加LC_ALL=C是强制FFmpeg用英文输出,避免不同语言环境下time=关键词不一样,导致匹配失败。

  2. 解析进度并计算百分比
    用awk匹配FFmpeg输出里的time=行,提取当前处理的时间,转成总秒数后,和我们之前计算的总处理时长对比,算出实时进度百分比,再输出给Zenity。

  3. 强制刷新输出
    awk默认会缓存输出,所以必须加fflush()强制把进度值立刻传给Zenity,不然进度条会卡顿或者延迟。

  4. Zenity的实用参数

    • --auto-close:进度到100%时自动关闭对话框
    • --auto-kill:如果用户点击取消按钮,会自动杀掉正在运行的FFmpeg进程
    • --text:设置对话框的初始提示文本

替换成Yad的小技巧:

如果你更喜欢用Yad,只需要把Zenity的命令换成Yad的进度对话框即可,参数基本兼容:

) | yad --progress --width=400 --auto-close --auto-kill --text="FFmpeg正在处理媒体文件..." --percentage=0

备注:内容来源于stack exchange,提问作者cipricus

火山引擎 最新活动