【问题标题】:php video upload and ffmpeg won't create a thumbnailphp视频上传和ffmpeg不会创建缩略图
【发布时间】:2019-06-08 06:08:40
【问题描述】:

我正在尝试为我的项目制作视频上传功能。但我对 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); 时,我会明白这一点

字符串(74) "https://mywebsite.com/uploads/video/ey1kXNew_video.flv: 输入/输出错误" string(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()给我NULLNULL

请帮我看看我哪里错了。

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

$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: Connection denied

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

这是最后一个 shell_exec 输出:

 $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 版本 2.8.15 版权所有 (c) 2000-2018 FFmpeg 开发人员使用 gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-36) 构建 配置:--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 1. 53. 3.100 输入#0,mov,mp4,m4a,3gp,3g2,mj2,来自'https://website.com/uploads/video/e0J6HwtK_video.mp4':元数据: 主要品牌:mp42 次要版本:0 兼容品牌:isommp42 创建时间:2018-01-01 12:09:49 持续时间:00:00:41.49,开始: 0.000000,比特率:230 kb/s 流 #0:0(und):视频:h264(约束基线)(avc1 / 0x31637661),yuv420p,240x360 [SAR 1:1 DAR 2:3],158 kb/s、9.73 fps、9.73 tbr、19462 tbn、19.46 tbc(默认) 元数据: handler_name : VideoHandler Stream #0:1(und): 音频: aac (LC) (mp4a / 0x6134706D), 44100 Hz, 单声道, fltp, 71 kb/s (默认) 元数据: 创建时间:2018-01-01 12:09:49 handler_name:IsoMedia 文件 由 Google 制作,2011 年 5 月 11 日 [swscaler @ 0xc8c580] 已弃用像素 使用的格式,确保您正确设置了范围输出#0,mjpeg, 到“https://website.com/uploads/video/e0J6HwtK_video.png”:元数据: 主要品牌:mp42 次要版本:0 兼容品牌:isommp42 编码器: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 (默认)元数据:handler_name:VideoHandler 编码器: Lavc56.60.100 mjpeg 流映射:Stream #0:0 -> #0:0 (h264 (native) -> mjpeg (native)) 按 [q] 停止,[?] 帮助 frame= 5 fps=0.0 q=1.6 Lsize= 100kB time=00:00:05.00 bitrate= 163.9kbits/s dup=0 drop=32 视频:100kB 音频:0kB 字幕:0kB 其他流:0kB 全局 标头:0kB 复用开销:0.000000%

【问题讨论】:

  • 如果在 shell 中运行 FFMPEG 命令会怎样?此外,要创建MCV example,您可以先尝试在新的 PHP 中运行它:var_dump(exec('/usr/bin/ffmpeg -version'));
  • @Raptor 打印如下:string(38) "libpostproc 53. 3.100 / 53. 3.100"
  • @Raptor shell_exec 给 mie NULL NULL in var_dump();
  • 如果 1 行示例能够提供有效的输出(就像您刚刚测试的那样),那么问题仅在于 FFMPEG 命令本身。尝试直接在 shell 中运行它,而不是通过 PHP。
  • 在您的计算机/服务器中运行。在基于 Linux 的机器中使用终端/Shell 控制台。是 Mac 还是 Linux?

标签: php ffmpeg


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      参数必须被转义,你不能只是将变量作为参数转储在那里,url包含像&amp;这样的东西,在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 提取 url(如果 ffmpeg 不是使用 http 构建的,这会更安全/https/whatever 支持,或者 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}";
      }
      

      【讨论】:

        【解决方案4】:

        我想你可以在你的服务器上检查 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");
        

        【讨论】:

          猜你喜欢
          • 2011-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-11
          • 2013-12-20
          • 2015-01-24
          • 2012-02-24
          • 2021-04-24
          相关资源
          最近更新 更多