Can ffmpeg show a progress bar?

2019-01-04 22:49发布

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?

Thank you very much.

9条回答
兄弟一词,经得起流年.
2楼-- · 2019-01-04 23:12

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.

查看更多
太酷不给撩
3楼-- · 2019-01-04 23:17

You can do it with ffmpeg's -progress argument and nc

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
查看更多
爷的心禁止访问
4楼-- · 2019-01-04 23:24

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).

查看更多
聊天终结者
5楼-- · 2019-01-04 23:26

It’s very simple if you use the pipeview command. To do this, transform

ffmpeg -i input.avi {arguments}

to

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

No need to get into coding!

查看更多
Bombasti
6楼-- · 2019-01-04 23:27

javascript should tell php to start converting [1] and then do [2] ...


[1] php: start conversion and write status to 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 need just javascript to read the file. The following example uses dojo.request for AJAX, but you could use jQuery or vanilla or whatever as well :

[2] js: grab the progress from the 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);
查看更多
倾城 Initia
7楼-- · 2019-01-04 23:30

Had problems with the second php part. So I am using 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)));

Outputs perfectly.

Would like to see something for multiple uploads for another progress bar. This passing for the current file for one percentage. Then an overall progress bar. Almost there.

Also, if people are having a hard time getting:

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 awhile to figure it out. FFMPEG kept failing. Worked when I changed to no space.

查看更多
登录 后发表回答