php video upload and ffmpeg won't create a thu

2019-06-24 09:49发布

问题:

I am trying to make a video upload feature for my project. But I have a problem with ffmpeg section. ffmpeg is already installed on my server. But i can not get any thumbnail. I have try to create thumbnail using the following code:

$videoa = exec("/usr/bin/ffmpeg  -i $videoUrlp.flv -f flv -s 650x390 $videoUrlp.mp4 2>&1");
$videob = exec("/usr/bin/ffmpeg  -i $videoUrlp.mp4 -vcodec png -ss 00:00:5 -s 650x390 -vframes 1 -an -f rawvideo $videoUrlp.png");

But i ge this when use var_dump(); for var_dump($videoa); and var_dump($videob);

string(74) "https://mywebsite.com/uploads/video/ey1kXNew_video.flv: Input/output error" string(0) ""

Also if i use the shell_exec like this:

$videoa = shell_exec("/usr/bin/ffmpeg  -i $videoUrlp.flv -f flv -s 650x390 $videoUrlp.mp4");
$videob = shell_exec("/usr/bin/ffmpeg  -i $videoUrlp.mp4 -vcodec png -ss 00:00:5 -s 650x390 -vframes 1 -an -f rawvideo $videoUrlp.png");

and the var_dumps() giving me NULL NULL.

Please help me where am I wrong.

And here is my full video upload code:

$valid_formats = array("mp4","MP4","flv");
            if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST") {
               $name = $_FILES['uploading']['name'];
               $size = $_FILES['uploading']['size'];
               if(strlen($name)) {
                   $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); 
                   $name = alphaID(microtime(true) * 10000).'_video';
                   if(in_array($ext,$valid_formats)) {
                   if($size<(50024*50024)) {
                      $GetVideoName = $name;
                      $video_ext=$ext;
                       $tmp = $_FILES['uploading']['tmp_name'];
                       if(move_uploaded_file($tmp, $videoPath.$GetVideoName.'.'.$video_ext)) {
                           $videoUrlp = $base_url.'uploads/video/'.$GetVideoName;
                           $videoa = exec("/usr/bin/ffmpeg  -i $videoUrlp.flv -f flv -s 650x390 $videoUrlp.mp4 2>&1");
                           $videob = exec("/usr/bin/ffmpeg  -i $videoUrlp.mp4 -vcodec png -ss 00:00:5 -s 650x390 -vframes 1 -an -f rawvideo $videoUrlp.png");
                           echo var_dump($videoa);
                           echo var_dump($videob);

                        } else {
                            echo "Fail upload folder with read access.";
                        }
                     } else
                        echo "Image file size max 1 MB";                    
                     } else
                        echo "invalidvieo"; 
                 } else
                    echo "Please select image..!";
                 exit;
              }

I have tested also like this way:

echo exec("/usr/bin/ffmpeg -i $videoUrlp.flv -ar 22050 -ab 32 -f flv -s 780x400 $videoUrlp.$video_ext");
echo exec("/usr/bin/ffmpeg -i $videoUrlp.$video_ext -deinterlace -an -ss 1 -t 00:00:05 -r 1 -y -vcodec mjpeg -f mjpeg $videoUrlp.png 2>&1");

and I see the following echo

video:71kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

and another try then I get this note: https://mywebsite.com/uploads/video/1547892356_video.flv: Connection refused

echo exec("/usr/bin/ffmpeg -i $videoUrlp.flv -ar 22050 -ab 32 -f flv -s 780x400 $videoUrlp.$video_ext");
echo exec("/usr/bin/ffmpeg -i $videoUrlp.$video_ext -deinterlace -an -ss 1 -t 00:00:05 -r 1 -y -vcodec mjpeg -f mjpeg $videoUrlp.png 2>&1");

Here is last shell_exec Output:

 $local = 'https://website.com/uploads/video/'.$GetVideoName.'.'.$video_ext;
 $localTumb = 'https://website.com/uploads/video/'.$GetVideoName.'.png';
 echo shell_exec("/usr/bin/ffmpeg -i $local -deinterlace -an -ss 1 -t 00:00:05 -r 1 -y -vcodec mjpeg -f mjpeg $localTumb 2>&1");    

