fetch_by_identifier('ffmpeg', 'dzz'); $app = unserialize($appdata['extra']); $this->status = $app['status']; $option = array( 'ffmpeg.binaries' => $app['ffmpeg.binaries'] ? $app['ffmpeg.binaries'] : (strstr(PHP_OS, 'WIN') ? DZZ_ROOT . 'dzz\ffmpeg\ffmpeg\ffmpeg.exe' : '/usr/bin/ffmpeg'), 'ffprobe.binaries' => $app['ffprobe.binaries'] ? $app['ffprobe.binaries'] : (strstr(PHP_OS, 'WIN') ? DZZ_ROOT . 'dzz\ffmpeg\ffmpeg\ffprobe.exe' : '/usr/bin/ffprobe'), 'timeout' => $app['timeout'] ? $app['timeout'] : 3600, // The timeout for the underlying process 'ffmpeg.threads' => $app['ffmpeg.threads'] ? $app['ffmpeg.threads'] : 1, // The number of threads that FFMpeg should use ); $this->fm = FFMpeg\FFMpeg::create($option, $this->logger); return $this->fm; } public function getInfo($data) { global $_G; if($data['aid']){ $attachment = IO::getMeta('attach::'.$data['aid']); }else{ $attachment = IO::getMeta($data['rid']); } $file = IO::getStream($attachment['path']);; //本地路径 if ($attachment['bz'] != 'dzz::') { $cachefile = $_G['setting']['attachdir'] . './cache/' . md5($data['path']) . '.' . $data['ext']; $handle = fopen($cachefile, 'w+'); $fp = fopen($file, 'rb'); while (!feof($fp)) { fwrite($handle, fread($fp, 8192)); } fclose($handle); fclose($fp); $file = $cachefile; } $app = C::t('app_market')->fetch_by_identifier('ffmpeg', 'dzz'); $option = array( 'ffmpeg.binaries' => $app['ffmpeg.binaries'] ? $app['ffmpeg.binaries'] : (strstr(PHP_OS, 'WIN') ? DZZ_ROOT . 'dzz\ffmpeg\ffmpeg\ffmpeg.exe' : '/usr/bin/ffmpeg'), 'ffprobe.binaries' => $app['ffprobe.binaries'] ? $app['ffprobe.binaries'] : (strstr(PHP_OS, 'WIN') ? DZZ_ROOT . 'dzz\ffmpeg\ffmpeg\ffprobe.exe' : '/usr/bin/ffprobe'), 'timeout' => $app['timeout'] ? $app['timeout'] : 3600, // The timeout for the underlying process 'ffmpeg.threads' => $app['ffmpeg.threads'] ? $app['ffmpeg.threads'] : 1, // The number of threads that FFMpeg should use ); $ffprobe = FFMpeg\FFProbe::create($option, null); if ('audio' == getTypeByExt($attachment['ext'])) { $meta = $ffprobe ->streams($file) // extracts streams informations ->audios() // filters video streams ->first(); $info = array(); if ($meta) { $info = array( 'duration' => round($meta->get('duration'), 2), ); } } else { $meta = $ffprobe ->streams($file) // extracts streams informations ->videos() // filters video streams ->first(); $info = array(); if ($meta) { $info = array( 'width' => intval($meta->get('width')), 'height' => intval($meta->get('height')), 'duration' => round($meta->get('duration'), 2), ); } } if ($cachefile) @unlink($cachefile); return $info; } /* 获取缩略图 $file:文件地址 $time:获取缩略图的时间点单位秒 */ public function getThumb($data, $time = 0) { global $_G; if($data['aid']){ $attachment = IO::getMeta('attach::'.$data['aid']); }else{ $attachment = IO::getMeta($data['rid']); } $file = IO::getStream($attachment['path']); //本地路径 if ($attachment['bz'] != 'dzz::') { $cachefile = $_G['setting']['attachdir'] . './cache/' . md5($attachment['path']) . '.' . $attachment['ext']; $handle = fopen($cachefile, 'w+'); $fp = fopen($file, 'rb'); while (!feof($fp)) { fwrite($handle, fread($fp, 8192)); } fclose($handle); fclose($fp); $file = $cachefile; } $thumbpath = $this->getthumbpath('pichomethumb'); if($data['aid'])$thumbname = md5($data['aid'].$data['thumbsign']).'_original.webp'; else $thumbname = md5($data['path'].$data['thumbsign']).'_original.webp'; $target = $thumbpath.$thumbname; if ('audio' == getTypeByExt($attachment['ext'])) { //$target = ($data['thumbsign']) ? $data['rid']. '.webp' : $data['rid'] . '.webp'; $jpg = $_G['setting']['attachdir'] . $target; $jpgpath = dirname($jpg); dmkdir($jpgpath); if (!in_array($data['ext'], array('mp3', 'wav'))) { $audio = $this->fm->open($file); $audio_format = new FFMpeg\Format\Audio\Mp3(); $tmp = $_G['setting']['attachdir'] . './cache/' . md5($file) . '.mp3'; $audio->save($audio_format, $tmp); } $audio = $this->fm->open($tmp ? $tmp : $file); $waveform = $audio->waveform(720, 360, array('#888888')); $waveform->save($jpg); if ($tmp) @unlink($tmp); } else { // $target = $data['rid'] . '.jpg'; $jpg = $_G['setting']['attachdir']. $target; $jpgpath = dirname($jpg); dmkdir($jpgpath); $app = C::t('app_market')->fetch_by_identifier('ffmpeg', 'dzz'); if(!$time){ $option = array( 'ffmpeg.binaries' => $app['ffmpeg.binaries'] ? $app['ffmpeg.binaries'] : (strstr(PHP_OS, 'WIN') ? DZZ_ROOT . 'dzz\ffmpeg\ffmpeg\ffmpeg.exe' : '/usr/bin/ffmpeg'), 'ffprobe.binaries' => $app['ffprobe.binaries'] ? $app['ffprobe.binaries'] : (strstr(PHP_OS, 'WIN') ? DZZ_ROOT . 'dzz\ffmpeg\ffmpeg\ffprobe.exe' : '/usr/bin/ffprobe'), 'timeout' => $app['timeout'] ? $app['timeout'] : 3600, // The timeout for the underlying process 'ffmpeg.threads' => $app['ffmpeg.threads'] ? $app['ffmpeg.threads'] : 1, // The number of threads that FFMpeg should use ); $ffprobe = FFMpeg\FFProbe::create($option, null); $meta = $ffprobe ->streams($file) // extracts streams informations ->audios() // filters video streams ->first(); $duration = 0; if ($meta) { $duration = round($meta->get('duration'), 2); } $time = getglobal('config/audiothumetime') ? intval(getglobal('config/audiothumetime')):5; $time = ($duration > $time) ? $time:ceil($data['duration']); } try { $video = $this->fm->open($file); $video ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds($time)) ->save($jpg); } catch (\Exception $e) { runlog('ffmpeg', $e->getMessage() . ' File:' . $file); } } if ($cachefile) @unlink($cachefile); if (is_file($jpg)) { $defaultspace = $_G['setting']['defaultspacesetting']; //如果原文件位置不在本地,则将转换完成文件迁移到对应位置 if ($defaultspace['bz'] != 'dzz') { $cloudpath = $defaultspace['bz'].':'.$defaultspace['did'] . ':/' .$target; $filepath = \IO::moveThumbFile($cloudpath, $jpg); if (!isset($filepath['error'])) { @unlink($jpg); return $target; } } else { return $target; } } return false; } public function getVideoQuality($videoquality = 1) { $templatename = ''; switch ($videoquality) { case 0://流畅 $templatename = 'pichomeconvert-mp4-640-360-400-mp3'; $width = 640; $height = 360; $bitrate = 400; break; case 1://标清 $templatename = 'pichomeconvert-mp4-960-540-900-mp3'; $width = 960; $height = 540; $bitrate = 900; break; case 2://高清 $templatename = 'pichomeconvert-mp4-1280-720-1500-mp3'; $width = 1280; $height = 720; $bitrate = 1500; break; case 3://超清 $templatename = 'pichomeconvert-mp4-1920-1080-3000-mp3'; $width = 1920; $height = 1080; $bitrate = 3000; break; case 4://2k $templatename = 'pichomeconvert-mp4-3500-2560-1440-mp3'; $width = 3500; $height = 2560; $bitrate = 1440; break; case 5://4k $templatename = 'pichomeconvert-mp4-3840-2160-6000-mp3'; $width = 3840; $height = 2160; $bitrate = 6000; break; } return array($templatename, $width, $height, $bitrate); } //转码,windows下大文件可能出现内部错误,X264报错,不知原因 public function convert($id, $ext = 'mp4', $videoquality = 1, $extra = array()) { global $_G; //获取附件信息 //获取记录表数据 $cron = C::t('video_record')->fetch($id); if($cron['aid']){ $attachment = IO::getMeta('attach::'.$cron['aid']); }else{ $attachment = IO::getMeta($cron['rid']); } list($templatename, $fwidth, $fheight, $fbitrate) = $this->getVideoQuality($videoquality); //本地文件路径 $target = 'pichomethumb/' . date('Ym') . '/' . date('d') .'/'.md5($attachment['path']) . '.' . $cron['format']; //本地存储时路径 $recordpath = 'dzz::' . $target; //文件保存路径 $mp4 = $_G['setting']['attachdir'].$target; $mp4path = dirname($mp4); dmkdir($mp4path); //开始转换过程 $file = IO::getStream($attachment['path']); if ($attachment['bz'] != 'dzz::') { $cachefile = $_G['setting']['attachdir'] . './cache/' . md5($attachment['path']) . '.' . $attachment['ext']; $handle = fopen($cachefile, 'w+'); $fp = fopen($file, 'rb'); while (!feof($fp)) { fwrite($handle, fread($fp, 8192)); } fclose($handle); fclose($fp); $file = $cachefile; } //更新转换执行次数 C::t('video_record')->update($cron['id'], array('status' => 1,'path'=>$target, 'dateline' => TIMESTAMP, 'jobnum' => (($cron['jobnum']) ? intval($cron['jobnum']) + 1 : 1))); $video = $this->fm->open($file); //水印 // $video->filters() ->watermark($watermarkPath, array('position' => 'relative','bottom' => 50, 'right' => 50 )); $video->path = $cron['id']; switch ($ext) { case 'mp4': $format = new FFMpeg\Format\Video\X264('aac'); break; case 'webm': $format = new FFMpeg\Format\Video\WebM(); break; case 'ogg': $format = new FFMpeg\Format\Video\Ogg(); break; case 'wmv': $format = new FFMpeg\Format\Video\WMV(); break; case 'wav': $format = new FFMpeg\Format\Audio\Wav(); break; case 'mp3': $format = new FFMpeg\Format\Audio\Mp3(); break; default: $format = new FFMpeg\Format\Video\X264('aac'); } if (!in_array($ext, array('mp3', 'wav'))) { //获取视频信息 try { $info = $this->getInfo($attachment); if(!in_array($ext,array('mp3','wav'))){ if($info['width']){ $width=$fwidth; $height=$info['height']?($width*$info['height']/$info['width']):$fheight; //指定视频宽高 $video->filters()->resize(new FFMpeg\Coordinate\Dimension($width, $height))->synchronize(); }else{ $video->filters()->resize(new FFMpeg\Coordinate\Dimension($fwidth, $fheight))->synchronize(); } } $bitrate=intval($fbitrate>$info['bit_rate']?$fbitrate:$info['bit_rate']); $format->setKiloBitrate($bitrate); } catch (\Exception $e) { }; } $format->on('progress', function ($video, $format, $percentage) { C::t('video_record')->update($video->path, array('percent' => $percentage > 0 ? $percentage : 1)); }); try { $video->save($format, $mp4); } catch (\Exception $e) { //失败时记录失败信息 C::t('video_record')->update($cron['id'], array('endtime' => strtotime('now'), 'status' => -1, 'error' => $e->getMessage())); return array('error' => $e->getMessage()); } //如果未发生错误更改记录表数据为成功,并存储本地存储时路径 C::t('video_record')->update($cron['id'], array('percent' => 100, 'endtime' => strtotime('now'), 'status' => 2, 'path' => $recordpath)); if ($cachefile) @unlink($cachefile); //如果原文件位置不在本地,则将转换完成文件迁移到对应位置 if ($attachment['bz'] != 'dzz::') { //组合云端保存位置 $cloudpath =$attachment['bz']. ':' . '/tmppichomethumb/' . md5($attachment['path']) . '.' . $cron['format']; $filepath = IO::moveThumbFile($cloudpath, $mp4); if (!isset($filepath['error'])) { C::t('video_record')->update($cron['id'], array('path' => $cloudpath,'remoteid'=>$attachment['remoteid'])); @unlink($mp4); } } return $cron; } //兼容linux下获取文件名 public function get_basename($filename) { if ($filename) { return preg_replace('/^.+[\\\\\\/]/', '', $filename); } return ''; } public function getPath($dir = 'imgcache/ffmpeg') { global $_G; $target1 = $dir . '/index.html'; $target_attach = $_G['setting']['attachdir'] . './' . $target1; $targetpath = dirname($target_attach); dmkdir($targetpath); return $dir; } public function getthumbpath($dir = 'pichomethumb'){ $subdir = $subdir1 = $subdir2 = ''; $subdir1 = date('Ym'); $subdir2 = date('d'); $subdir = $subdir1 . '/' . $subdir2 . '/'; // $target1 = $dir . '/' . $subdir . 'index.html'; $target = $dir . '/' . $subdir; return $target; } }