Calculer l’etat d’avancement d’un encodage ffmpeg avec php

Dans cet article nous allons voir comment lancer un encodage de vidéo avec le  logiciel ffmpeg et calculer l’état d’avancement du travail avec php. Je vous laisse juges du champs d’application. Personnellement, je l’utilise afin d’afficher une barre de progression pour chaque encodage en cours dans une interface utilisateur. Le script d’encodage est exécuté en mode CLI, les tâches d’encodage pouvant prendre du temps cela permet de s’affranchir de la limitation d’exécution de php.

L’opération s’effectue à l’aide de deux appels à ffmpeg : un premier appel pour obtenir les informations de la vidéo, et un deuxième appel pour lancer l’encodage et calculer le pourcentage d’avancement de l’encodage.

Obtenir les informations sur une vidéo avec ffmpeg

Pour visualiser les propriétés d’une vidéo avec ffmpeg il suffit de lancer la commande « ffmpeg -i mavideo.mpg ». Vous aurez alors à l’écran les informations ci-dessous.

Information sur une vidéo

On constate que la durée de cette vidéo est de 3 minutes 12 secondes et 64 images. Nous allons extraire l’information et la transformer en seconde.

$handle = popen('ffmpeg -i maVideo.mpg 2>&1','r');

ob_start();
while($read = fread($handle,100))
{
	echo $read;
}
$content = ob_get_clean();

pclose($handle);

// récupération de la durée
preg_match('`\s*Duration:\s*(\d{2}):(\d{2}):(\d{2})\.(\d{1,2})`msi',$content, $reg);

// calcul de la durée en seconde
$duration = (($reg[1] * 60  + $reg[2]) *  60 + $reg[3]);

// on rajoute le nombre d'image supplémentaire
$duration = floatval($duration.'.'.$reg[4]);

Lancement de l’encodage et calcul du pourcentage

Lorsque vous lancez l’encodage de la vidéo vous voyez une succession de lignes relatives à  l’état d’avancement de l’encodage. Vous pouvez observer le temps de lecture de la vidéo : « time » exprimé en seconde.

Encodage avec ffmpeg

Il ne reste plus qu’a extraire cette information pour calculer le ratio d’encodage.

// ligne de commande à exécuter
$cmd = 'ffmpeg -i maVideo.mpg maVideo.flv 2>&1';

$pourcent = 0;

// création du processus puis lecture
$handle = popen($cmd,'r');
while($read = fread($handle,100))
{
    if(preg_match('`time=(\d+\.\d+)`',$read,$reg))
    {
         $time = floatval($reg[1]);
         $pourcent = ($time / $duration) * 100; // duration calculé plus haut
         if($pourcent > 100)
         {
             $pourcent = 100;
         }
        // faire quelque chose avec le pourcentage (enregistrement en bdd par exemple)
    }
}
pclose($handle);
$pourcent = 100; // forcément à 100% en fin d'encodage

Le système est relativement simple, le plus compliqué étant de définir : où trouver et comment traiter les données qui nous intéressent (duration et time).

Vous pouvez laisser une réponse, ou utiliser ce permalien depuis votre site.

8 réponses à “Calculer l’etat d’avancement d’un encodage ffmpeg avec php”

  1. Krosk dit :

    Bonjour,

    merci pour l’astuce mais ça ne fonctionne pas chez moi…
    Le fread attend la fin du processus ffmpeg pour retourner une valeur (vide). Donc pas de moyen de récupérer la progression…

    Comment expliquer ce problème, et y-a-t-il un moyen de le contourner ?

    • Stéphane dit :

      Bonjour,
      il faudrait vérifier quelques points, le script ci-dessus n’étant qu’un exemple sommaire :
      - Vérifier que la fonction popen ne retourne pas FALSE cela peut être le cas si l’exécutable ffmpeg ne fait pas partie de votre « PATH » (mettre alors le chemin absolu vers l’exécutable)
      - La vidéo a-t-elle été correctement encodée après l’appel au script
      - Une directive safe_mode activée ne permettra l’exécution de programme que dans un répertoire prédéfini

      Il serait également préférable de spécifier des chemins absolus pour les fichiers vidéo.
      Essayez de lancer la commande ffmpeg dans une console depuis le répertoire du script afin de vérifier la sortie du programme

      • Krosk dit :

        Merci pour votre réponse (rapide !).
        J’ai vérifié les points que vous avez relevé, tout fonctionne bien à ce niveau.

        Ce qui me paraît bizarre :
        - quand j’exécute en ligne de commande « ffmpeg -params … », tout se passe bien, j’ai bien les logs de l’encodage qui apparaissent dans la console (temps d’exécution du script, etc).
        - mais si j’exécute « ffmpeg -params … > file.log », le fichier file.log est vide. C’est à dire que les logs ffmpeg qui apparaissent à l’écran ne peuvent pas être récupérées dans le fichier file.log. Et j’ai supposé après lecture de la doc de popen, que c’était la même raison pour laquelle je ne récupère les ce que je veux avec le fread…

        Je ne sais pas si j’ai été bien clair…
        En tout cas merci pour votre aide.

        • racer_x dit :

          Je sais pas si j’arrive trop tard, mais voila l’explication :

          ffmpeg n’écrit rien dans la sortie standard. Tous les messages que vous voyez dans le terminal sont écrits dans la sortie erreur. Pour le vérifier, tu peux faire :

          « ffmpeg -params … 2> file.log ».

          Ensuite pour ce qui est popen, c’est normal que le fread ne reçoive rien jusqu’a la fin de ffmpeg, car popen() lit par défaut la sortie standard du processus en mode lecture. Pour y remédier :

          _soit fermer le fd ou (handle) de la sortie out pour que la sortie err prenne sa place avant le popen

          _ soit se faire son propre popen avec : ouverture d’un pipe() en ecriture sur la sortie err dans le fils, en lecture coté pere, puis fork et exec ma_commande dans le fils.

          C’est pas très détaillé mais la solution est la, je connais pas PHP mais tu devrais trouver facilement des tutos sur ce sujet en PHP.

          • Stéphane dit :

            Exact, je ne pensais plus au fait que les sorties de ffmpeg sont faites sur la sortie d’erreur.
            En fait il faut rediriger la sortie d’erreur sur la sortie standard :
            ffmpeg [params] 2>&1.

            Je corrige les morceaux de code :)

  2. MyRé dit :

    Bonjour Stéphane,

    J’ai réussi à faire compresser mon fichier vidéo via ton script.
    Par contre je n’arrive pas à afficher les résultats…

    J’aimerais savoir si tu as modifié ton code depuis ton dernier post.

    Merci !

Laisser un commentaire

Subscribe to RSS Feed Follow me on Twitter!