ffmpeg version 2.8.15 Copyright (c) 2000-2018 the FFmpeg developers built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-36) configuration: --prefix=/usr --bindir=/usr/bin
--datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib64 --mandir=/usr/share/man --arch=x86_64 --optflags='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic' --extra-ldflags='-Wl,-z,relro ' --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvo-amrwbenc --enable-version3 --enable-bzlib --disable-crystalhd --enable-gnutls --enable-ladspa --enable-libass --enable-libcdio --enable-libdc1394 --enable-libfdk-aac --enable-nonfree --disable-indev=jack --enable-libfreetype --enable-libgsm --enable-libmp3lame --enable-openal --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvorbis --enable-libv4l2 --enable-libx264 --enable-libx265 --enable-libxvid --enable-x11grab --enable-avfilter --enable-avresample --enable-postproc --enable-pthreads --disable-static --enable-shared --enable-gpl --disable-debug --disable-stripping --shlibdir=/usr/lib64 --enable-runtime-cpudetect libavutil 54. 31.100 / 54. 31.100 libavcodec 56. 60.100 / 56. 60.100 libavformat 56. 40.101 / 56. 40.101 libavdevice 56. 4.100 / 56. 4.100 libavfilter 5. 40.101 / 5. 40.101 libavresample 2. 1. 0 / 2. 1. 0 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 2.101 / 1. 2.101 libpostproc 53. 3.100 / 53. 3.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'https://website.com/uploads/video/e0J6HwtK_video.mp4': Metadata: major_brand : mp42 minor_version : 0 compatible_brands: isommp42 creation_time : 2018-01-01 12:09:49 Duration: 00:00:41.49, start: 0.000000, bitrate: 230 kb/s Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 240x360 [SAR 1:1 DAR 2:3], 158 kb/s, 9.73 fps, 9.73 tbr, 19462 tbn, 19.46 tbc (default) Metadata: handler_name : VideoHandler Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 71 kb/s (default) Metadata: creation_time : 2018-01-01 12:09:49 handler_name : IsoMedia File Produced by Google, 5-11-2011 [swscaler @ 0xc8c580] deprecated pixel format used, make sure you did set range correctly Output #0, mjpeg, to 'https://website.com/uploads/video/e0J6HwtK_video.png': Metadata: major_brand : mp42 minor_version : 0 compatible_brands: isommp42 encoder : Lavf56.40.101 Stream #0:0(und): Video: mjpeg, yuvj420p(pc), 240x360 [SAR 1:1 DAR 2:3], q=2-31, 200 kb/s, 1 fps, 1 tbn, 1 tbc (default) Metadata: handler_name : VideoHandler encoder : Lavc56.60.100 mjpeg Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> mjpeg (native)) Press [q] to stop, [?] for help frame= 5 fps=0.0 q=1.6 Lsize= 100kB time=00:00:05.00 bitrate= 163.9kbits/s dup=0 drop=32 video:100kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

回答1:

If you are using https, your ffmpeg has to be configured with ssl support (ffmpeg over https fails).



回答2:

arguments have to be escaped, you can't just dump variables in there as arguments, urls contain stuff like & which has special meaning in shells.. for example this

exec("/usr/bin/ffmpeg -i $videoUrlp.flv -f flv -s 650x390 $videoUrlp.mp4 2>&1");

should have been this:

exec("/usr/bin/ffmpeg -i ".escapeshellarg($videoUrlp.flv)." -f flv -s 650x390 ".escapeshellarg($videoUrlp.mp4)." 2>&1");

but..

please anyone can help me?

here are 2 functions to get the thumbnail, getThumbPng2() will download the entire video first with curl, saving it to a temporary file, and then extract the url with ffmpeg (this is safer if ffmpeg isn't built with http/https/whatever support, or if ffmpeg is blocked by a firewall or whatever, but the downside is that it's potentially much slower)

and the first function fetches the thumbnail from ffmpeg without fetching the video first (which is potentially much faster as ffmpeg will just read the required parts instead of downloading the entire video, but may not work for reasons explained above)

function getThumbPng2(string $uri, string &$imageBinary=NULL, string &$stderr=NULL):bool{
    $ch=curl_init($uri);
    if(!$ch){
        $imageBinary=$stderr="curl_init() failed";
        return false;
    }
    $tmph=tmpfile();
    curl_setopt_array($ch,array(
        CURLOPT_SSL_VERIFYPEER=>false,
        CURLOPT_SSL_VERIFYHOST=>false,
        CURLOPT_FILE=>$tmph
    ));
    if(!curl_exec($ch)){
        $imageBinary=$stderr="curl error: ".curl_errno($ch).": ".curl_error($ch);
        curl_close($ch);
        fclose($tmph);
        return false;
    }
    curl_close($ch);
    $ret=getThumbPng(stream_get_meta_data($tmph)['uri'],$imageBinary,$stderr);
    fclose($tmph);
    return $ret;
}
function getThumbPng(string $uri,string &$imageBinary=NULL, string &$stderr=NULL):bool{
    $imageBinary="";
    $stderr="";
    $descriptorspec = array(
        0 => array("pipe", "rb"),  // stdin
        1 => array("pipe", "wb"),  // stdout
        2 => array("pipe","wb") // stderr 
    );
    $cmd="ffmpeg -i ".escapeshellarg($uri)." -ss 00:00:3 -s 650x390 -vframes 1 -c:v png -f image2pipe -";
    // var_dump($cmd);
    $proc = proc_open($cmd, $descriptorspec, $pipes);
    if(!$proc){
        $stderr="failed to start ffmpeg, proc_open(\"ffmpeg\",...) failed. (why? don't know, and PHP has no way of telling us either, afaik.)";
        return false;
    }
    fclose($pipes[0]);// by default stdin is *inherited*, which is not what we want,
    // so to avoid the default behaviour, we explicitly create a stdin pipe and close it.
    $fetch=function()use(&$pipes,&$imageBinary,&$stderr){
        $tmp=stream_get_contents($pipes[1]);
        if(is_string($tmp)){
            $imageBinary.=$tmp;
        }
        $tmp=stream_get_contents($pipes[2]);
        if(is_string($tmp)){
            $stderr.=$tmp;
        }   
    };
    while(($status=proc_get_status($proc))['running']){
        usleep(10*1000);
        $fetch();
    }
    $fetch();
    fclose($pipes[1]);
    fclose($pipes[2]);
    $ret=$status['exitcode'];
    proc_close($proc);
    //var_dump($ret);
    return ($ret===0);
}

