php视频上传和ffmpeg不会创建缩略图

时间:2019-01-14 09:04:07

标签: php ffmpeg

我正在尝试为我的项目制作视频上传功能。但是我对ffmpeg部分有问题。 ffmpeg已安装在我的服务器上。但是我无法得到任何缩略图。我尝试使用以下ffmpeg代码创建缩略图:

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

但是在将var_dump();var_dump($videoa);用于var_dump($videob);时会出现这种情况

  

string(74)“ https://mywebsite.com/uploads/video/ey1kXNew_video.flv:   输入/输出错误“字符串(0)”“

如果我这样使用shell_exec

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

var_dumps()给我NULL NULL

我在这里想念什么,任何人都可以帮助我吗?

这是我完整的视频上传代码:

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

我也这样测试过:

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

我看到以下回声

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

再尝试一次,我得到以下提示: https://mywebsite.com/uploads/video/1547892356_video.flv:连接被拒绝

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

4 个答案:

答案 0 :(得分:3)

如果您使用的是https,则必须为ffmpeg配置ssl支持(ffmpeg over https fails)。

答案 1 :(得分:1)

使用此代码: `           //应该在下面的代码中添加缩略图路径           //测试拇指

      $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;
        }`

答案 2 :(得分:1)

参数必须转义,您不能只是在其中转储变量作为参数,URL包含诸如&之类的东西,它们在shell中具有特殊含义。例如,

  

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

应该是这个:

  

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

但是..

  

请问有人可以帮助我吗?

这里有2个获取缩略图的函数,getThumbPng2()将首先使用curl下载整个视频,将其保存到一个临时文件中,然后使用ffmpeg提取网址(如果ffmpeg不是使用http构建的,则更加安全) / https /什么支持,或者ffmpeg是否被防火墙等阻止,但缺点是速度可能慢得多

第一个功能无需先获取视频即可从ffmpeg获取缩略图(这可能会更快,因为ffmpeg只会读取所需部分而不是下载整个视频,但由于上述原因可能无法正常工作)

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

用法示例:

<?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 :(得分:1)

我认为您可以在服务器上检查ffmpeg安装的文件。

$ffmpeg = trim(shell_exec('whereis ffmpeg')); // This will show you which path FFMPEG 

if (empty($ffmpeg))
{
    die('ffmpeg not available');
}else{
    echo $ffmpeg;
}

然后尝试:

$cmd = shell_exec("$ffmpeg -i $videoUrlp.mp4 -ss 00:00:02.000 -vframes 1 $videoUrlp.png");