Can ffmpeg show a progress bar?

I am converting a .avi file to a .flv file using ffmpeg. Since it takes a long time to convert the file, I would like to display a progress bar. Can anyone advise me how to go about the same.

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

Thank you very much.

+54
ffmpeg progress-bar
Apr 14 '09 at 14:51
source share
10 answers

I play with this for several days. This "ffmpegprogress" thing helped, but it was very difficult to work with my setup and reading the code was not easy.

To show the progress of ffmpeg, you need to do the following:

  • run ffmpeg command with php without waiting for an answer (for me it was the hardest part)
  • tell ffmpeg to send it to a file
  • from the front side (AJAX, Flash, independently) it gets either to this file directly or to the php file, which can output progress from ffmpeg output.

Here is how I solved each part:

1. I got the following idea from "ffmpegprogress". This he did: one PHP file calls another via an http socket. The second one actually runs "exec", and the first file just hangs on it. For me, its implementation was too complicated. He used "fsockopen". I like curl. So here is what I did:

$url = "http://".$_SERVER["HTTP_HOST"]."/path/to/exec/exec.php"; curl_setopt($curlH, CURLOPT_URL, $url); $postData = "&cmd=".urlencode($cmd); $postData .= "&outFile=".urlencode("path/to/output.txt"); curl_setopt($curlH, CURLOPT_POST, TRUE); curl_setopt($curlH, CURLOPT_POSTFIELDS, $postData); curl_setopt($curlH, CURLOPT_RETURNTRANSFER, TRUE); // # this is the key! curl_setopt($curlH, CURLOPT_TIMEOUT, 1); $result = curl_exec($curlH); 

Setting CURLOPT_TIMEOUT to 1 means that 1 second will wait for a response. Preferably, this is lower. There is also CURLOPT_TIMEOUT_MS, which takes milliseconds, but for me it did not work.

After 1 second, CURL freezes, but the exec command still works. Part 1 solved.

BTW - Several people have suggested using the nohup command for this. But it didn't seem to work for me.

* ALSO! Having a php file on your server that can execute code directly on the command line is an obvious security risk. You must have a password or encode these messages in some way.

2. The above "exec.php" script should also specify ffmpeg to output to the file. Here is the code for this:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1> path/to/output.txt 2>&1"); 

Note the "1> path /to/output.txt 2> & 1". I am not an expert on the command line, but from what I can say, this line says "send normal output to this file and send errors to the same place." Check this url for more information: http://tldp.org/LDP/abs/html/io-redirection.html

3. From the external interface, call php script, indicating the location of the output.txt file. Then this php file will pull the progress from the text file. Here is how I did it:

 // # get duration of source preg_match("/Duration: (.*?), start:/", $content, $matches); $rawDuration = $matches[1]; // # rawDuration is in 00:00:00.00 format. This converts it to seconds. $ar = array_reverse(explode(":", $rawDuration)); $duration = floatval($ar[0]); if (!empty($ar[1])) $duration += intval($ar[1]) * 60; if (!empty($ar[2])) $duration += intval($ar[2]) * 60 * 60; // # get the current time preg_match_all("/time=(.*?) bitrate/", $content, $matches); $last = array_pop($matches); // # this is needed if there is more than one match if (is_array($last)) { $last = array_pop($last); } $curTime = floatval($last); // # finally, progress is easy $progress = $curTime/$duration; 

Hope this helps someone.

+32
Jun 05 2018-11-11T00:
source share
β€” -

This English article describes how to solve your problem.

The goal is to catch the Duration value before encoding and to catch the time=... values ​​during encoding.

 --skipped-- Duration: 00:00:24.9, start: 0.000000, bitrate: 331 kb/s --skipped-- frame= 41 q=7.0 size= 116kB time=1.6 bitrate= 579.7kbits/s frame= 78 q=12.0 size= 189kB time=3.1 bitrate= 497.2kbits/s frame= 115 q=13.0 size= 254kB time=4.6 bitrate= 452.3kbits/s --skipped-- 
+25
Jun 10 '10 at 13:35
source share

FFmpeg uses stdout for media output and stderr for logging / progress information. You just need to redirect stderr to a file or to the stdin of a process capable of handling it.

With the unix shell, this is something like:

 ffmpeg {ffmpeg arguments} 2> logFile 

or

 ffmpeg {ffmpeg arguments} 2| processFFmpegLog 

In any case, you need to run ffmpeg as a separate thread or process.

+19
Apr 14 '09 at 14:57
source share

It is very simple if you use the pipeview command. To do this, convert

 ffmpeg -i input.avi {arguments} 

to

 pv input.avi | ffmpeg -i pipe:0 -v warning {arguments} 

No need to go into coding!

+13
May 27 '15 at 12:17
source share

