Peut ffmpeg afficher une barre de progression?

je suis en train de convertir un .avi fichier .fichier flv à l'aide de ffmpeg. Comme il faut beaucoup de temps pour convertir un fichier je voudrais afficher une barre de progression. Est-ce que quelqu'un peut me guider sur la façon de faire la même chose?

je sais que ffmpeg doit en quelque sorte sortir la progression dans un fichier texte et je dois la lire en utilisant des appels ajax. Mais comment faire pour que ffmpeg affiche la progression dans le fichier texte?

Merci beaucoup.

49
demandé sur brian d foy 2009-04-14 18:51:29

9 réponses

j'ai joué avec ça pendant quelques jours. Ce truc de "ffmpegprogress" m'a aidé, mais c'était très dur de travailler avec mon appareil, et de lire le code.

pour montrer les progrès de ffmpeg vous devez faire ce qui suit:

  1. exécuter la commande ffmpeg à partir de php sans attendre une réponse (pour moi, ce fut la partie la plus difficile)
  2. dis à ffmpeg d'envoyer sa sortie dans un fichier
  3. de l'avant (AJAX, Flash, n'importe quoi) a frappé soit ce fichier directement ou un fichier php qui peut tirer la progression de la sortie de ffmpeg.

Voici comment j'ai résolu chaque partie:

1. J'ai eu l'idée suivante de "ffmpegprogress". C'est ce qu'il a fait: un fichier PHP en appelle un autre via une socket http. Le 2e exécute le "exec" et le premier fichier raccroche. Pour moi sa mise en œuvre est trop complexe. Il a l'aide de "fsockopen". J'aime CURL. Alors voici ce que j'ai fait:

$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);

mettre CURLOPT_TIMEOUT à 1 signifie qu'il attendra 1 seconde pour une réponse. De préférence, ce serait plus faible. Il y a aussi le CURLOPT_TIMEOUT_MS qui prend des millisecondes, mais ça n'a pas marché pour moi.

après 1 seconde, CURL raccroche, mais la commande exec fonctionne toujours. Partie 1 résolue.

BTW-quelques personnes suggéraient d'utiliser la commande" nohup " pour cela. Mais cela ne semblait pas fonctionner pour moi.

* ALSO! Avoir un fichier php sur votre serveur qui peut exécuter du code directement sur la ligne de commande est un risque de sécurité évident. Vous devriez avoir un mot de passe, ou encoder les données de poste d'une certaine façon.

2. Le " exec.php " script ci-dessus doit aussi dire ffmpeg à la sortie d'un fichier. Voici le code pour cela:

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

Note le " 1 > path/to / output.txt 2>&1". Je ne suis pas expert en ligne de commande, mais de ce que je peut dire que cette ligne dit "envoyer la sortie normale à ce fichier, et envoyer les erreurs au même endroit". Consultez cette url pour plus d'informations: http://tldp.org/LDP/abs/html/io-redirection.html

3. À partir de la fin de l'appel un script php lui donnant l'emplacement de la sortie.fichier txt. Ce fichier php va ensuite extraire la progression du fichier texte. Voici comment j'ai fait:

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

J'espère que ça aidera quelqu'un.

28
répondu Mike Kellogg 2015-03-31 14:08:47

il y a un article en russe qui décrit comment résoudre votre problème.

le point est de saisir la valeur Duration avant l'encodage et de saisir les valeurs time=... pendant l'encodage.

--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--
22
répondu baltazar 2010-06-10 13:35:30

FFmpeg utilise stdout pour outputing media data et stderr pour logging / progress information. Vous avez juste à rediriger stderr vers un fichier ou à stdin d'un processus capable de le gérer.

avec un shell unix c'est quelque chose comme:

ffmpeg {ffmpeg arguments} 2> logFile

ou

ffmpeg {ffmpeg arguments} 2| processFFmpegLog

de toute façon, vous devez exécuter ffmpeg comme un fil ou un processus séparé.

19
répondu mouviciel 2009-04-14 14:57:27

c'est très simple si vous utilisez la commande pipeview. Pour ce faire, transformez

ffmpeg -i input.avi {arguments}

à

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

Pas besoin d'entrer dans le codage!

13
répondu istefani 2015-05-27 12:17:37

vous pouvez le faire avec ffmpeg 's -progress argument et nc

WATCHER_PORT=9998

DURATION= $(ffprobe -select_streams v:0 -show_entries "stream=duration" \
    -of compact $INPUT_FILE | sed 's!.*=\(.*\)!!g')

nc -l $WATCHER_PORT | while read; do
    sed -n 's/out_time=\(.*\)/ of $DURATION/p')
done &

ffmpeg -y -i $INPUT_FILE -progress localhost:$WATCHER_PORT $OUTPUT_ARGS
7
répondu iluvcapra 2015-07-11 19:15:03

appeler la fonction système de php bloque ce thread, vous aurez donc besoin de lancer 1 requête HTTP pour effectuer la conversion, et un autre polling pour lire le fichier txt, qui est généré.

ou, mieux encore, les clients soumettent la vidéo pour la conversion et alors un autre processus est rendu responsable de l'exécution de la conversion. De cette façon, la connexion du client ne sera pas temporisée en attendant que l'appel système se termine. Le sondage se fait dans le même manière que ci-dessus.

1
répondu Allain Lalonde 2009-04-14 14:56:09

a eu des problèmes avec la deuxième partie de php. Donc j'utilise ceci à la place:

    $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)));

sort parfaitement.

aimerait voir quelque chose pour plusieurs téléchargements pour une autre barre de progression. Ce passage pour le fichier courant pour un pourcentage. Puis une barre de progression globale. On y est presque.

aussi, si les gens ont du mal à obtenir:

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

pour travailler.

Essayez:

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

" 1> chemin d'accès "" 1>chemin d'accès " OU " 2> chemin d'accès "" 2>chemin d'accès "

m'a pris un moment pour le comprendre. FFMPEG n'arrêtait pas d'échouer. A travaillé quand j'ai changé pour de l'espace.

1
répondu Neotropic 2011-08-24 01:41:28

javascript devrait dire à php de commencer à convertir [1] et ensuite de faire [2] ...


[1] php: démarrer la conversion et de l'écriture dans un fichier (voir ci-dessus):

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

pour la deuxième partie nous avons besoin de juste javascript pour lire le fichier. L'exemple suivant utilise le dojo.demande pour AJAX, mais vous pourriez utiliser jQuery ou vanille ou n'importe quoi aussi bien :

[2] js: saisir l'avancement du dossier:

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);
1
répondu sebilasse 2013-06-26 09:23:03

malheureusement, ffmpeg lui – même ne peut toujours pas montrer une barre de progrès - aussi, beaucoup des susnommés bash-ou python-basé des solutions de stop-gap sont devenus désuets et non fonctionnelle.

ainsi, je recommande de donner le tout nouveau ffmpeg-progressbar-cli un essai:

ffmpeg-progressbar-cli screencast

c'est un wrapper pour l'exécutable ffmpeg , montrant un coloré, barre de progression centrée et le temps restant.

aussi, c'est open-source, basé sur Node.js et activement développé, en traitant la plupart des bizarreries mentionnées (divulgation complète: je suis son développeur principal actuel).

0
répondu sidneys 2018-08-11 01:13:06