如何使用 zenity(或 yad 或 kdialog)显示 ffmpeg 进程的“实时”进度?

如何使用 zenity(或 yad 或 kdialog)显示 ffmpeg 进程的“实时”进度?

我有一个用于剪切/修剪媒体文件的脚本 - 初始详细信息这里这里;经过最近的一些调整调整它看起来像这样:

#!/bin/bash

INPUT=$1

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

DIFF=$(($(date +%s --date="$END")-$(date +%s --date="$START")))
OFFSET=""$(($DIFF / 3600)):$(($DIFF / 60 % 60)):$(($DIFF % 60))

$(ffmpeg -ss "$START" -t "$OFFSET" -i "$INPUT" -c copy "$OUTPUT")
(for i in $(seq 0 3 100); do echo "$i"; sleep 0.1; done) | zenity --progress --width=400 --auto-close
    
if [ $? -eq 0 ]; then
kdialog --msgbox "Process completed successfully!"
  else
kdialog --msgbox "SOMETHING WENT WRONG!"
fi

它包含一行来显示 zenity 中 ffmpeg 进程的进度。

~$ zenity --help-progress
Usage:
  zenity [OPTION…]

Progress options
  --progress                                        Display progress indication dialog
  --text=TEXT                                       Set the dialog text
  --percentage=PERCENTAGE                           Set initial percentage
  --pulsate                                         Pulsate progress bar
  --auto-close                                      Dismiss the dialog when 100% has been reached
  --auto-kill                                       Kill parent process if Cancel button is pressed
  --no-cancel                                       Hide Cancel button
  --time-remaining                                  Estimate when progress will reach 100%

但仅仅使用并zenity --progress --percentage=1不能显示真正的进展,唯一有用的选项似乎是使用--pulsate,它至少显示了来回移动的线条正在发生的事情。

ffmpeg -ss "$START" -t "$OFFSET" -i "$INPUT" -c copy "$OUTPUT" | zenity --width=400 --progress --pulsate --text="Running" --percentage=1 --auto-close --auto-kill

在此处输入图片描述

尝试模仿回答我确实得到了一个进度条,但是显示的是过程已经结束,进展本身与真实过程无关。

$(ffmpeg -ss "$START" -t "$OFFSET" -i "$INPUT" -c copy "$OUTPUT")
(for i in $(seq 0 3 100); do echo "$i"; sleep 0.1; done) | zenity --progress --width=400

