• php如何截取出视频中的指定帧作为图片


    php如何截取出视频中的指定帧作为图片

    一、总结

    一句话总结:截取视频指定帧为图片,php ffmpeg扩展已经完美实现,并且php ffmpeg是开源的

    二、php如何截取出视频中的指定帧作为图片

    截取视频指定帧为图片,php ffmpeg扩展已经完美实现:

     
    1
    2
    3
    4
    5
    6
    $movie = new ffmpeg_movie($video_filePath);
    $ff_frame = $movie->getFrame(1);
    $gd_image = $ff_frame->toGDImage();
    $img="./test.jpg";
    imagejpeg($gd_image, $img);
    imagedestroy($gd_image);

    然而问题来了,智能手机拍摄的视频,由于拍摄方向不同,视频会被旋转,并带上meta信息rotate,当你相对视频截取frame图片的时候,如果有rotate信息的视频,frame也是旋转的,因此你需要将截取的图片相应的旋转。

    然后php ffmpeg扩展并无法获知rotation信息(php ffmpeg扩展文档),但可以通过ffmpeg命令行获取:

    /usr/local/ffmpeg/bin/ffprobe test.mp4 -show_streams  | grep rotate
    用php简单封装下如下:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function get_video_orientation($video_path) {
      $cmd = "/usr/local/ffmpeg/bin/ffprobe " . $video_path . " -show_streams 2>/dev/null";
      $result = shell_exec($cmd);
       
      $orientation = 0;
      if(strpos($result, 'TAG:rotate') !== FALSE) {
        $result = explode(" ", $result);
        foreach($result as $line) {
          if(strpos($line, 'TAG:rotate') !== FALSE) {
            $stream_info = explode("=", $line);
            $orientation = $stream_info[1];
          }
        }
      }
      return $orientation;
    }

    使用imagerotate()函数就可以旋转截图:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $movie = new ffmpeg_movie($video_filePath);
    $frame = $movie->getFrame(1);
    $gd = $frame->toGDImage();
    if ($orientation = $this->get_video_orientation($video_filePath)) {
      $gd = imagerotate($gd, 360-$orientation, 0);
    }
    $img="./test.jpg";
    imagejpeg($gd, $img);
    imagedestroy($gd_image);

    最后还有一个麻烦事,不是所有的播放器和浏览器都可对video识别orientation并自动rotate,如果你想对视频进行旋转,可通过ffmpeg命令解决:

    /usr/local/ffmpeg/bin/ffmpeg -i input.mp4 -vf 'transpose=3' -metadata:s:v:0 rotate=0

    参考:php截取视频指定帧为图片_php技巧_脚本之家
    https://www.jb51.net/article/84359.htm

    三、ffmpeg-php扩展

    php视频缩略图,较常用的是ffmpeg-php

    1: 安装 ffmpeg

    ffmpeg的下载链接  http://ffmpeg.org/download.html

    解压安装包

    tar -jxvf ffmpeg-x.x.tar.bz2

    进入目录

    cd ffmpeg-x.x

    编译安装

    ./configure --enable-shared && make && make install

    安装完成之后 执行 ffmpeg -version

    如果能够出现类似下列信息,说明ffmpeg安装成功。

    ffmpeg version 2.5.11 Copyright (c) 2000-2016 the FFmpeg developers
    built on Apr 17 2017 16:47:15 with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-11)
    configuration: --enable-shared
    libavutil      54. 15.100 / 54. 15.100
    libavcodec     56. 13.100 / 56. 13.100
    libavformat    56. 15.102 / 56. 15.102
    libavdevice    56.  3.100 / 56.  3.100
    libavfilter     5.  2.103 /  5.  2.103
    libswscale      3.  1.101 /  3.  1.101
    libswresample   1.  1.100 /  1.  1.100
    

     2 安装ffmpeg-php

    官方的下载链接

    https://sourceforge.net/projects/ffmpeg-php/files/ffmpeg-php/

    官方版本已经很久很久不更新了,我在centos 7 + php5.6&php7.1   centos6.5+php5  试了都不行。在configure完 make的时候会报错。

    后来在github上找了一个版本。在centos7.2+php5.5.6 上编译安装成功 (centos7 + php7.1还是不行)

    地址:    git clone https://github.com/tony2001/ffmpeg-php.git 

    也可以访问我的百度云盘进行下载

    https://pan.baidu.com/s/1skQTVlj

    进入 ffmpeg-php目录 进行编译扩展

    /usr/local/php/bin/phpize   

    ./configure --with-php-config=/usr/local/php/bin/php-config

    make && make install

    注意(如果make之后出现错误,那就是ffmpeg-php版本的问题,别再折腾了,换版本吧(或者降低php版本试试))。

    在php的配置文件 php.ini中 添加  

    extension=ffmpeg.so
    

    重启php。在 phpinfo()中查看有无ffmpeg信息。

    有的话就OK

    或者执行 

    /usr/local/php/bin/php -i |grep ffmpeg
    

     要是有输出的话OK

    参考:ffmpeg-php扩展 - 思此狂 - 博客园
    https://www.cnblogs.com/jkklearn/p/6737467.html
     
     

    二、PHP的ffmpeg使用

    因为项目需求,同事写了一个ffmpeg的类,但是因为临时来了一个其他的项目,所以这个未完成的类就交给我来完成,所以我就把这个类的完成过程记录一下

    <?php
    include('FFmpegSupport.php');
    //http://blog.csdn.net/doublefi123/article/details/24325159 基本用法
    class FFmpegManage
    {
        /**
         * ffmpeg默认结构:ffmpeg  [全局选项] [输入文件选项] -i (输入文件路径) [输出文件选项] (输出文件路径)
         * 其中[]括号里的是可选,()括号里的是必选的
         */
        private $ExecString = 'ffmpeg.exe '; //命令语句
        private $GlobalOptions = ''; //全局选项
        private $ErrMessage = array(); //错误信息
        private $InputFileOptionsString = ''; //输入文件选项
        private $InputFileOptions = array(); //输入文件选项数组
        private $InputFilePath = array(); //输入文件路径
        private $OutFileOptions = ''; //输出文件选项
        private $OutFilePath = ''; //输出文件路径
        private $OutFileTybe = ''; //输入文件的后缀名
        //可配置参数
        private $config = array(
            'startTime'=>1,        //文件开始时间
            'fmt'=>1,               //文件格式
            'codec'=>1,             //解码器
            'audioCodec'=>1,       //音频解码器
            'bitRate'=>1,           //比特率
            'sampleRate'=>1,        //采样率
            'audioChannels'=>1,    //声道数
            'endTime'=>1,           //结束时间
            'timeLength'=>1,        //文件时间长度
        );
        /**
            $Config = array(
                'inputFilePath'            =>  array(),   //输入路径(不能为空)
                'outputFilePath'                => '',     //输出路径(不能为空)
                //输入文件选项(为空时不执行)
                'fileOption'        =>array(
                    'studyTime'             => '',               //文件开始时间
                    'fmt'                    => '',              //文件格式
                    'codec'                  => '',             //解码器
                    'audioCodec'            => '',              //音频解码器
                    'bitRate'               => '',              //比特率
                    'sampleRate'            => '',              //采样率
                    'audioChannels'         => '',             //声道数
                    'endTime'                => '',            //结束时间
                    'timeLength'             => '',            //文件时间长度
                ),
            );
         **/
    
        public function setConfig($config){
    
            @$fileOption = $config['fileOption'];
            @$inputFilePath =  $config['inputFilePath'];
            @$outputFilePath =  $config['outputFilePath'];
    
            //判断是否有输入或输出路径
            if(empty($inputFilePath) && empty($outputFilePath)){
                $this->setErrMessage('inputFilePath and outputFilePath is null');
            }
    
            //获取输入文件路径
            if(!is_array($inputFilePath)){
                $filePathArray = explode('+',$inputFilePath);
            }else{
                $filePathArray = $inputFilePath;
            }
    
            if(!empty($fileOption))
                //遍历输入文件路径
                foreach($filePathArray as $filePath){
                    //将配置信息进行遍历
                    foreach($fileOption as $key => $value){
                        //判断配置信息是否正确,如果不正确跳过
                        if(!empty($this->config[$key]) && !empty($value)){
                            //加载配置
                            $this->$key($value);
                        }
                    }
                    //判断文件是否能进行写入
                    if( file_exists( $filePath ) ){
                        //将输入配置与输入文件进行关联
                        $this->InputFilePath[] = '-i ' . $filePath . ' ';
                        $this->InputFileOptions[] = '-i ' . $filePath . ' '.$this->InputFileOptionsString;
                        $this->InputFileOptionsString = '';
                    }else{
                        $this->setErrMessage('Input File is not Exist!!');
                    }
                }
    
            $this->OutFileTybe = substr( $outputFilePath , -4 );
            $this->OutFilePath = $outputFilePath . ' ';
            return $this;
        }
    
        /**
         * 设置ffmpeg执行时对所有选项都回答yes,例文件已存在,要覆盖的时候程序会等待回答yes or on ,有时候不添加会出错
         * @return $this
         */
        public function setAnswerAllYes(){
            $this->GlobalOptions .= ' -y ';
            return $this;
        }
    
    ////////////////////////////配置信息载入////////////////////////////
        /**
         * 强制设定文件的格式,需要使用ffmpeg当前版本支持的名称(缺省使用扩展名称)
         * @param $_fileType String 文件类型
         */
        private function fmt( $_fileType ){
             empty( $_fileType ) ?
                 $this->setErrMessage( 'File Type is empty!!'):
                 $this->InputFileOptionsString .= '-f ' . $_fileType . ' ';
        }
    
        /**
         * 设置输入文件的起始时间点,在此时间点开始读取数据 ,
         * @param $_time int 起始时间(单位:秒s)
         */
        private function startTime( $_time ){
            $_time = (int)$_time;
            empty($_time) && ($_time < 0) ?
                $this->setErrMessage( " $_time must be biger than 0"):
                $this->InputFileOptionsString .= '-ss ' . $_time . ' ';
    
        }
    
        /**
         * 指定解码器,需输入此版本支持的解码器
         * @param $_codecName
         */
        private function codec( $_codecName ){
            empty( FFmpegSupport::$InputProtocolsArray[ $_codecName ] )  && empty( FFmpegSupport::$OutputProtocolsArray[ $_codecName ] ) ?
                $this->setErrMessage( 'This versions ffmpeg is not support this codec!!' ):
                $this->InputFileOptionsString .= '-c ' . $_codecName . ' ';
        }
    
        /**
         *指定音频解码器
         * @param $_audioCodecName String 解码器名称,需输入此版本ffmpeg支持的解码器
         */
        private function audioCodec( $_audioCodecName ){
            empty( FFmpegSupport::$InputProtocolsArray[ $_audioCodecName ] )  && empty( FFmpegSupport::$OutputProtocolsArray[ $_audioCodecName ] ) ?
                $this->setErrMessage( 'This versions ffmpeg is not support this codec!!' ):
                $this->InputFileOptionsString .= '-acodec ' . $_audioCodecName . ' ';
        }
    
        /**
         * 设置音频流的采样率
         * 可以使用的采样率
         * 8,000 Hz - 电话所用采样率, 对于人的说话已经足够
         * 11,025 Hz
         * 22,050 Hz - 无线电广播所用采样率
         * 32,000 Hz - miniDV 数码视频 camcorder、DAT (LP mode)所用采样率
         * 44,100 Hz - 音频 CD, 也常用于 MPEG-1 音频(VCD, SVCD, MP3)所用采样率
         * 47,250 Hz - 商用 PCM 录音机所用采样率
         * 48,000 Hz - miniDV、数字电视、DVD、DAT、电影和专业音频所用的数字声音所用采样率
         * 50,000 Hz - 商用数字录音机所用采样率
         * 96,000 或者 192,000 Hz - DVD-Audio、一些 LPCM DVD 音轨、BD-ROM(蓝光盘)音轨、和 HD-DVD (高清晰度 DVD)音轨所用所用采样率
         * 2.8224 MHz - Direct Stream Digital 的 1 位 sigma-delta modulation 过程所用采样率。
         * @param $_audioSampleRate int 音频采样率,单位Hz
         */
    
        private function sampleRate( $_audioSampleRate ){
             $_audioSampleRate < 1 ?
                 $this->setErrMessage( 'AudioSampleRate can not smaller than 0!!'):
                 $this->InputFileOptionsString .= '-ar ' . $_audioSampleRate . ' ';
        }
    
        /**
         * 设置音频流的比特率
         * @param $_audioBitRate int 音频比特率,单位bps
         */
        private function bitRate( $_audioBitRate ){
            $_audioBitRate < 1 ?
                $this->setErrMessage( 'BitRate can not smaller than 0!!'):
                $this->InputFileOptionsString .= '-ab ' . $_audioBitRate . ' ';
        }
    
        /**
         * 设置音频流的声道数目
         * @param $_channels int 通道数目整数,大于等于1
         */
        private function audioChannels( $_channels ){
            $_channels<1 ?
                $this->setErrMessage( 'Channels count must be biger than 0!!'):
                $this->InputFileOptionsString .= '-ac ' . $_channels . ' ';
        }
    
        /**
         * 设置终止时间点
         * @param $_endTimePoint String 终止时间点 hh:mm:ss
         */
        private function endTime( $_endTimePoint ){
            $_endTimePoint = trim( $_endTimePoint );
            $_endTimePoint < 0 ?
                $this->setErrMessage( 'Time can not be less than 0!!'):
                $this->OutFileOptions .= '-to ' . $_endTimePoint . ' ';
        }
    
        /**
         * 设置时间长度
         * @param $_time String 时间长度 hh:mm:ss
         * @return $this Class 此类
         */
        private function timeLength( $_timeLen ){
            $_timeLen = trim( $_timeLen );
            $_timeLen < 0 ?
                $this->setErrMessage( 'Time can not be less than 0!!'):
                $this->OutFileOptions .= '-t ' . $_timeLen . ' ';
        }
    
    
    ////////////////////////////处理音频////////////////////////////
        /**
         * 修改音频的音量
         * @param $_volume int 你需要设置的音频音量
         * @return $this  Class 此类
         */
        public function changeAudioVolume( $_volume ){
            ( (int)$_volume < 10 )?
                $this->setErrMessage( 'Volume can not smaller than 10!!'):
                $this->OutFileOptions .= '-vol ' . $_volume . ' ';
            return $this;
        }
    
        /**
         * 合并多音轨
         * @return $this Class 此类
         */
        public function audioComplex(  ){
            if( sizeof( $this->InputFilePath ) < 2 ){
                $this->setErrMessage( 'In this Complex function, The number of input files can not smaller than 2!!');
            }elseif( $this->OutFileTybe == 'amr' ){
                $this->setErrMessage( 'The outfile can not be amr type!!');
            }else{
                $this->OutFileOptions .= '-filter_complex join=inputs=2: ';
            }
            return $this;
        }
    
        /**
         * 多音轨合并(比如将BGM与人声结合) 
         * @return $this
         */
        public function audioAmix(){
            count($this->InputFilePath) < 2 ?
                $this->setErrMessage('File number is less than 2'):
                $this->OutFileOptions .= '-filter_complex amix=inputs=2:duration=first:dropout_transition=2 ';
            return $this;
        }
    
        /**
         * 拼接两个音频文件
         * @return $this Class 此类
         */
        public function audioJoin(  ){
            ( sizeof( $this->InputFilePath ) < 2 )?
                $this->setErrMessage( 'The number of input files can not smaller than 2!!' ):
                $this->OutFileOptions .= '-filter_complex acrossfade=d=10:c1=exp:c2=exp ';
            return $this;
        }
    
    
        /**
         * 改变音频的速率
         * @param $_speed int 你需要设置的速率 分数格式 7/10
         * @return $this Class 此类
         */
        public function changeAudioSpeed( $_speed ){
            $_speed = trim( $_speed );
            ( $_speed <= 0 && empty($_speed))?
                $this->ErrMessage[] = 'The slowdown speed can not smaller than 0 or =0!!':
                $this->OutFileOptions .= '-filter:a atempo=' . $_speed . ' ';
            return $this;
        }
    
        /**
         * 改变原音频的声调,改变声音
         * @param $_rateHz rateHz
         */
        public function audioChangeVoice( $_rateHz ){
            $_rateHz = trim( $_rateHz );
            ( $_rateHz < 100 )?
                $this->ErrMessage[] = 'The rate size cannot be lower than 100Hz!!':
                $this->OutFileOptions .= '-filter_complex asetrate=r=' . $_rateHz . ' ';
            return $this;
        }
    
    
    ////////////////////////////处理视频////////////////////////////
        /**
         * 裁剪视频
         * @param $_Property Array 包括以下元素:'operation':操作,'width':要裁剪的宽,'height':要裁剪的高,'offestX':水平偏移,'offestY':垂直偏移
         * @return $this
         */
        public function videoCrop( $_Property ){
            if(empty($_Property) && !is_array($_Property)){
                $this->setErrMessage('The parameter is incorrect');
            }else {
                switch ($_Property['operation']) {
                    case 'normal'://普通操作,即要输入裁剪的宽高和开始裁剪的xy值
                        $this->OutFileOptions .= '-filter_complex crop=w=' . $_Property['width'] . ':h=' . $_Property['height'] . ':x=' . $_Property['offestX'] . ':y=' . $_Property['offestY'] . ' ';
                        break;
                    case 'centerWH'://从中心开始裁剪多宽和多高,需要输入裁剪的宽高值
                        $this->OutFileOptions .= '-filter_complex crop=' . $_Property['width'] . ':' . $_Property['height'] . ' ';
                        break;
                    case 'center'://从中心开始裁剪,裁剪的宽高值由程序控制
                        $this->OutFileOptions .= '-filter_complex crop=out_w=in_h crop=in_h ';
                        break;
                    case 'boder'://据上下多少,左右多少进行裁剪,需输入裁剪的宽高值,此时宽高值为:距离边界多少像素值
                        $this->OutFileOptions .= '-filter_complex crop="in_w-2 ' . $_Property['width'] . ':in_h-2 ' . $_Property['height'] . '" ';
                        break;
                    case 'shake':
                        $this->OutFileOptions .= "-filter_complex crop='in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(n/10):(in_h-out_h)/2+((in_h-out_h)/2)*sin(n/7)' ";
                        break;
                }
            }
            return $this;
        }
    
        /**
         * 在视频上画网格
         * @param $_boxWidthCount  int  水平多少个格, 默认3
         * @param $_boxHeightCount int  垂直多少个格,默认3
         * @param $_thickness int 网格线的宽度,默认2
         * @param $_color String 网格颜色名称,默认yellow,详解:https://xdsnet.gitbooks.io/other-doc-cn-ffmpeg/content/ffmpeg-doc-cn-37.html
         * @param $_transparent 网格透明度,0~1 ,支持一位小数,默认1
         * @return $this Class 此类
         */
        public function videoDrawGrid( $_boxWidthCount = "" , $_boxHeightCount ="" , $_thickness ="" , $_color ="" , $_transparent =""){
            if( empty( $_color ) ){
                $_color = 'yellow';
            }
            if( empty( $_transparent ) ){
                $_transparent = 1;
            }
            if( empty( $_thickness ) ){
                $_thickness = 2;
            }
            if( empty( $_boxWidthCount ) ){
                $_boxWidthCount = 3;
            }
            if( empty( $_boxHeightCount ) ){
                $_boxHeightCount = 3;
            }
            $this->OutFileOptions .= '-filter_complex drawgrid=width='.$_boxWidthCount . ':height=' . $_boxHeightCount . ':thickness=' . $_thickness . ':color=' . $_color . '@' . $_transparent . ' ';
            return $this;
        }
    
    
        /**
         * 水平翻转视频
         * @return $this
         */
        public function videoHFlip(){
            $this->OutFileOptions .= '-vf "hflip" ';
            return $this;
        }
    
        /**
         * 垂直翻转视频
         * @return $this
         */
        public function videoVFlip(){
            $this->OutFileOptions .= '-vf "vflip" ';
            return $this;
        }
    
    
        /**
         * 旋转视频
         * @param $_dir  int 角度(单位:90度)
         * @return $this Class 此类
         */
        public function videoTranspose( $_dir ){
            if(empty($_dir)){
                $_dir = 90;
            }
            $this->OutFileOptions .= '-filter_complex transpose=dir=' . $_dir . ' ';
            return $this;
        }
    
        /**
         * 拼接多个视频
         * 需要php的ffmpeg扩展
         * @return $this Class 此类
         */
        public function videoConcat(){
            if(empty(get_extension_funcs('ffmpeg'))){
                $this->setErrMessage('ffmpeg Extension does not exist');
            }else{
                if( empty( $this->InputFilePath ) ){
                    $this->ErrMessage[] = 'Line 583 , The inputFiles count empty!!';
                }
                if( sizeof( $this->InputFilePath ) < 2 ){
                    $this->ErrMessage[] = 'Line 586 , The inputFiles count must be bigger than 1!!';
                }
    
                $biggerWidth = 0;
                $biggerHeight = 0;
                for( $i = 0 ; $i < sizeof( $this->InputFilePath ) ; $i++  ){
                    $ffmpeg = new ffmpeg_movie( $this->InputFilePath[$i] );
                    if( $ffmpeg->getFrameWidth() > $biggerWidth ){
                        $biggerWidth = $ffmpeg->getFrameWidth();
                    }
                    if( $ffmpeg->getFrameHeight() > $biggerHeight ){
                        $biggerWidth = $ffmpeg->getFrameHeight();
                    }
                }
    
                for( $i = 0 ; $i < sizeof( $this->InputFilePath ) ; $i++  ){
                    $ffmpeg = new ffmpeg_movie( $this->InputFilePath[$i] );
                    if( $ffmpeg->getFrameHeight() == $biggerHeight && $ffmpeg->getFrameWidth() == $biggerWidth ){
                        continue;
                    }else{
                        $heightDifference = $ffmpeg->getFrameHeight() - $biggerHeight;
                        $widthDifference = $ffmpeg->getFrameWidth() - $biggerWidth;
                        if( $heightDifference !== 0 ){
                            $heightDifference = $heightDifference/2;
                        }
                        if( $widthDifference !== 0 ){
                            $widthDifference = $widthDifference/2;
                        }
    
                        $savePath = substr( $this->InputFilePath[$i] , 0 , strrpos( $this->InputFilePath[$i] , '.' , 0 )  ) . '1' . substr( $this->InputFilePath[$i] , strrpos( $this->InputFilePath[$i] , '.' , 0 ) + 1  );
                        $ffmpegStr = 'ffmpeg -y -i ' . $this->InputFilePath[$i] . ' -vf pad=' . $biggerWidth . ':' . $biggerHeight . ':' . $widthDifference . ':' . $heightDifference . ':black ' . $savePath;
                        $this->execute( $ffmpegStr );
                        $this->InputFilePath[$i] = $savePath;
                    }
                }
                $this->OutFileOptions .= "-filter_complex concat=n=" . sizeof( $this->InputFilePath ) . ' ';
            }
            return $this;
        }
    
        /**
         * 添加水印,水印图片为png图片,透明度用绘图软件调整
         * @param $_operation  string 操作类型,有normal(正常:需输入x,y偏移值),lefttop(左上角),righttop(右上角),leftbottom(左下角),rightbottom(右下角),center(中心)
         * @param $_offestX  (x偏移值)
         * @param $_offestY  (y偏移值)
         * @return $this  Class 此类
         */
        public function videoOverlay( $_operation , $_offestX , $_offestY ){
    
            switch( $_operation ){
                case 'normal':
                    $offestX = $_offestX;
                    $offestY = $_offestY;
                    break;
                case 'lefttop':
                    $offestX = 0;
                    $offestY = 0;
                    break;
                case 'righttop':
                    $offestX = 'main_w-overlay_w';
                    $offestY = 0;
                    break;
                case 'leftbottom':
                    $offestX = 'main_w-overlay_w';
                    $offestY = 'main_h-overlay_h';
                    break;
                case 'rightbottom':
                    $offestX = 0;
                    $offestY = 'main_h-overlay_h';
                    break;
                case 'center':
                    $offestX = '(main_w-overlay_w)/2';
                    $offestY = '(main_h-overlay_h)/2';
                    break;
                default:
                    $offestX = 0;
                    $offestY = 0;
                    break;
            }
    
            $this->OutFileOptions .= "-filter_complex overlay=" . $offestX . ':' . $offestY . ' ';
            return $this;
        }
    
        public function setAphaser(  ){
            $this->OutFileOptions .= "-filter_complex blend=all_mode=normal ";
            return $this;
        }
    
        /**
         * 修改视频速率(只修改视频,音频依旧是原速率)
         * @param $_speed   速率
         * @return $this  Class 此类
         */
        public function videoSetpts($_speed){
            (empty($_speed))?
                $this->ErrMessage[] = 'videoSpeed is null':
                $this->OutFileOptions .= "-filter:v setpts=PTS*('.$_speed.')' ";
            return $this;
        }
    
        /**
         * 同时修改音频与视频速率
         */
            public function changeVideoSpeed($_speed){
            $_speed = explode('/',$_speed);
            if(empty($_speed)){
                $this->ErrMessage[] = 'speed is null';
            }elseif(($_speed[0]/$_speed[1] > 2) || ($_speed[0]/$_speed[1] < 1/2)){
                $this->ErrMessage[] = 'The rate is only 2/1(2.0) to 1/2(0.5)';
            }else{
                $videoSpeed = '('.$_speed[0].'/'.$_speed[1].')';
                $audioSpeed = '('.$_speed[1].'/'.$_speed[0].')';
                $this->OutFileOptions .= "-filter_complex [0:v]setpts=".$videoSpeed."*PTS[v];[0:a]atempo=".$audioSpeed."[a] -map [v] -map [a] ";
            }
            return $this;
        }
    
        /**
         * 视频单独分离
         * @return $this  Class 此类
         */
        public function separateVideo(){
            $this->OutFileOptions .= '-vcodec copy -an ';
            return $this;
        }
    
        /**
         * 音频单独分离
         * @return $this  Class 此类
         */
        public function separateAudio(){
            $this->OutFileOptions .= '-acodec copy -vn ';
            return $this;
        }
    
        /**
         * 修改视频尺寸   参考 640x480
         * @param $Width    视频宽度
         * @param $Height   视频高度
         * @return $this
         */
        public function changeAudioSize($Width,$Height){
            (empty($Width) || empty($Height))?
                $this->ErrMessage[] = 'width or height is null':
                $this->OutFileOptions .= '-s '.$Width.'x'.$Height.' ';
            return $this;
        }
    
        /*
         * 转换黑白
         */
        public function videoBlackWhite(){
            $this->OutFileOptions .= '-vf lutyuv="u=128:v=128" ';
            return $this;
        }
    
    
        /**
         * 生成gif
         * @return $this
         */
        public function makeGif(){
            $this->OutFileOptions .='-pix_fmt rgb24 ';
            return $this;
        }
    
        ////////////////////////////错误处理,运行ffmpeg方法////////////////////////////
        /**
         * 获取执行错误信息
         * @return array 错误信息,包括错误行数和错误内容
         */
        public function setErrMessage($message){
            $this->ErrMessage[] = $message;
        }
    
        public function getErrorMessage(){
            return($this->ErrMessage);
        }
    
        /**
         * 执行ffmpeg命令
         * @return string 执行结果信息
         */
        public function exec(  ){
            if(!empty($this->ErrMessage)){
                return false;
            }
            //amr文件输出方式跟其他文件不同,需要分开处理
            if( $this->OutFileTybe == 'amr' ){
                $acIndex = strrpos( $this->OutFileOptions , '-ac' , 0 );
                $arIndex = strrpos( $this->OutFileOptions , '-ar' , 0 );
                $this->OutFileOptions =  $acIndex === false ? $this->OutFileOptions . ' -ac 1 ' : $this->OutFileOptions;
                $this->OutFileOptions =  $arIndex === false ? $this->OutFileOptions . ' -ar 8000 ' : $this->OutFileOptions;
            }
    
            //输入文件内容
            $inputString = '';
            //将输入条件与对应文件进行匹配
            foreach ($this->InputFileOptions as $value) {
                $inputString .= $value;
            }
            //将执行语句拼接
            $this->ExecString .=  $this->GlobalOptions . $inputString . $this->OutFileOptions . $this->OutFilePath;
    
    
            //执行ffmpeg命令
            exec( $this->ExecString,$execInfo,$execCode);
            //执行后清空本次执行选项,防止干扰下次使用
            $this->ExecString = 'ffmpeg ';
            $this->GlobalOptions = '';
            $this->InputFileOptionsString = '';
            $this->InputFileOptions = array();
            $this->InputFilePath = array();
            $this->OutFileOptions = '';
            $this->OutFilePath = '';
            $this->OutFileTybe = '';
            //检查exec语句运行是否成功,如果不成功返回失败
            if(!is_array($execInfo) && $execCode!=0){
                $this->setErrMessage('exec error!!');
                return false;
            }else {
                return true;
            }
        }
    
    
        /**
         * 此方法用来解决无法用户无法通过浏览器执行exec命令(此方法只能在windos上使用)
         * @param $batPath bat文件路径
         * @return bool
         */
        public function execute($batPath){
            if(!empty($this->ErrMessage)){
                return false;
            }
            if( $this->OutFileTybe == 'amr' ){
                $acIndex = strrpos( $this->OutFileOptions , '-ac' , 0 );
                $arIndex = strrpos( $this->OutFileOptions , '-ar' , 0 );
                $this->OutFileOptions =  $acIndex === false ? $this->OutFileOptions . ' -ac 1 ' : $this->OutFileOptions;
                $this->OutFileOptions =  $arIndex === false ? $this->OutFileOptions . ' -ar 8000 ' : $this->OutFileOptions;
            }
    
            //输入文件内容
            $inputString = '';
            //将输入条件与对应文件进行匹配
            foreach ($this->InputFileOptions as $value) {
                $inputString .= $value;
            }
            //将执行语句拼接
            $this->ExecString .=  $this->GlobalOptions . $inputString . $this->OutFileOptions . $this->OutFilePath;
    
            $bat = fopen($batPath,'w+');
            if(!$bat){
                $this->setErrMessage('batFile can not open');
                return false;
            }
            fwrite($bat, $this->ExecString);
            fclose($bat);
            exec($batPath,$execInfo,$execCode);
    
            $this->ExecString = 'ffmpeg ';
            $this->GlobalOptions = '';
            $this->InputFileOptionsString = '';
            $this->InputFileOptions = array();
            $this->InputFilePath = array();
            $this->OutFileOptions = '';
            $this->OutFilePath = '';
            $this->OutFileTybe = '';
            //检查exec语句运行是否成功,如果不成功返回失败
            if(!is_array($execInfo) && $execCode!=0){
                $this->setErrMessage('exec error!!');
                return false;
            }else {
                return true;
            }
        }
    }

    有些功能有冲突是不能同时使用的,比如音频分离跟修改速率是不能同时执行的
    ffmpeg是一个功能十分强大的开源库,我这里只列举一部分功能,而且这个类还有许多可以优化的地方,这个类写出来主要是为了抛砖引玉 :D

    下面附上ffmpeg参数说明
    http://www.cnblogs.com/chen1987lei/archive/2010/12/03/1895242.html

     
    参考:PHP的ffmpeg使用 - CSDN博客
    https://blog.csdn.net/qq_20329253/article/details/51420661
     
     
     
  • 相关阅读:
    poj 2718 Smallest Difference
    AtCoder Beginner Contest 100 2018/06/16
    aoj 0009 Prime Number
    poj 1930 Dead Fraction
    poj 3669 Meteor Shower
    aoj 0121 Seven Puzzle
    poj 2429 GCD & LCM Inverse
    aoj 0005 GCD and LCM
    aoj 0558 Cheese
    aoj 0033 玉
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/9595527.html
Copyright © 2020-2023  润新知