Can ffmpeg show a progress bar?

Viewed 99281

I am converting a .avi file to .flv file using ffmpeg. As it takes a long time to convert a file I would like to display a progress bar. Can someone please guide me on how to go about the same.

I know that ffmpeg somehow has to output the progress in a text file and I have to read it using ajax calls. But how do I get ffmpeg to output the progress to the text file?

14 Answers

FFmpeg uses stdout for outputing media data and stderr for logging/progress information. You just have to redirect stderr to a file or to stdin of a process able to handle it.

With a unix shell this is something like:

ffmpeg {ffmpeg arguments} 2> logFile

or

ffmpeg {ffmpeg arguments} 2| processFFmpegLog

Anyway, you have to run ffmpeg as a separate thread or process.

Sadly, ffmpeg itself still cannot show a progress bar – also, many of the aforementioned bash- or python-based stop-gap solutions have become dated and nonfunctional.

Thus, i recommend giving the brand-new ffmpeg-progressbar-cli a try:

ffmpeg-progressbar-cli screencast

It's a wrapper for the ffmpeg executable, showing a colored, centered progress bar and the remaining time.

Also, it's open-source, based on Node.js and actively developed, handling most of the mentioned quirks (full disclosure: i'm its current lead developer).

If you just need hide all info and show default progress like ffmpeg in last line, you can use -stats option:

ffmpeg -v warning -hide_banner -stats ${your_params}

I found ffpb Python package (pip install ffpb) that passes arguments transparently to FFmpeg. Due to it's robustness, it doesn't need much maintenance. The last release is from Apr 29, 2019.

https://github.com/althonos/ffpb

Calling php's system function blocks that thread, so you'll need to spawn off 1 HTTP request for performing the conversion, and another polling one for reading the txt file, that's being generated.

Or, better yet, clients submit the video for conversion and then another process is made responsible for performing the conversion. That way the client's connection won't timeout while waiting for the system call to terminate. Polling is done in the same way as above.

This is my solution:

I use ffpb and python subprocess to tracking ffmpeg progress. Then I push status to a database (ex: Redis) for display a progress bar on website.

import subprocess

cmd = 'ffpb -i 400MB.mp4 400MB.avi'

process = subprocess.Popen(
    cmd,
    stdout=subprocess.PIPE,
    stderr=subprocess.STDOUT,
    shell=True,
    encoding='utf-8',
    errors='replace'
)

while True:
    realtime_output = process.stdout.readline()

    if realtime_output == '' and process.poll() is not None:
        break

    if realtime_output:
        print(realtime_output.strip(), flush=True)
        print('Push status to Redis...')

These answers that use multiple tools/consoles are complicating things too much.
pv is a good option but has the noted drawbacks of missing non-senquential data.
Just use the progress utility: Run ffmpeg as normal then in another console monitor with progress -m -c ffmpeg

By taking the progress bar from this link, I create a simple script that shows the actual frame of the video being encoded and shows a progress bar at the bottom of it... at the same time that ffmpeg encodes the video, of course.

enter image description here

First, we have to get duration, width and height from the video, to create the bar. But, as color filter can't get this information from the file, we have to get them first with ffprobe. Then, we use them with ffmpeg.

#!/bin/bash

video_duration=`ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$1"`
video_width=`ffprobe -v quiet -select_streams v -show_entries stream=width    -of csv=p=0:s=x "$1"`
video_height=`ffprobe -v quiet -select_streams v -show_entries stream=height   -of csv=p=0:s=x "$1"`
five_percent=`expr $video_height / 20`

#echo $video_duration
#echo $video_width
#echo $video_height
#echo $five_percent

ffmpeg -i "$1" -filter_complex "color=c=red:s='$video_width'x$five_percent[bar];[0][bar]overlay=-w+(w/$video_duration)*t:H-h:shortest=1[bar]" "$2" -map [bar] -f xv display

Then, use script as:

sh encode_with_bar.sh video_in.mkv video_out.mp4

Performance: the filter used is very simple... but everything added consumes additional CPU. Testing a 10MB video file in my computer, this is the difference:

  • Without script: 14.46 seconds
  • With script: 17.05 seconds (18% more)

Yes, almost 20% more. For short videos, it's nice. For larger files, probably it's not a good idea .

Related