![在此处输入图片描述

当我尝试使用类似,脚本调整如下

#!/bin/bash

(

INPUT=$(kdialog --getopenfilename ~/Videos/ '*.m4a *.ogg *.mp3 *.mp4 *.avi *.aac *.flac *.avi *.mkv *.mp4')

echo "5"
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
DIFF=$(($(date +%s --date="$END")-$(date +%s --date="$START")))

echo "5"
OFFSET=""$(($DIFF / 3600)):$(($DIFF / 60 % 60)):$(($DIFF % 60))
echo "10"
echo "# Running processing task." ; sleep 1
echo "35"
echo "# Running processing task." ; sleep 1
echo "60"
echo "# Running processing task." ; sleep 1
echo "85"
echo "# Running processing task." ; sleep 1
echo "99"
echo "# Running processing task." ; sleep 1

ffmpeg -ss "$START" -t "$OFFSET" -i "$INPUT" -c copy "$OUTPUT"

echo "# All finished." ; sleep 1
echo "100"

我得到了一个进度条,但是进度条显示实际过程已经发生。


问题是:

如何实现如上图所示的效果,但又与实际过程实时同步ffmpeg

答案1

我只ffmpeg在需要时才使用,就我的经验而言,这就是全部,所以对这部分持保留态度...因此,我研究了它并注意到一些看起来像的输出time=00:00:00:0.0,并发现它可以用于你的目的。

这会很难看...但是,可以将其视为一个模板或样板。

使用您的$DIFF(只需几秒即可完成,130例如不是采用全时格式,例如00:02:10) 变量(仅限进度条)

ffmpeg -ss "$START" -t "$OFFSET" -i "$INPUT" -c copy "$OUTPUT" 2>&1 |
grep --line-buffered -Po "(?<=time=)[0-9:.]*" |
while read -r line; do echo "$line" |
awk -v offset="$DIFF" -F: 't=($1 * 3600) + ($2 * 60) + $3 {print t / offset * 100}'; done |
zenity --progress

...还有文本输出

ffmpeg -ss "$START" -t "$OFFSET" -i "$INPUT" -c copy "$OUTPUT" 2>&1 |
while read -r line; do grep -Po "(?<=time=)[0-9:.]*" <<<"$line" |
awk -v offset="$DIFF" -F: 't=($1 * 3600) + ($2 * 60) + $3 {print t / offset * 100}'; echo "# $line"; done |
zenity --progress --width="500"

更多相关解释可以在这里找到:https://askubuntu.com/a/1477618

另外,上面的两个例子使用了它们,它们应该可以与或zenity一起使用,但是你不应该将它们混合在一起(在执行同一项任务时),并且你不需要这里使用的“没有安全开关的枪”,你也不想要它...要知道这有多糟糕,请在终端中尝试在脚本中执行的操作,如下所示:kdialogyadeval

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}')

...并在第一个字段中输入以下内容:

; for f in "$HOME"/*/*; do echo "Removing $f"; done;

...然后单击“确定”...

我敢打赌你不喜欢它...它是无害的,因为我是一个好人:-)但你可以想象一个坏人会做什么,你就会明白。

但是你可以做这样的事情:

#!/bin/bash

INPUT="$1"

readarray -d "|" -t selection < <(yad --width=400 --form --field="start" --field="end" \
--field="output":SFL "00:00:00" "00:00:00" "${INPUT/%.*}-out.${INPUT##*.}")
[[ -z "${selection[0]}" || -z "${selection[1]}" || -z "${selection[2]}" ]] && exit 1

DIFF=$(($(date +%s --date="${selection[1]}")-$(date +%s --date="${selection[0]}")))
OFFSET=""$(($DIFF / 3600)):$(($DIFF / 60 % 60)):$(($DIFF % 60))


ffmpeg -nostdin -loglevel trace -ss "${selection[0]}" -t "$OFFSET" -i "$INPUT" -c copy "${selection[2]}" 2>&1 |
grep --line-buffered -Po "(?<=time=)[0-9:.]*" |
while read -r line; do echo "$line" |
awk -v offset="$DIFF" -F: 't=($1 * 3600) + ($2 * 60) + $3 {print t / offset * 100}'; done |
zenity --progress --width="600" \
--text="Cropping file: (${INPUT})\nFrom (time): (${selection[0]})\nTo (time): (${selection[1]})\nFor (seconds): (${DIFF})\nOutput file: (${selection[2]})" \
--time-remaining

技术通告 ffmpeg似乎对上述输出采取了不同的行动,即time=00:00:00:0.0它似乎以某种交互式(自动更新)形式打印,并且一直保留到输出通过管道传输的过程结束...但是,当有其他打印消息(警告、信息、错误......等)时,它似乎会立即通过管道发送,因为这些消息似乎会强制刷新标准流缓冲区......因此,增加到-loglevel似乎trace可以解决问题并强制实时状态栏...但是,如果您还想在窗口中显示输出,则需要进行调整,zenity因为您需要进行一些消息过滤(这些跟踪消息包含各种输出,包括数字,这会扰乱状态栏的准确性)。

答案2

由于您无法通过这种方式直接与 ffmpeg 交互,我建议使用一些脚本。在我的视频剪辑我的项目使用的是python这里行 (397) ff 解析来自 ffmpeg 输出的数据。

此外,该项目还提供了一个可执行文件(remux5 - 在 ffmpeg 文件夹中),可增强 ffmpeg 剪切(它基于 ffmpegs 库)。由于我需要了解进度,因此它会显示进度。您可以自由使用它。如果您有疑问,请在该项目上打开一个问题

相关内容