ffmpeg 抓取视频截图,生成小图片


需要做视频分享网站,这个在php中查找相关资料后 说是要使用ffmpeg工具,这个工具既提供了命令行驱动的接口(ffmpeg.exe),(从任何支持系统调用的语言中都可以与之交互如:java,php ,.net等),还提供了专门针对php的模块即 php-ffmpeg.dll (还有配套的几个其他dll文件)需要添加到 php的ext目录,在php.ini配置文件中启用加载该模块(网上有很多这样的例子)。但由于我使用的是 php5.3没有合适的php-ffmpeg所以只能用这种方法了,不过命令行驱动的好处在于 其跨平台(学会命令行)在任何其他语言(如java中)也是很好改造的。所以这个类就这样诞生了,我只用其中的生成截图函数,至于视频转换,只是用来研究的,太费时了! 生成小图片也是可以的,但是最好别用(自己算缩放比,还要打开一个进程),我在前面提供了一个生成小图片的类,可以用那个

ffmpeg工具集(包括其他命令行程序)可在网上下载(google一下第一个一般就是官网),分别有widows版本,和其他nix平台的版本,如果不嫌费事,或者对编译成dll文件很在行,那么可以编译源码。或者下载使用二进制文件

<?php
/**
* @author yiqing95
*?@copyright?Copyright?(c)?2010,yiqing95.gicp.net
* FFmpeg工具类 封装常用的ffmpeg命令 为使用者提供一个
* 易用的接口,应同时提供静态类使用方法和类实例使用方法
* 由于时间较紧,未编写静态方法,其实下面实例方法稍改造
* 就能提供实例方法。具体命令行用法可参考ffmpeg官方文档
* 可自行改造,添加方法。
*该类是在 ffmpeg_php.dll无法使用的条件下,逼不得已
* 才这么做的,如果你机器上可以用ffmpeg_php.dll建议用
* 那个,里面的类提供了很好用的方法。
* 其中的视频转换,太慢了,我都不做转换直接用源格式,只用其中
* 的截图函数而已,jquery 提供的 media插件可播放任何格式,所以
* 没必要费时的在那转换,除非强迫使用flv格式
* (另外记着格式转换时最费cpu的事情,
* 我测试过其中的转换方法cpu利用率80%以上-----你就别干其他事了)
*
* 使用ffmpeg.exe方式生成视频截图代码(在window2003和windowXP下都好使,我当时就是这样处理的)
* 注意:在2003下由于存在权限问题,不能直接在php中使用exec调用ffmpeg命令,必须使用COM
* $phpwsh=new COM("Wscript.Shell") or die("Create Wscript.Shell Failed!");
* $exec=$phpwsh->exec("cmd.exe /c ffmpeg.exe -i D:/FFmpeg/test.flv -f image2 -ss 5 -s 120*90 -vframes 1 D:/FFmpeg/test.jpg");
* 本项目中 ffmpeg存放路径:
*     用法如:
*     $ffUtil = new FFmpegUtil(".././ffmpeg/bin");
*     $ffUtil->convert2flv("Uploads/Videos/me.3gp", "Uploads/Videos/me.gif");
*     $ffUtil->getThumbnailFormVideo("Uploads/Videos/me.3gp","Uploads/Videos/me.gif");
*
*/

