1

I have a script to cut/trim media files - initial details here and here; after some more recent adjustments adjustments it looks like this:

#!/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

It includes a line to show the progress of ffmpeg process with zenity.

~$ 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%

but just using zenity --progress --percentage=1 shows no real progress, the only useful option seems to be to use --pulsate, which at least shows something is happening with a line that goes back and forth.

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

enter image description here

Trying to mimic this answer I do get a progress bar, but that is shown after the process has ended and the progress itself has nothing to do with the real process.

$(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

![enter image description here

When I try to use something like this, and the script is adjusted like this

#!/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"

I get a progress bar but the progress bar is shown before the actual process takes place.


The question is:

How to have something like in the image above, but synchronized in real time with the actual ffmpeg process?

cipricus
  • 4,066
  • 4
  • 47
  • 106

2 Answers2

3

I only use ffmpeg when I need to and that's it as far as my experience with it goes, so take that part with a pinch of salt ... So, I looked into it and noticed some output that looks like time=00:00:00:0.0 and figured out that it can be used for your purpose.

This is going to be ugly ... However, consider it a template or a boiler plate.

Using your $DIFF(needs to be in seconds only like e.g. 130 and not in full time format like 00:02:10) variable (Progress bar only)

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

... and with the text output as well

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"

More related explanation can be found here: https://askubuntu.com/a/1477618

Also the above two examples use zenity and they should work with either kdialog or yad but you shouldn’t mix them together (when doing the same one task) and you don’t need the "gun without safety switch" eval used here and you don’t want it either ... To know how bad that could be, try what you have in your script in the terminal like so:

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

... and enter this in the first field:

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

... and click OK ...

I bet you didn't like it ... It was harmless because I'm a nice person :-) but you could imagine what a bad person might do and you get the point.

You can however do something like this:

#!/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

Technical notice ffmpeg seems to act differently regarding the above mentioned output i.e. time=00:00:00:0.0 which it seams to print in some interactive(auto-updating) form that is being held until the end of the process when the output is being piped ... It, however, seems to be immediately sent through the pipe when there are other printed messages (warnings, info, errors ... etc.) as these seem to force flushing the standard streams buffers ... Therefore, increasing the -loglevel to trace seems to do the trick and force real-time status bar ... This, however, will need tuning if in addition you want to show the output as well in the zenity window as you'll need to do some messages filtering (those trace messages contain all sorts of output including numbers which will mess up the accuracy of the status bar).

Raffa
  • 34,963
1

Since you can't interact directly with ffmpeg this way I'd recommend to use some script. In my Videocut project am using python here Line (397) ff to parse the data from an ffmpeg output.

In addition that project offers an executable (remux5 - in the ffmpeg folder) that enhances the ffmpeg cutting (Its based on ffmpegs libraries). Since I need to know the progress, it displays them. You are free to use it. If you have questions, open an issue on that project

kanehekili
  • 7,426