Partage
  • Partager sur Facebook
  • Partager sur Twitter

Extraire une image d'une vidéo en utilisant ffmpeg

    20 septembre 2021 à 16:41:05

    Bonjour,

    Pour un projet, je souhaite extraire une image d'une vidéo en local (extension : .mp4, .avi, etc.) et pour cela, j'ai vu qu'il fallait utiliser la libraire ffmpeg.
    A noter que mon projet est hébergé sous o2Switch (Linux xxxxx 4.18.0-305.10.2.2.lve.el7h.x86_64 #1 SMP Wed Jul 28 13:09:44 UTC 2021 x86_64).

    Je me permets de venir vers vous, car ça fait plusieurs jours que je me bats avec ça, j'ai essayé plein de choses, mais rien y fait Je désespère un peu!!

    Premier code que j'ai essayé :

    <?php
    	error_reporting(E_ALL);
    	ini_set('display_errors', '1');
    	/*
    		Commands
    		
    		-i input file name
    		-an Disabled audio
    		-ss Get image from X seconds in the video
    		-s Size of the image
    	*/
    	// Get one thumbnail from the video
    	$ffmpeg = "http://[NOMDOMAINE]/ffmpeg-N-103630-g06de593303-linux64-gpl/bin/ffmpeg";
    	$videoFile = "http://[NOMDOMAINE]/sans-titre_OQnF6aR4.mp4";
    	$imageFile = "http://[NOMDOMAINE]/2.jpg";
    	$size = "120x90";
    	$getFromSecond = 5;
    	$cmd = "$ffmpeg -i $videoFile -an -ss $getFromSecond -s $size $imageFile";
    	if(!shell_exec($cmd)) {
    		echo "Thumbnaail Created !";
    	} else {
    		echo "Error Creating Thumbnail";
    	}
    ?>

    La librairie "ffmpeg-N-103630-g06de593303-linux64-gpl" a été téléchargée via le lien suivant : https://github.com/BtbN/FFmpeg-Build...21-09-15-12-22
    Lorsque j'exécute le code ci-dessus, il m'affiche le texte "Thumbnaail Created !" mais l'image n'est pas crée.



    Seconde méthode testée :

    <?php
    	// error_reporting(E_ALL);
    	ini_set("display_errors", 1);
     
    	require_once 'vendor/autoload.php';
     
    	use Char0n\FFMpegPHP\Movie;
    	echo 'z';
     
    	$videoInfo = new FFMpegMovie('test.mp4');
     
     
    	$videoFrames = $videoInfo->getFrameCount();
    	$largeur = $videoImage->getWidth();
    	$hauteur = $videoImage->getHeight();
     
    	// ici je divise le nombre d'images de la video par 2,
    	// ainsi je prendrai ma miniature en plein milieu de la video
    	$videoImage = $videoInfo->getFrame($videoFrames/2);
     
     
    	// je veux des miniatures de 300px de large je calcule donc le % de réduction pour avoir
    	// une largeur de 300px et une hauteur proportionnelle
    	$pourcentageReduction = (300/$largeur)*100;
     
    	// je calcule donc mes nouvelles valeur en appliquant la focntion
    	// ceil qui arrondit à l'entier supérieur (on ne peut pas avoir des moitiés de pixels !)
    	$newLargeur = ceil($largeur*($pourcentageReduction/100));
    	$newHauteur = ceil($hauteur*($pourcentageReduction/100));
    	$miniature = $videoImage->resize($newHauteur, $newLargeur);
     
    	$img = $miniature->toGDImage();
    	imagejpeg($img, 'ma_miniature.jpeg');
    ?>

    Pour cette méthode, j'ai suivi le lien suivant : https://github.com/char0n/ffmpeg-php
    Lorsque j'exécute le code ci-dessus, il m'affiche la chose suivante :

    Fatal error: Uncaught Error: Class 'FFMpegMovie' not found in /home/frjo3166/public_html/_video/test.php:10 Stack trace: #0 {main} thrown in /home/frjo3166/public_html/_video/test.php on line 10 



    Troisième méthode testée :
    En suivant le lien suivant http://ffmpeg-php.sourceforge.net/ j'ai téléchargé ceci : https://sourceforge.net/projects/ffmpeg-php/ et je l'ai installé sur mon projet.
    Lorsque j'effectue la partie "Testing the Installation" en exécutant le code suivant dans mon navigateur
    :

    <?
    	error_reporting(E_ALL);
    	ini_set("display_errors", 1);
     
    /*
     * This test script is not part of the automatic regression tests. It serves
     * as a simple manual test script and an example of the syntax for calling
     * the ffmpeg-php functions
     * 
     * To run it from the command line type 'php -q ffmpeg_test.php'or from a 
     * browser * copy this file into your web root and point your browser at it.
     */
     
    $extension = "ffmpeg";
    $extension_soname = $extension . "." . PHP_SHLIB_SUFFIX;
    $extension_fullname = PHP_EXTENSION_DIR . "/" . $extension_soname;
     
    // load extension
    if (!extension_loaded($extension)) {
        dl($extension_soname) or die("Can't load extension $extension_fullname\n");
    }
     
    function getDirFiles($dirPath)
    {
        if ($handle = opendir($dirPath))
        {
            while (false !== ($file = readdir($handle))) {
                $fullpath = $dirPath . '/' . $file;
                if (!is_dir($fullpath) && $file != "CVS" && $file != "." && $file != "..")
                    $filesArr[] = trim($fullpath);
            }
            closedir($handle);
        } 
     
        return $filesArr;   
    }
     
     
    if (php_sapi_name() != 'cgi') {
        echo '<pre>';
    }
     
    // print available functions and aliases
    printf("libavcodec version number: %d\n", LIBAVCODEC_VERSION_NUMBER);
    printf("libavcodec build number: %d\n", LIBAVCODEC_BUILD_NUMBER);
     
    // print available functions and aliases
    echo "\nFunctions available in $extension_fullname extension:\n";
    foreach(get_extension_funcs($extension) as $func) {
        echo $func."\n";
    }
     
    $class = "ffmpeg_movie";
    echo "\nMethods available in class $class:\n";
    foreach(get_class_methods($class) as $method) {
        echo $method."\n";
    }
     
    // put some movie files into this array to test the ffmpeg functions
    $movies = getDirFiles(dirname(__FILE__) . '/test_media');
     
    echo "--------------------\n\n";
    foreach($movies as $movie) {        
        $mov = new ffmpeg_movie($movie);
        printf("file name = %s\n", $mov->getFileName());
        printf("duration = %s seconds\n", $mov->getDuration());
        printf("frame count = %s\n", $mov->getFrameCount());
        printf("frame rate = %0.3f fps\n", $mov->getFrameRate());
        printf("comment = %s\n", $mov->getComment());
        printf("title = %s\n", $mov->getTitle());
        printf("author = %s\n", $mov->getAuthor());
        printf("copyright = %s\n", $mov->getCopyright());
        printf("frame height = %d pixels\n", $mov->getFrameHeight());
        printf("frame width = %d pixels\n", $mov->getFrameWidth());
        printf("has audio = %s\n", $mov->hasAudio() == 0 ? 'No' : 'Yes');
        printf("get pixel format = %s\n", $mov->getPixelFormat());
        printf("get video codec = %s\n", $mov->getVideoCodec());
        printf("get audio codec = %s\n", $mov->getAudioCodec());
        printf("get audio channels = %s\n", $mov->getAudioChannels());
        printf("get bit rate = %d kb/s\n", $mov->getBitRate());
    /*    
        while (1) {
            $frame = $mov->getFrame();
            if (!is_resource($frame)) {
                break;
            }
            echo "get frame() $frame" . "\n";
        }
     */    
        printf("get frame = %s\n", $mov->getFrame(10));
        printf("get frame number = %d\n", $mov->getFrameNumber());
        echo "\n--------------------\n\n";
    }
     
    if (php_sapi_name() != 'cgi') {
        echo '</pre>';
    }
     
    ?>

    Voici le résultat :

    Fatal error: Uncaught Error: Call to undefined function dl() in /home/frjo3166/public_html/_video/ext_ffmpeg_20050221/ffmpeg1/tests/test_ffmpeg.php:24 Stack trace: #0 {main} thrown in /home/frjo3166/public_html/_video/ext_ffmpeg_20050221/ffmpeg1/tests/test_ffmpeg.php on line 24 


    Quelqu'un saurait-il comment faire pour extraire une image d'une vidéo soit en utilisant l'une des méthodes présentées ci-dessus où je suis preneur pour toute autre solution sur un serveur o2switch (Linux xxxxx 4.18.0-305.10.2.2.lve.el7h.x86_64 #1 SMP Wed Jul 28 13:09:44 UTC 2021 x86_64) ?

    Merci par avance,
    Loïc.

    • Partager sur Facebook
    • Partager sur Twitter
      20 septembre 2021 à 18:16:47

      Avec ta première méthode tu devrais afficher le retour de shell_exec pour voir ce que ta ligne de commande retourne vraiment, là tu regardes juste si elle renvoie quelque chose ou pas (erreur de la commande ou pas). Suite à ça, tu verras le message renvoyer par la ligne de commande. (je mettrai aussi l'option -ss avant l'option -i, l'opération devrait être un peu plus rapide : $cmd = "$ffmpeg -ss $getFromSecond -i $videoFile -an -s $size $imageFile"; )

      Je pense aussi que les chemins devraient être définis localement (en relatif par rapport à ton fichier php par exemple). 

      Pour la seconde, il semble manquer le ./ au début du chemin du require (par rapport à la doc) => require_once './vendor/autoload.php'; (de même pour le chemin de la vidéo)

      Pour la 3ème méthode, la fonction PHP dl() a sans doute été supprimé (cf la doc https://www.php.net/manual/fr/function.dl.php ) il faudrait donc rajouter l'extension directement dans le fichier php.ini

      Edit: ta 2nde solution semble obsolète (fonctionnelle mais plus maintenue); une autre semblable, soutenue par les gars derrière symfony est https://github.com/PHP-FFMpeg/PHP-FFMpeg 

      -
      Edité par umfred 20 septembre 2021 à 18:24:03

      • Partager sur Facebook
      • Partager sur Twitter
        22 septembre 2021 à 16:33:40

        Bonjour umfred,

        Merci pour ta réponse.

        Première méthode :

        Avec ta première méthode tu devrais afficher le retour de shell_exec pour voir ce que ta ligne de commande retourne vraiment, là tu regardes juste si elle renvoie quelque chose ou pas (erreur de la commande ou pas). Suite à ça, tu verras le message renvoyer par la ligne de commande. (je mettrai aussi l'option -ss avant l'option -i, l'opération devrait être un peu plus rapide : $cmd = "$ffmpeg -ss $getFromSecond -i $videoFile -an -s $size $imageFile"; )

        Lorsque je fais :

        <?php
        error_reporting(E_ALL);
        ini_set('display_errors', '1');
        /*
        Commands

        -i input file name
        -an Disabled audio
        -ss Get image from X seconds in the video
        -s Size of the image
        */
        // Get one thumbnail from the video
        $ffmpeg = "ffmpeg-N-103630-g06de593303-linux64-gpl/bin/ffmpeg";
        $videoFile = "sans-titre_OQnF6aR4.mp4";
        $imageFile = "2.jpg";
        $size = "120x90";
        $getFromSecond = 5;
        $cmd = "$ffmpeg -i $videoFile -an -ss $getFromSecond -s $size $imageFile";
        echo shell_exec($cmd);
        ?>

        Je n'ai rien qui s'affiche.
        J'ai essayé de le lancer en ligne de commande, voici le résultat :

        ffmpeg-N-103630-g06de593303-linux64-gpl/bin/ffmpeg -ss 5 -i sans-titre_OQnF6aR4.mp4 -an -s 120x90 2.jpg
        ffmpeg-N-103630-g06de593303-linux64-gpl/bin/ffmpeg: error while loading shared libraries: libmvec.so.1: cannot open shared object file: No such file or directory

         Seconde méthode :

        Pour la seconde, il semble manquer le ./ au début du chemin du require (par rapport à la doc) => require_once './vendor/autoload.php'; (de même pour le chemin de la vidéo)

        Après avoir modifié le code comme ceci :

        <?php
        	// error_reporting(E_ALL);
            ini_set("display_errors", 1);
          
            require_once './vendor/autoload.php';
          
            use Char0n\FFMpegPHP\Movie;
        
            $videoInfo = new Movie('./test.mp4');
          
            $videoFrames = $videoInfo->getFrameCount();
            $largeur = $videoImage->getWidth();
            $hauteur = $videoImage->getHeight();
          
            // ici je divise le nombre d'images de la video par 2,
            // ainsi je prendrai ma miniature en plein milieu de la video
            $videoImage = $videoInfo->getFrame($videoFrames/2);
          
          
            // je veux des miniatures de 300px de large je calcule donc le % de réduction pour avoir
            // une largeur de 300px et une hauteur proportionnelle
            $pourcentageReduction = (300/$largeur)*100;
          
            // je calcule donc mes nouvelles valeur en appliquant la focntion
            // ceil qui arrondit à l'entier supérieur (on ne peut pas avoir des moitiés de pixels !)
            $newLargeur = ceil($largeur*($pourcentageReduction/100));
            $newHauteur = ceil($hauteur*($pourcentageReduction/100));
            $miniature = $videoImage->resize($newHauteur, $newLargeur);
          
            $img = $miniature->toGDImage();
            imagejpeg($img, './ma_miniature.jpeg');
        ?>

        Voilà ce que j'obtiens :

        Fatal error: Uncaught RuntimeException: FFmpeg is not installed on host server in /home/frjo3166/public_html/_video/vendor/char0n/ffmpeg-php/src/OutputProviders/FFMpegProvider.php:49 Stack trace: #0 /home/frjo3166/public_html/_video/vendor/char0n/ffmpeg-php/src/Movie.php(264): Char0n\FFMpegPHP\OutputProviders\FFMpegProvider->getOutput() #1 /home/frjo3166/public_html/_video/vendor/char0n/ffmpeg-php/src/Movie.php(250): Char0n\FFMpegPHP\Movie->setProvider(Object(Char0n\FFMpegPHP\OutputProviders\FFMpegProvider)) #2 /home/frjo3166/public_html/_video/test.php(9): Char0n\FFMpegPHP\Movie->__construct('./test.mp4') #3 {main} thrown in /home/frjo3166/public_html/_video/vendor/char0n/ffmpeg-php/src/OutputProviders/FFMpegProvider.php on line 49
        Edit: ta 2nde solution semble obsolète (fonctionnelle mais plus maintenue); une autre semblable, soutenue par les gars derrière symfony est https://github.com/PHP-FFMpeg/PHP-FFMpeg 

        Suite à cela, je l'ai installé et j'ai testé le code suivant :

        <?php
        	error_reporting(E_ALL);
        	ini_set("display_errors", 1);
        	 
        	require './vendor/autoload.php';
        	 
        	$video_file = './sans-titre_OQnF6aR4.mp4';
        	$frame_second = 15;
        	echo "sfr";
        	$ffmpeg = FFMpeg\FFMpeg::create([
        		  'ffmpeg.binaries'  => "/ffmpeg/bin/ffmpeg.exe",
        		  'ffprobe.binaries' => "/ffmpeg/bin/ffprobe.exe",
        		  'timeout'          => 3600,
        		  'ffmpeg.threads'   => 12,
        		]);
        	$video = $ffmpeg->open(dirname(__FILE__) . '/' . $video_file);
        	$video
        			->filters()
        			->resize(new FFMpeg\Coordinate\Dimension(320, 240))
        			->synchronize();
        	$video
        			->frame(FFMpeg\Coordinate\TimeCode::fromSeconds($frame_second))
        			->save('frame.jpg');
        	?>
        	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
        	<div class="container">
        		<p>
        			Frame à 00:<?= $frame_second; ?> :<br />
        			<img src="frame.jpg" alt="" class="w-100" />
        		</p>
        	 
        		<p>
        			Vidéo originale :
        			<video src="<?= $video_file; ?>" class="w-100" type="video/mp4" loop="true" muted="true" autoplay="true" controls="true" />
        		</p>
        	</div>

        Voici le message d'erreur :

        Fatal error: Uncaught Alchemy\BinaryDriver\Exception\ExecutableNotFoundException: Executable not found, proposed : /ffmpeg/bin/ffprobe.exe in /home/frjo3166/public_html/_video/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/AbstractBinary.php:159 Stack trace: #0 /home/frjo3166/public_html/_video/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Driver/FFProbeDriver.php(48): Alchemy\BinaryDriver\AbstractBinary::load(Array, NULL, Object(Alchemy\BinaryDriver\Configuration)) #1 /home/frjo3166/public_html/_video/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe.php(226): FFMpeg\Driver\FFProbeDriver::create(Object(Alchemy\BinaryDriver\Configuration), NULL) #2 /home/frjo3166/public_html/_video/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFMpeg.php(132): FFMpeg\FFProbe::create(Array, NULL, Object(Doctrine\Common\Cache\ArrayCache)) #3 /home/frjo3166/public_html/_video/test5.php(11): FFMpeg\FFMpeg::create(Array) #4 {main} Next FFMpeg\Exception\ExecutableNotFoundException: Unable to load FFProbe in /home/frjo3166/public_html/_video/vendor/ph in /home/frjo3166/public_html/_video/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Driver/FFProbeDriver.php on line 50

         Troisième méthode :

        Pour la 3ème méthode, la fonction PHP dl() a sans doute été supprimé (cf la doc https://www.php.net/manual/fr/function.dl.php ) il faudrait donc rajouter l'extension directement dans le fichier php.ini

        Etant sur l'hébergeur o2switch, je n'ai aucun accès direct au fichier php.ini (où alors je ne sais pas comment faire ;) ). Par contre dans le cPanel, il est possible d'activer des extensions, mais je ne trouve pas dl ni enable_dl.



        Merci par avance pour ton aide.

        • Partager sur Facebook
        • Partager sur Twitter
          22 septembre 2021 à 17:58:11

          1ère méthode: il semble manquer des librairies, peut-être qu'avec la build ffmpeg en linux64-lgpl-shared le problème sera résolu ?

          2nde méthode:

          Avec ton code modifié, il semble qu'il ne trouve pas ffmpeg à l'endroit désirée qui est indiqué ligne 59 du fichier /home/frjo3166/public_html/_video/vendor/char0n/ffmpeg-php/src/OutputProviders/FFMpegProvider.php (si je décrypte le message d'erreur)

          pour moi, avec l'extension de mon lien, le code devrait se résumer à:

          require 'vendor/autoload.php';
          $video_file = './sans-titre_OQnF6aR4.mp4';
          $frame_second = 15;
          $ffmpeg = FFMpeg\FFMpeg::create();
          $video = $ffmpeg->open($video_file);
          $video
              ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds($frame_seconds))
              ->save('frame.jpg')

          (ton erreur dit, en résumé, qu'il ne trouve pas ffmpeg dans le chemin que tu lui indiques; et la construction du chemin passer en paramètre de $ffmpeg->open me semble étrange)

          3ème méthode: je vois qu'il y a l'extension ffmpeg de proposer dans les extensions du PHP dans leur FAQ, suffit de la cocher en fait (donc plus besoin de la partie qui charge l'extension (lignes 18-21)) et ça devrait résoudre une bonne partie des problèmes (pour les 3 méthodes peut-être) https://faq.o2switch.fr/hebergement-mutualise/tutoriels-cpanel/selecteur-version-php  

          -
          Edité par umfred 22 septembre 2021 à 18:02:00

          • Partager sur Facebook
          • Partager sur Twitter
            22 septembre 2021 à 18:42:11

            Merci pour tes réponses, je n'ai pas eu le temps d'explorer tes réponses, mais je voulais te répondre pour la dernière :

            3ème méthode: je vois qu'il y a l'extension ffmpeg de proposer dans les extensions du PHP dans leur FAQ, suffit de la cocher en fait (donc plus besoin de la partie qui charge l'extension (lignes 18-21)) et ça devrait résoudre une bonne partie des problèmes (pour les 3 méthodes peut-être) https://faq.o2switch.fr/hebergement-mutualise/tutoriels-cpanel/selecteur-version-php 

            Lorsque je vais sur o2switch pour ajouter l'extension ffmpeg, il est introuvable comme le montre l'image ci-dessous :


             
            Cordialement,
            Loïc.

            EDIT DU 23/09/2021 :

            Je crois que c'est mort :(
            J'ai envoyé un message à o2Switch pour connaître la raison pour laquelle je ne pouvais pas installer l'extension "ffmpeg".

            Voici leur réponse :

            Bonjour, 
            
            L'extension ffmpeg n'est malheureusement pas installé en effet.
            
            Vous ne pourrez pas l'installer dans un contexte d'hébergement mutualisé.
            
            Cordialement,
            Ludovic

            Qu'en penses-tu ?

            -
            Edité par LoïcVivien 23 septembre 2021 à 16:45:40

            • Partager sur Facebook
            • Partager sur Twitter

            Extraire une image d'une vidéo en utilisant ffmpeg

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            • Editeur
            • Markdown