class FFmpegUtil{
/**
   *工具安装的路径,bin路径 全称,不然加载到环境变量也行,
   * 这样 ffmpegHome 就给个空串不然要给出全称路径
   * echo realpath("../.")."\ffmpeg\bin\ffmpeg"; 用realpath函数可求出
   * 当前文件的全称路径,这样来根据ffmpeg存放的位置来构造绝对路径
   * @var string
   */
private $ffmpegHome;
/**
   * ffmpeg.exe存放目录路径
   * 可用命令行的全路径比如:d://ffmpeg/bin/ffmpeg
   * @var string
   */
private $cmdHome;
public function __construct($ffmpegHome){
   //如果给的路径中还有:认为是绝对路径
    if(strpos($ffmpegHome, ":") === false){
      //不含盘符的路径认为是相对路径 ,转为绝对路径
      $this->ffmpegHome = realpath($ffmpegHome);
    }else{
      //否则给的是绝对路径,不用转化
      $this->ffmpegHome = $ffmpegHome;
}
$this->cmdHome = $this->ffmpegHome .DIRECTORY_SEPARATOR ."ffmpeg";
}
/**
* 返回FFmpeg.exe的绝对路径
* 帮助调试用
* @return string
*/
public function getFFmpegHome(){
return $this->ffmpegHome;
}

public function getFFmpegCmdPath(){
   return $this->cmdHome;
}

/**
* 转换成flv文件 方法经过测试,理论上的异步不起作用
* @param string $inFile 输入文件 ,可以是任何ffmpeg支持的视频格式
* @param string $outFile 输出文件 ,理论上也可以是ffmpeg支持的格式
*                但这个方法既然都这样叫了,你就最好给个xxx.flv吧!^-^
* @param $async bool 是否同步,默认是同步的,这样保证执行完文件后使用$outFile不会出错
*                不然使用异步方式 该方法不阻塞立即返回但是如果想显示可能有点问题
*/
public function convert2flv( $inFile, $outFile , $async = false )
{
@unlink( $outFile );
if(!is_file( $inFile )){
     throw new Exception("不是一个文件");
     return;
}
   //realpath(dirname($testFile)).DIRECTORY_SEPARATOR.basename($testFile);
$srcFile = $inFile; //原始文件路径
$destFile = $outFile; //目标文件路径

//相对路径的处理
if(strpos($srcFile, ":") === false){
        $srcFile = realpath(dirname($inFile)).DIRECTORY_SEPARATOR.basename($inFile);
}
   //相对路径的处理
if(strpos($destFile, ":") === false){
        $destFile = realpath(dirname($outFile)).DIRECTORY_SEPARATOR.basename($outFile);
}

//-ar 参数是控制音频取样率的 默认是44100 Hz这个是最高音质(cd音质)
$cmd = $this->cmdHome." -v 0 -i $srcFile -ar 11025 $destFile 2>&1";

//只所以用管道 而不用exec 下面有例子,是因为一个是同步,一个是异步!!!
if($async === false){
    $fh = popen( $cmd, "r" );
    while( fgets( $fh ) ) { /*读取管道输出阻塞*/}
    pclose( $fh );
}else{
   //异步执行,方法不阻塞 理论上是实际不是

    pclose(popen( $cmd, "r" ));
    //exec($cmd);
}
}

/**
* 从视频流获取截图
* @param string $videoFile 视频文件路径,相对或绝对,但绝对路径没测试过
* @param string $thumbImg 目标截图文件的路径(全称),
* @param number $startSecond 从第几秒截取
* @param number $width 高度
* @param number $height 宽度
* @return bool 没啥用弄着玩,异常就够了 ,还没有学习进程交互的太多知识
*               这里可能出错的就是转换出错,从另一个进程(ffmpeg)管道流中
*               分析错误并反馈给用户,
*/
public function getThumbnailFormVideo( $videoFile, $thumbImg , $startSecond=6 ,$width=400 ,$height=300 )
{
@unlink( $thumbImg );
if(!is_file( $videoFile )){
     throw new Exception("不是一个文件");
     return false;
}

$srcFile = $videoFile; //原始文件路径
$destFile = $thumbImg; //目标文件路径

//相对路径的处理
if(strpos($srcFile, ":") === false){
        $srcFile = realpath(dirname($videoFile)).DIRECTORY_SEPARATOR.basename($videoFile);
}
   //相对路径的处理
if(strpos($destFile, ":") === false){
        $destFile = realpath(dirname($thumbImg)).DIRECTORY_SEPARATOR.basename($thumbImg);
}

$cmd = $this->cmdHome." -i $srcFile -pix_fmt rgb24 -vframes 1 -ss $startSecond -s {$width}x{$height} $destFile 2>&1";
$fh = popen( $cmd, "r" );
while( fgets( $fh ) ) { }
pclose( $fh );
}

/**
* 从图片得到小图标,这里没有计算等比缩放因子,
* 请自己计算,这只不过是告诉你 ffmpeg可以生成小图片
* 本类意在转 flv格式,以及从视流抓取某个桢画面,无损
* 这个函数只是测试而已,但确实可用,
* 就是高度和宽度要自己给合适了不然图像会变形!!!
* @param <type> $srcImg
* @param <type> $destImg
* @param <type> $width
* @param <type> $height
* @return <type>
*/
public function getThumbnailFromImg( $srcImg, $destImg,$width=200,$height=150 ){
@unlink( $destImg ); //如果存在先删掉
//判断给定的文件是否正常
if(!is_file($srcImg)){
     throw new Exception("不是一个文件");
     return;
}
$srcFile = $srcImg; //原始文件路径
$destFile = $destImg; //目标文件路径
//相对路径的处理
if(strpos($srcFile, ":") === false){
        $srcFile = realpath(dirname($srcFile)).DIRECTORY_SEPARATOR.basename($srcFile);
}
   //相对路径的处理
if(strpos($destFile, ":") === false){
        $destFile = realpath(dirname($destFile)).DIRECTORY_SEPARATOR.basename($destFile);
}

$cmd = $this->cmdHome." -i $srcFile -pix_fmt rgb24 -s {$width}*{$height} $destFile";
$fh = popen( $cmd, "r" );
//耗尽管道的输出流
while( fgets( $fh ) ) { }
pclose( $fh );
}

/**
* 使用方法
* @param string $upFile 刚上传的视频文件
* @param string $fname 要保存的目标文件(FLV)格式的随便给个合法的名字,可以不带flv后缀
* @param String $destDir 要保存的目标文件夹
*/
public function flv_import( $upFile, $fname ,$destDir)
{
$fname = preg_replace( '/\..*$/', '', basename( $fname ) );
$flvpath = "$fname.flv";
$thumbpath = "$fname.gif";


$fname = preg_replace( '/\..*$/', '', basename( $fname ) );
$flvpath = "$fname.flv";
$thumbpath = "$fname.gif";

$this->convert2flv( $upfile, "$destDir".DIRECTORY_SEPARATOR."$flvpath" );
$this->getThumbnailFormVideo( $upfile, "$destDir".DIRECTORY_SEPARATOR."$thumbpath" );

//分别存储 视频和音频文件到某个位置
   /**
    * 'INSERT INTO movies VALUES ( $title, $flvpath, $thumbpath, 300, 200 ))' ;
    */
}
//下面是另一种参考实现 以供参考

//转换为Flv
private function makeFlv($video_file,$flv_file)
{
//判断给定的文件是否正常
if(!is_file($video_file)){
return false;
}
//这个是执行消息 需要反馈的话弄个实例变量即可,一般没用
$flv_msg;
    $flv_cmd="ffmpeg -i ".$video_file." ".$flv_file;
    exec($flv_cmd,$flv_msg);
}
//创建flv视频的图片
/**
* 参数意义自明
* @param <type> $flv_file
* @param <type> $flv_pic_file
* @param <type> $width
* @param <type> $height
* @return <type>
*/
private function makeFlvPic($flv_file,$flv_pic_file,$width=350,$height=240)
{
//判断给定的文件是否正常
if(!is_file($video_file)){
return false;
}
$flv_msg;
    $flv_pic_cmd="ffmpeg -i ".$flv_file.
       " -y -f image2 ".
       " -ss 1 ".
       " -t 0.001 ".
       " -s {$width}x{$height} ".$flv_pic_file;
    exec($flv_pic_cmd,$flv_msg);
}

}
/*
*附上ffmpeg.exe参数说明:
ffmpeg -i "e:\test.flv" -f image2 -ss 5 -s 120*90 -vframes 1 "e:\test.jpg"
ffmpeg // 命令
-i "f:\test.flv" // 输入文件
-f image2 -ss 6 -s 120*90 -vframes 1
// 可选参数: -f表示输出文件格式、
// -ss表示相对于文件开始处的时间偏移值, 即从6秒出开始截图
// -s表示截图的的大小
// -vframes表示截图的桢数
"f:\test.jpg" // 输出文件
上面的意思就是,从test.flv中的第5秒开始截1帧大小为120*90保存成名为test.jpg的图片
*
*
*/
?>

多媒体插件下载:http://www.open-lib.com/html/Type/172-1.html

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: