Files
Pichome/dzz/ffmpeg/class/class_fmpeg.php

404 lines
16 KiB
PHP
Raw Normal View History

2021-12-09 21:00:09 +08:00
<?php
/*
* @copyright QiaoQiaoShiDai Internet Technology(Shanghai)Co.,Ltd
* @license https://www.oaooa.com/licenses/
*
* @link https://www.oaooa.com
* @author zyx(zyx@oaooa.com)
*/
require_once DZZ_ROOT . './dzz/ffmpeg/vendor/autoload.php';
require_once(DZZ_ROOT . './dzz/class/class_encode.php');
class fmpeg
{
private $fm;
2024-01-31 01:00:33 +08:00
private $status = 0;
2021-12-09 21:00:09 +08:00
private $logger = NULL;
public function __construct($options = array())
{
2024-01-31 01:00:33 +08:00
$appdata = C::t('app_market')->fetch_by_identifier('ffmpeg', 'dzz');
$app = unserialize($appdata['extra']);
$this->status = $app['status'];
2021-12-09 21:00:09 +08:00
$option = array(
2024-01-31 01:00:33 +08:00
'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
2021-12-09 21:00:09 +08:00
);
$this->fm = FFMpeg\FFMpeg::create($option, $this->logger);
return $this->fm;
}
public function getInfo($data)
{
2024-01-31 01:00:33 +08:00
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));
2021-12-09 21:00:09 +08:00
}
2024-01-31 01:00:33 +08:00
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);
2021-12-09 21:00:09 +08:00
2024-01-31 01:00:33 +08:00
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),
);
2021-12-09 21:00:09 +08:00
}
2024-01-31 01:00:33 +08:00
} 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),
2024-02-06 23:16:10 +08:00
'tags' => $meta->get('tags'),
2024-01-31 01:00:33 +08:00
);
}
}
if ($cachefile) @unlink($cachefile);
2024-02-06 23:16:10 +08:00
if(isset($info['tags']['rotate'])){
$rotate = intval($info['tags']['rotate'])%360;
if($rotate == 90){
$width = $info['width'];
$height = $info['height'];
$info['width'] = $height;
$info['height'] = $width;
}
}
unset($info['tags']);
2021-12-09 21:00:09 +08:00
return $info;
}
/* 获取缩略图
$file:文件地址
$time:获取缩略图的时间点单位秒
*/
2024-01-31 01:00:33 +08:00
public function getThumb($data, $time = 0)
2021-12-09 21:00:09 +08:00
{
global $_G;
2024-01-31 01:00:33 +08:00
if($data['aid']){
$attachment = IO::getMeta('attach::'.$data['aid']);
}else{
$attachment = IO::getMeta($data['rid']);
}
2021-12-09 21:00:09 +08:00
2024-01-31 01:00:33 +08:00
$file = IO::getStream($attachment['path']);
2021-12-09 21:00:09 +08:00
//本地路径
2024-01-31 01:00:33 +08:00
if ($attachment['bz'] != 'dzz::') {
$cachefile = $_G['setting']['attachdir'] . './cache/' . md5($attachment['path']) . '.' . $attachment['ext'];
2021-12-09 21:00:09 +08:00
$handle = fopen($cachefile, 'w+');
$fp = fopen($file, 'rb');
while (!feof($fp)) {
fwrite($handle, fread($fp, 8192));
}
fclose($handle);
fclose($fp);
2024-01-31 01:00:33 +08:00
$file = $cachefile;
2021-12-09 21:00:09 +08:00
}
2024-01-31 01:00:33 +08:00
$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';
2021-12-09 21:00:09 +08:00
2024-01-31 01:00:33 +08:00
$jpg = $_G['setting']['attachdir'] . $target;
2021-12-09 21:00:09 +08:00
$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 {
2024-01-31 01:00:33 +08:00
// $target = $data['rid'] . '.jpg';
$jpg = $_G['setting']['attachdir']. $target;
2021-12-09 21:00:09 +08:00
$jpgpath = dirname($jpg);
dmkdir($jpgpath);
2024-01-31 01:00:33 +08:00
$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
2024-03-12 17:49:15 +08:00
->videos() // filters video streams
2024-01-31 01:00:33 +08:00
->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']);
}
2021-12-09 21:00:09 +08:00
try {
2024-01-31 01:00:33 +08:00
2021-12-09 21:00:09 +08:00
$video = $this->fm->open($file);
$video
->frame(FFMpeg\Coordinate\TimeCode::fromSeconds($time))
->save($jpg);
} catch (\Exception $e) {
2024-01-31 01:00:33 +08:00
2021-12-09 21:00:09 +08:00
runlog('ffmpeg', $e->getMessage() . ' File:' . $file);
}
}
2024-01-31 01:00:33 +08:00
if ($cachefile) @unlink($cachefile);
2021-12-09 21:00:09 +08:00
if (is_file($jpg)) {
2024-01-31 01:00:33 +08:00
$defaultspace = $_G['setting']['defaultspacesetting'];
//如果原文件位置不在本地,则将转换完成文件迁移到对应位置
if ($defaultspace['bz'] != 'dzz') {
$cloudpath = $defaultspace['bz'].':'.$defaultspace['did'] . ':/' .$target;
2024-02-06 00:03:33 +08:00
$filepath = \IO::moveThumbFile($cloudpath, $jpg);
2024-01-31 01:00:33 +08:00
if (!isset($filepath['error'])) {
@unlink($jpg);
return $target;
}
} else {
return $target;
}
}
return false;
2021-12-09 21:00:09 +08:00
}
2024-01-31 01:00:33 +08:00
2024-02-06 00:03:33 +08:00
public function getVideoQuality($videoquality = 1)
2024-01-31 01:00:33 +08:00
{
2022-06-25 14:48:20 +08:00
$templatename = '';
2024-01-31 01:00:33 +08:00
switch ($videoquality) {
2022-06-25 14:48:20 +08:00
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;
2024-02-06 00:03:33 +08:00
$height = 540;
2022-06-25 14:48:20 +08:00
$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;
}
2024-01-31 01:00:33 +08:00
return array($templatename, $width, $height, $bitrate);
2022-06-25 14:48:20 +08:00
}
2024-01-31 01:00:33 +08:00
2022-06-25 14:48:20 +08:00
//转码,windows下大文件可能出现内部错误X264报错不知原因
2024-02-06 00:03:33 +08:00
public function convert($id, $ext = 'mp4', $videoquality = 1, $extra = array())
2022-06-25 14:48:20 +08:00
{
global $_G;
//获取附件信息
2024-01-31 01:00:33 +08:00
2022-06-25 14:48:20 +08:00
//获取记录表数据
2024-01-31 01:00:33 +08:00
$cron = C::t('video_record')->fetch($id);
if($cron['aid']){
$attachment = IO::getMeta('attach::'.$cron['aid']);
}else{
$attachment = IO::getMeta($cron['rid']);
}
2024-02-06 00:03:33 +08:00
list($templatename, $fwidth, $fheight, $fbitrate) = $this->getVideoQuality($videoquality);
2022-06-25 14:48:20 +08:00
//本地文件路径
2024-01-31 01:00:33 +08:00
$target = 'pichomethumb/' . date('Ym') . '/' . date('d') .'/'.md5($attachment['path']) . '.' . $cron['format'];
2022-06-25 14:48:20 +08:00
//本地存储时路径
$recordpath = 'dzz::' . $target;
//文件保存路径
2024-01-31 01:00:33 +08:00
$mp4 = $_G['setting']['attachdir'].$target;
2022-06-25 14:48:20 +08:00
$mp4path = dirname($mp4);
dmkdir($mp4path);
//开始转换过程
2024-01-31 01:00:33 +08:00
$file = IO::getStream($attachment['path']);
if ($attachment['bz'] != 'dzz::') {
$cachefile = $_G['setting']['attachdir'] . './cache/' . md5($attachment['path']) . '.' . $attachment['ext'];
$handle = fopen($cachefile, 'w+');
2022-06-25 14:48:20 +08:00
$fp = fopen($file, 'rb');
2024-01-31 01:00:33 +08:00
while (!feof($fp)) {
fwrite($handle, fread($fp, 8192));
2022-06-25 14:48:20 +08:00
}
fclose($handle);
fclose($fp);
$file = $cachefile;
}
//更新转换执行次数
2024-01-31 01:00:33 +08:00
C::t('video_record')->update($cron['id'], array('status' => 1,'path'=>$target, 'dateline' => TIMESTAMP, 'jobnum' => (($cron['jobnum']) ? intval($cron['jobnum']) + 1 : 1)));
2022-06-25 14:48:20 +08:00
$video = $this->fm->open($file);
2024-02-06 00:03:33 +08:00
2022-06-25 14:48:20 +08:00
//水印
// $video->filters() ->watermark($watermarkPath, array('position' => 'relative','bottom' => 50, 'right' => 50 ));
$video->path = $cron['id'];
2021-12-09 21:00:09 +08:00
2022-06-25 14:48:20 +08:00
switch ($ext) {
case 'mp4':
2024-02-06 00:03:33 +08:00
$format = new FFMpeg\Format\Video\X264('aac');
2022-06-25 14:48:20 +08:00
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:
2024-02-06 00:03:33 +08:00
$format = new FFMpeg\Format\Video\X264('aac');
2021-12-09 21:00:09 +08:00
2022-06-25 14:48:20 +08:00
}
2024-01-31 01:00:33 +08:00
if (!in_array($ext, array('mp3', 'wav'))) {
2022-06-25 14:48:20 +08:00
//获取视频信息
try {
$info = $this->getInfo($attachment);
2024-02-06 23:16:10 +08:00
2024-02-06 00:03:33 +08:00
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);
2022-06-25 14:48:20 +08:00
} 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) {
//失败时记录失败信息
2024-01-31 01:00:33 +08:00
C::t('video_record')->update($cron['id'], array('endtime' => strtotime('now'), 'status' => -1, 'error' => $e->getMessage()));
2022-06-25 14:48:20 +08:00
return array('error' => $e->getMessage());
}
//如果未发生错误更改记录表数据为成功,并存储本地存储时路径
C::t('video_record')->update($cron['id'], array('percent' => 100, 'endtime' => strtotime('now'), 'status' => 2, 'path' => $recordpath));
2024-01-31 01:00:33 +08:00
if ($cachefile) @unlink($cachefile);
2022-06-25 14:48:20 +08:00
//如果原文件位置不在本地,则将转换完成文件迁移到对应位置
2024-01-31 01:00:33 +08:00
if ($attachment['bz'] != 'dzz::') {
2022-06-25 14:48:20 +08:00
//组合云端保存位置
2024-01-31 01:00:33 +08:00
$cloudpath =$attachment['bz']. ':' . '/tmppichomethumb/' . md5($attachment['path']) . '.' . $cron['format'];
2022-06-25 14:48:20 +08:00
$filepath = IO::moveThumbFile($cloudpath, $mp4);
if (!isset($filepath['error'])) {
2024-01-31 01:00:33 +08:00
C::t('video_record')->update($cron['id'], array('path' => $cloudpath,'remoteid'=>$attachment['remoteid']));
2022-06-25 14:48:20 +08:00
@unlink($mp4);
}
}
return $cron;
}
2024-01-31 01:00:33 +08:00
2021-12-09 21:00:09 +08:00
//兼容linux下获取文件名
public function get_basename($filename)
{
if ($filename) {
return preg_replace('/^.+[\\\\\\/]/', '', $filename);
}
return '';
}
2022-06-25 14:48:20 +08:00
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;
}
2024-01-31 01:00:33 +08:00
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;
}
2022-06-25 14:48:20 +08:00
2021-12-09 21:00:09 +08:00
}