You can do this with the ffmpeg -progress and nc arguments

 WATCHER_PORT=9998 DURATION= $(ffprobe -select_streams v:0 -show_entries "stream=duration" \ -of compact $INPUT_FILE | sed 's!.*=\(.*\)!\1!g') nc -l $WATCHER_PORT | while read; do sed -n 's/out_time=\(.*\)/\1 of $DURATION/p') done & ffmpeg -y -i $INPUT_FILE -progress localhost:$WATCHER_PORT $OUTPUT_ARGS 
+8
Jul 11 '15 at 5:07
source share

Unfortunately, ffmpeg itself still cannot display a progress bar - also many of the aforementioned bash- or python-based time-limited solutions have become obsolete and non-functional.

Thus, I recommend trying the brand new ffmpeg-progressbar-cli :

ffmpeg-progressbar-cli screencast

This is the shell for the ffmpeg executable, showing the color progress bar in the center and the remaining time.

In addition, it is open source, based on Node.js and actively developing, handles most of the quirks mentioned (full disclosure: I am currently its lead developer).

+3
Aug 11 '18 at 1:13
source share

javascript must say php to start the conversion [1] and then do [2] ...




[1] php: start conversion and write status to a file (see above):

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1"); 



For the second part, we just need javascript to read the file. The following example uses dojo.request for AJAX, but you can use jQuery or vanilla or something else:

[2] js: capture progress from file:

 var _progress = function(i){ i++; // THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] : var logfile = 'path/to/output.txt'; /* (example requires dojo) */ request.post(logfile).then( function(content){ // AJAX success var duration = 0, time = 0, progress = 0; var resArr = []; // get duration of source var matches = (content) ? content.match(/Duration: (.*?), start:/) : []; if( matches.length>0 ){ var rawDuration = matches[1]; // convert rawDuration from 00:00:00.00 to seconds. var ar = rawDuration.split(":").reverse(); duration = parseFloat(ar[0]); if (ar[1]) duration += parseInt(ar[1]) * 60; if (ar[2]) duration += parseInt(ar[2]) * 60 * 60; // get the time matches = content.match(/time=(.*?) bitrate/g); console.log( matches ); if( matches.length>0 ){ var rawTime = matches.pop(); // needed if there is more than one match if (lang.isArray(rawTime)){ rawTime = rawTime.pop().replace('time=','').replace(' bitrate',''); } else { rawTime = rawTime.replace('time=','').replace(' bitrate',''); } // convert rawTime from 00:00:00.00 to seconds. ar = rawTime.split(":").reverse(); time = parseFloat(ar[0]); if (ar[1]) time += parseInt(ar[1]) * 60; if (ar[2]) time += parseInt(ar[2]) * 60 * 60; //calculate the progress progress = Math.round((time/duration) * 100); } resArr['status'] = 200; resArr['duration'] = duration; resArr['current'] = time; resArr['progress'] = progress; console.log(resArr); /* UPDATE YOUR PROGRESSBAR HERE with above values ... */ if(progress==0 && i>20){ // TODO err - giving up after 8 sec. no progress - handle progress errors here console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }'); return; } else if(progress<100){ setTimeout(function(){ _progress(i); }, 400); } } else if( content.indexOf('Permission denied') > -1) { // TODO - err - ffmpeg is not executable ... console.log('{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }'); } }, function(err){ // AJAX error if(i<20){ // retry setTimeout(function(){ _progress(0); }, 400); } else { console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }'); console.log( err ); } return; }); } setTimeout(function(){ _progress(0); }, 800); 
+2
Jun 26 '13 at 7:53 on
source share

Calling php system functions blocks this thread, so you will need to deploy 1 HTTP request to perform the conversion and another poll to read the txt file that is created.

Or, even better, clients send the video for conversion, and then another process is responsible for performing the conversion. Thus, the client connection will not be disconnected while waiting for the completion of the system call. The survey is performed as described above.

+1
Apr 14 '09 at 14:56
source share

There were problems with the second part of php. Therefore, I use this instead:

  $log = @file_get_contents($txt); preg_match("/Duration:([^,]+)/", $log, $matches); list($hours,$minutes,$seconds,$mili) = split(":",$matches[1]); $seconds = (($hours * 3600) + ($minutes * 60) + $seconds); $seconds = round($seconds); $page = join("",file("$txt")); $kw = explode("time=", $page); $last = array_pop($kw); $values = explode(' ', $last); $curTime = round($values[0]); $percent_extracted = round((($curTime * 100)/($seconds))); 

The conclusion is excellent.

I would like to see something for several downloads for another progress bar. This transfer of the current file for one percent. Then a general progress bar. Almost there.

In addition, if people can hardly get:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1> path/to/output.txt 2>&1"); 

To work.

Try:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1"); 

" 1> path " to " 1> path " OR " 2> path " to " 2> path "

Took me a little to figure it out. FFMPEG does not work. Worked when I did not take up space.

+1
Aug 24 '11 at 1:30
source share

If you just need to hide all the information and show the default progress, for example, ffmpeg in the last line, you can use -stats :

 ffmpeg -v warning -hide_banner -stats ${your_params} 
0
Apr 25 '19 at 16:25
source share



All Articles