example usage:

<?php
if(getThumbPng("http://files.4x4norway.no/2018/vik2.webm",$imageBinary,$stderr)){
    echo "got a thumbnail! (the png binary data is in the \$imageBinary variable.)";
}else{
    var_dump($imageBinary);
    echo "failed to create thumbnail! error: {$stderr}";
}


回答3:

use this code: ` //thumb path should be added in the below code //test for thumb

      $dir_img='uploads/';
      $mediapath='123.jpg';

      $file_thumb=create_movie_thumb($dir_img.$mediapath,$mediapath,$mediaid);

        $name_file=explode(".",$mediapath);
        $imgname="thumb_".$name_file[0].".jpg";     



        /*
          Function to create video thumbnail using ffmpeg
        */
        function create_movie_thumb($src_file,$mediapath,$mediaid)
        {
            global $CONFIG, $ERROR;

            $CONFIG['ffmpeg_path'] = '/usr/local/bin/'; // Change the path according to your server.
            $dir_img='uploads/';
            $CONFIG['fullpath'] = $dir_img."thumbs/";

            $src_file = $src_file;
            $name_file=explode(".",$mediapath);
            $imgname="thumb_".$name_file[0].".jpg";
            $dest_file = $CONFIG['fullpath'].$imgname;

            if (preg_match("#[A-Z]:|\\\\#Ai", __FILE__)) {
                // get the basedir, remove '/include'
                $cur_dir = substr(dirname(__FILE__), 0, -8);
                $src_file = '"' . $cur_dir . '\\' . strtr($src_file, '/', '\\') . '"';
                $ff_dest_file = '"' . $cur_dir . '\\' . strtr($dest_file, '/', '\\') . '"';
            } else {
                $src_file = escapeshellarg($src_file);
                $ff_dest_file = escapeshellarg($dest_file);
            }

            $output = array();

            if (eregi("win",$_ENV['OS'])) {
                // Command to create video thumb
                $cmd = "\"".str_replace("\\","/", $CONFIG['ffmpeg_path'])."ffmpeg\" -i ".str_replace("\\","/" ,$src_file )." -an -ss 00:00:05 -r 1 -vframes 1 -y ".str_replace("\\","/" ,$ff_dest_file);
                exec ("\"$cmd\"", $output, $retval);

            } else {
                // Command to create video thumb
                $cmd = "{$CONFIG['ffmpeg_path']}ffmpeg -i $src_file -an -ss 00:00:05 -r 1 -vframes 1 -y $ff_dest_file";
                exec ($cmd, $output, $retval);

            }


            if ($retval) {
                $ERROR = "Error executing FFmpeg - Return value: $retval";
                if ($CONFIG['debug_mode']) {
                    // Re-execute the command with the backtick operator in order to get all outputs
                    // will not work if safe mode is enabled
                    $output = `$cmd 2>&1`;
                    $ERROR .= "<br /><br /><div align=\"left\">Cmd line : <br /><span style=\"font-size:120%\">" . nl2br(htmlspecialchars($cmd)) . "</span></div>";
                    $ERROR .= "<br /><br /><div align=\"left\">The ffmpeg program said:<br /><span style=\"font-size:120%\">";
                    $ERROR .= nl2br(htmlspecialchars($output));
                    $ERROR .= "</span></div>";
                }
                @unlink($dest_file);
                return false;
            }

            $return = $dest_file;
            //@chmod($return, octdec($CONFIG['default_file_mode'])); //silence the output in case chmod is disabled
            return $return;
        }`


标签: php ffmpeg