clipbucket/upload/includes/classes/conversion/conversion.class.php

1681 lines
49 KiB
PHP
Raw Normal View History

2012-04-23 06:15:53 +00:00
<?php
/**
* @author : Arslan Hassan
* @copyright : ClipBucket Conversion Kit 2012
* @license : AAL (Attribute Assurance License)
* @package : ClipBucket CSDK
* @version : 3.0
* @name : CBConverter
* @todo : Convert Videos to Mp4,mp4-mobile, Flv, Ogg with H264
*
*/
/*
* if(!defined('IN_CLIPBUCKET')) exit("Sorry, visitors not allowed");
*/
define('FFMPEG','D:\wamp\bin\ffmpeg\bin\ffmpeg.exe');
define('MPLAYER','D:\wamp\bin\mplayer\mplayer.exe');
define('MEDIAINFO','D:\wamp\bin\mediainfo\MediaInfo.exe');
/**
* These static variables are already defined in ClipBucket,
* if you are not using this SDK with ClipBucket, please uncomment
* following static variables and define them accordingly
*
* define("TEMP_DIR","/path/to/temp_dir");
*
*/
class CBConverter
{
var $input; //Input File
var $output; //Output File
var $inDetails; //Details and Information of Video Input
var $outDetails; //Details and Information of Video Output
//Errors, Warnings and Messages Log, its an array
var $log;
//Max FPS, we are coverting videos for web streaming and 30 fps is more than
//Enough to get a good quality video for online streaming, if you have
//Plans to incrase it, simply change max_fps value and then make changes
//In your input values..
var $max_fps = 30;
//Max Bitrate, for web streaming 512k gives you a very good video quality
//Youtube uses around 365k which is also not bad, here will we set
//640k as max, where k => 1000;
var $max_bitrate = 640000;
//Allowed list of Audio Rates, any input which does not match
//With any of the following will be replaced with the default
//Audio Rate
var $audio_rates = array('22050','44100','48000');
//Setting up max audio bitrate, usually 128k is good but incase you want
//To enhance the video quality you can incrase it. read more about
//Audio bitrate on google
var $max_audio_bitrate = 396000;
//IN some cases ffmpeg is not abelt convert video with more than 5 channels
//In this situtation we have to force use 2 channels for the output video
//As for web video, 2 channel video is actualyl pretty good
//By setting it to true, we will use force 2 channelf or videos more than
// 5 channels otherwise it will skipp the step
var $valid_two_channels = true;
//Log file where output of every command will be given.
//By default is set to false so that defined output file can be used
//if value set, this file will be used to save outptu.
var $output_log = false;
2012-04-23 06:15:53 +00:00
/**
* Constructor and sets the input file and get information..
* @param Video File
*/
function CBConverter($file=NULL)
{
if($file)
{
$this->input = $file;
$info = $this->getInfo();
$this->inDetails = $info;
}
}
/**
* @name : getInfo
* @todo : Get Video Information
* @param STRING input
* @return ARRAY video details
*/
function getInfo($input=false)
{
if(!$input)
$input = $this->input;
if(!file_exists($input))
{
2012-07-16 14:53:27 +00:00
$this->log('<strong>'.$input.'</strong> File does not exist...');
2012-04-23 06:15:53 +00:00
return $this->log();
}
$info = $this->_getInfo($input);
return $info;
}
/**
* @name : _getInfo
* @todo : Generate video info using FFMPEG or php-ffmpeg (if available)
* @param STRING input video
* @return ARRAY of video details
*/
private function _getInfo($input)
{
//Checking if php-ffmpeg extension is available
//there is no ffmpeg-php for windows..will work on it later...
$CMD = FFMPEG.' -i "'.$input.'" -acodec copy'.
' -vcodec copy -f null ';
//Add /dev/null in non win os
if(!stristr(php_uname('s'),'windows'))
$CMD .= '/dev/null';
$rawOutput = $this->exec($CMD,true);
$parsedData = $this->parseData($rawOutput);
//Now Getting information from media info
$CMD = MEDIAINFO.' '.$input;
$rawOutput = $this->exec($CMD,true);
//Get Parsed Data from media Info
$miParsedData = $this->parseData($rawOutput,true);
//Merge two arrays
if($miParsedData)
$parsedData = array_merge ($parsedData,$miParsedData);
return $parsedData;
}
/**
* function get ffmpeg version
* @name getVersion
* @return ffmpeg version
*/
function getVersion()
{
$CMD = FFMPEG.' -version';
$output = $this->exec($CMD,true);
$array = array();
//Checking for revision
preg_match('/ffmpeg version N\-([0-9]+)\-/i',$output,$rev);
$rev = $rev[1];
if($rev)
$array['rev'] = $rev;
//Checking for version..
preg_match('/ffmpeg version ([0-9.]+)/',$output,$ver);
$ver = $ver[1];
if($ver)
$array['ver'] = $ver;
//Checking for built date
preg_match('/built on ([A-Za-z]{3}) ([0-9]{1,3}) ([0-9]{4}) /',$output,$date);
$date = $date[1].' '.$date[2].' '.$date[3];
$time = strtotime($date);
if($date)
{
$array['date'] = date('Y-m-d',$time);
$array['timestamp'] = $time;
}
return $array;
}
/**
* @name : log
* @todo : Log Message or Error and Insert it into log (Array)
* @param STRING message
* @param STRING type (e,w,m) for (errors,warnings and messages) res..
* @return ARRAY of log
*/
function log($msg=NULL,$type=e,$index=null)
{
if(!$msg)
return $this->log;
if($index)
$this->log[$type][$index] = $msg;
else
$this->log[$type][] = $msg;
return $this->log;
}
/**
* @name exec
* @param type $cmd
* @param type $output
* @return type
*/
function exec( $cmd,$output=false ) {
# use bash to execute the command
# add common locations for bash to the PATH
# this should work in virtually any *nix/BSD/Linux server on the planet
# assuming we have execute permission
//$cmd = "PATH=\$PATH:/bin:/usr/bin:/usr/local/bin bash -c \"$cmd\" ";
$output_cmd = "";
if($output)
{
if(function_exists('RandomString'))
$outputFile = TEMP_DIR.'/'.time().RandomString(5);
else
$outputFile = TEMP_DIR.'/'.time().mt_rand(5, 6);
if($this->output_log)
$outputFile = $this->output_log;
2012-04-23 06:15:53 +00:00
$output_cmd = " 2> ".$outputFile;
}
$result = shell_exec( $cmd.$output_cmd);
if(!$result && $output)
{
//Read output file..
if(file_exists($outputFile))
$result = file_get_contents ($outputFile);
}
2012-07-16 14:53:27 +00:00
if(file_exists($outputFile) && !$this->output_log)
2012-04-23 06:15:53 +00:00
unlink($outputFile)
or $this->log('Unable to remove tmp bash output file','e');
return $result;
}
/**
* @name parseData
* @todo Parse data and list them in array
* @param STRING $content
* @param BOOLEAN $mi MediaInfo data
* @return ARRAY
*/
function parseData($content,$mi=false)
{
$info = array();
//Things we need to extract
/**
* duration
* width and height
* bitrate
* frame rate
* audio bitrate
* audio rate
* audio channels
* video codec
* audio codec
* format
*/
#Getting Duration
$duration = $this->pregMatch( 'Duration: ([0-9.:]+),', $content );
$duration = $duration[1];
$duration = explode(':',$duration);
//Convert Duration to seconds
$hours = $duration[0];
$minutes = $duration[1];
$seconds = $duration[2];
$hours = $hours * 60 * 60;
$minutes = $minutes * 60;
$duration = $hours+$minutes+$seconds;
$info['duration'] = $duration;
#Video Bitrate
//Setting has_video bydefault to no
$info['has_video'] = 'no';
$args= $this->pregMatch( 'bitrate: ([0-9]+) kb\/s', $content );
if($args) {
$info['bitrate' ] = $args[1]*1000/8;
}
#Checking fps
$args = $this->pregMatch(', ([0-9.]+) fps',$content);
if($args)
{
$info['fps'] = $args[1];
}
#Using TBR to determine fps incase there is no value for above method
if(!$info['fps'])
{
$args = $this->pregMatch(', ([0-9.]+) tbr',$content);
if($args)
{
$info['fps'] = $args[1];
}
}
#Total Frames
if($info['fps'])
$info['frames'] = $duration * $info['fps'];
#Getting Video Width, Height and the Ratio
$args= $this->pregMatch( '([0-9]{2,4})x([0-9]{2,4})', $content );
if($args) {
$info['width' ] = $args[1];
$info['height' ] = $args[2];
$info['wh_ratio'] = (float)$info['width'] / (float)$info['height'];
if($args[1])
$info['has_video'] = 'yes';
}
#Getting Video Codec
$args= $this->pregMatch('Video: ([^ ^,]+)',$content);
if($args)
{
$info['video_codec' ] = $args[1];
}
# get audio information
//Setting has audio bydefault to no
$info['has_audio'] = 'no';
$args = $this->pregMatch( "Audio: ([^ ]+), ([0-9]+) Hz, ".
"([0-9+.^\n]*)(.*)?, ([0-9]+) kb\/s", $content);
if($args) {
$audio_codec = $info['audio_codec'] = $args[1];
$audio_rate = $info['audio_rate'] = $args[2];
$info['audio_channels'] = $args[3];
$info['audio_bitrate'] = $args[5];
if($args[1])
$info['has_audio'] = 'yes';
//Checking if there is streo or mono stuff
//Then make changes for channel key
if(!$info['audio_channels'])
{
if(strstr( $args[4],'stereo'))
$channels = 2;
if(strstr( $args[4],'mono'))
$channels = 1;
$info['audio_channels'] = $channels;
}
}
//Incase we are not able to fetch info from above method, then
//Try an alternative..
if(!$audio_codec || !$audio_rate)
{
$args = $this->pregMatch( "Audio: ([a-zA-Z0-9]+)(.*), ".
"([0-9]+) Hz, ([0-9+]*)(.*)?, ([0-9]+) kb\/s", $content);
$info['audio_codec' ] = $args[1];
$info['audio_rate' ] = $args[3];
$info['audio_channels'] = $args[4];
$info['audio_bitrate'] = $args[6];
if($args[1])
$info['has_audio'] = 'yes';
//Checking if there is streo or mono stuff
//Then make changes for channel key
if(!$info['audio_channels'])
{
if(strstr( $args[5],'stereo'))
$channels = 2;
if(strstr( $args[5],'mono'))
$channels = 1;
$info['audio_channels'] = $channels;
}
}
$info['audio_bitrate'] *= 1000;
/**
* We use MediaInfo in addition with FFMPEG to extract information
* Because ffmpeg is not able to extract all info that we need
* such as rotation language etc..
*/
//Parsing from mdiainfo
/** Dumping, just extracting rotation for now ;)
if(!$info['duration'])
{
$duration = $this->pregMatch('Duration(\s+)\" : \"([0-9a-z ]+)', $content);
$durations = explode(' ',$duration[2]);
$mins = 0;
$hrs = 0;
$secs = 0;
$msecs = 0;
foreach($durations as $d)
{
if(strstr($d,'mn'))
{
$mins = str_replace('mn', '', $d);
}elseif(strstr($d,'h'))
{
$hrs = str_replace('h', '', $d);
}elseif(strstr($d,'ms'))
{
$msecs = str_replace('ms', '', $d);
}elseif(strstr($d,'s'))
{
$secs = str_replace('s', '', $d);
}
}
$duration = ($hrs*60*60) + ($mins*60) + $secs + ($msecs/1000);
$info['duration'] = $duration;
}
//Checking if input has audio and or video
if($info['has_video']=='no')
{
$fps = $this->pregMatch('Frame rate(\s+)\" : \"([0-9.]+)\"',
$content);
if($fps[2] && strstr($content,'Video'))
{
$info['has_video'] = 'yes';
$info['fps'] = $fps[2];
}
//Checking for width and height..
$width = $this->pregMatch('Width(\s+)\" : \"([0-9]+)\"',
$content);
$height = $this->pregMatch('Height(\s+)\" : \"([0-9]+)\"',
$content);
$info['height'] = $height[2];
$info['width'] = $width[2];
}
if($info['has_audio']=='no')
{
$channels = $this->pregMatch('Channel\(s\)(\s+)\" : \"([0-9]+)\"',
$content);
if($channels[2] && strstr($content,'Audio'))
$info['has_video'] = 'yes';
$info['audio_channels'] = $channels[2];
}
*/
if($mi)
{
$info = '';
$rotation = $this->pregMatch('Rotation(\s+)\"? : \"?([0-9]+)', $content);
if($rotation[2])
$info['rotation'] = $rotation[2];
else
$info['rotation'] = 0;
}
return $info;
}
/**
* Get video duration, from inDetails/outDetails array...
* @param STRING in/out
* @return STRING Duration
*/
function getDuration($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['duration'];
}
/**
* Get video frames count
* @param STRING in/out
* @return STRING frames count
*/
function getFramesCount($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['frames'];
}
/**
* Get Video Frame Rate per Second
* @param STRING in/out
* @return STRING fps
*/
function getFrameRate($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['fps'];
}
/**
* Get Video File Name
* @param STRING in/inout
* @return STRING filename
*/
function getFilename($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['filename'];
}
/**
* Get Video Height
* @param STRING in/out
* @return STRING video height
*/
function getHeight($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['height'];
}
/**
* Get video width
* @param STRING in/out
* @return STRING video width
*/
function getWidth($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['width'];
}
/**
* Get WHRatio
* @param STRING in/out
* @return STRING WHRatio
*/
function getWHRatio($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['width']/$arr['height'];
}
/**
* Get Audio Bitrate
* @param STRING in/out
* @return STRING audio bitrate
*/
function getAudioBitrate($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['audio_bitrate'];
}
/**
* Get Audio Sample Rate
* @params STRING in/out
* @return STRING audio rate
*/
function getAudioRate($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['audio_rate'];
}
/**
* Get Video Bitrate
* @param STRING in/out
* @return STRING video bitrate
*/
function getVideoBitrate($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['bitrate'];
}
/**
* Get Video Rate
* @params STRING in/out
* @return STRING video rate
*/
function getVideoRate($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['video_rate'];
}
/**
* Get audio codec
* @params STRING in/out
* @return STRING audio codec
*/
function getAudioCodec($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['audio_codec'];
}
/**
* Get video codec
* @params STRING in/out
* @return STRING video codec
*/
function getVideoCodec($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['video_codec'];
}
/**
* Get audio channels
* @params STRING in/out
* @return STRING audio channels
*/
function getAudioChannes($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
return $arr['audio_channels'];
}
/**
* Check file has video or not
* @params STRING in/out
* @return BOOLEAN
*/
function hasVideo($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
if($arr['has_video']=='yes')
return true;
else
return false;
}
/**
* Check file has audio or not
* @params STRING in/out
* @return BOOLEAN
*/
function hasAudio($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
if($arr['has_audio']=='yes')
return true;
else
return false;
}
/**
* Check file has audio or not
* @params STRING in/out
* @return BOOLEAN
*/
function getRotation($vid='in')
{
$arr = $this->inDetails;
if($vid!='in')
$arr = $this->outDetails;
if($arr['rotation'])
return $arr['rotation'];
else
return '0';
}
/**
* Function used to convert video in
* - MP4 , h264, aac for web streaming
* - FLV , h264, aac for web streaming
* - WebM, Standard Adopted by Google for webs streaming using HTML5
* - mobile , H264/3GP for mobile streaming
*
* Resize =>
*/
function convert($params=false)
{
$defaults = array(
'format' => 'flv',
'2pass' => false,
'h264' => true,
'height' => '490',
'width' => '640',
'resize' => 'max',
'bitrate' => 512000,
'aspect_ratio' => '4:3',
'arate' => '22050',
'fps' => 24,
'abitrate'=> 128000,
'preset' => 'normal',
'auto_rotate' => true,
2012-04-23 06:15:53 +00:00
);
2012-04-23 06:15:53 +00:00
if($params && $defaults)
$params = array_merge($defaults, $params);
elseif($defaults)
$params = $defaults;
$output_file = $params['output_file'];
2012-04-23 06:15:53 +00:00
//Creating array to pass to calculateResize func
//and get resizeable width and height...
$dimInfo = array(
'height' => $this->getHeight(),
'width' => $this->getWidth(),
'resize_height' => $params['height'],
'resize_width' => $params['width'],
'wh_ratio' => $this->getWHRatio(),
'resize_ratio' => $params['aspect_ratio'],
'resize' => $params['resize'],
);
$resizedInfo = $this->calculateResize($dimInfo);
/**
* Here we will preset everything before checking for which
* format we are going to convert into..
* first we will set up basic values for all common inputs such
* as width, height, bitrates, by default we will make
* h264 and aac to be used as video and audio codecs, respectively.
* we can later change them in switch statement.
*/
//Setting Up the Codecs..
$validCodecs = array('libx264','libvorbis','libfaac','mpeg4','aac',
'libmp3lame','mp3','flv','libvpx');
$vcodec = $params['vcodec'];
if(!in_array($vcodec, $validCodecs) && $vcodec)
{
$vcodec = 'libx264';
}
if(!$vcodec && $params['h264'])
$vcodec = 'libx264';
$acodec = $params['acodec'];
if(!in_array($acodec, $validCodecs) && $acodec
|| ( !$acodec && $vcodec = 'libx264'))
{
$acodec = 'libfaac';
}
//Setting videobitrate and audiobitrate..
//Learn more about bitrates on google ;)
$fps = $params['fps'];
$in_fps = $this->getFrameRate();
$fps = min($fps,$in_fps);
//As we are converting videos for web streaming, so we are keeping
//Frame rates to max 30 chek max_fps var, if you have plans of changing to more
//Simple change the second condition..
if($fps<24)
$fps = 24;
if($fps>$this->max_fps)
$fps = $this->max_fps;
//Bitrate controls the size and quality we are setting them
//To get the best output...max bitrate by default is 640k
$bitrate = $params['bitrate'];
$in_bitrate = $this->getVideoBitrate();
$bitrate = min($bitrate,$in_bitrate);
if($bitrate>$this->max_bitrate)
$bitrate = $this->max_bitrate;
//Audio Rate also known as sample rate will make your audio
//Heard more clearly WRT media and in web streaming we
//use 22050,44100 or 48000
$arate = $params['arate'];
$in_arate = $this->getAudioRate();
$arate = min($arate,$in_arate);
if(!in_array($arate, $this->audio_rates))
{
$arate = $defaults['arate'];
}
//Audio Bitrate controls the audio quality, usually
//96k bit audio is pretty good fod videos but if you want to get
//More quality audio you can increase audio bitrate to 128, 164,
//256, 396 etc...by default we will use 128k and for max 396k
$abitrate = $params['abitrate'];
$in_abitrate = $this->getAudioBitrate();
$abitrate = min($abitrate,$in_abitrate);
if(!$abitrate>$this->max_audio_bitrate)
$abitrate = $this->max_audio_bitrate;
$presets = array(
'width' => $resizedInfo['width'],
'height' => $resizedInfo['height'],
'aspect_ratio' => $resizedInfo['ratio'],
'vcodec' => $vcodec,
'acodec' => $acodec,
'preset' => $params['preset'],
'fps' => $fps,
'arate' => $arate,
'bitrate' => $bitrate,
'abitrate' => $abitrate,
);
//Setting the input option array which will later become
//String/command to make things more easier
$cmd_array = array(
'i' => $this->input,
);
//Overwrite existing
$cmd_array['y'] = ' ';
if($presets['acodec'])
$cmd_array['acodec'] = $presets['acodec'];
if($presets['vcodec'])
$cmd_array['vcodec'] = $presets['vcodec'];
if($presets['width'] && $presets['height'])
$cmd_array['s'] = $presets['width'].'x'.$presets['height'];
if($presets['fps'])
$cmd_array['r'] = $presets['fps'];
if($presets['bitrate'])
$cmd_array['b:v'] = $presets['bitrate'];
if($presets['arate'])
$cmd_array['ar'] = $presets['arate'];
if($presets['abitrate'])
$cmd_array['ab'] = $presets['abitrate'];
//If channels are greater than 2, video is not convertable
//In many cases, so we always choose 2 channel audio
if($this->valid_two_channels)
if($this->getAudioChannes()>2)
$cmd_array['ac'] = 2;
/**
* Checking if there is some duration or size limit
*/
if($params['max_duration'] && is_numeric($params['max_duration']))
{
$cmd_array['t'] = $params['duration'];
}
if($params['max_size'] && is_numeric($params['max_size']))
{
$cmd_array['fs'] = $params['max_size'];
}
//Padding
$rinfo = $resizedInfo;
if($rinfo['pad_x'] || $rinfo['pad_y'])
{
$pad_width = $rinfo['width'] + ($rinfo['pad_x']*2);
$pad_height = $rinfo['height'] + ($rinfo['pad_y']*2);
if(!$params['padding_color'])
$pad_color = 'black';
else
$pad_color = $params['padding_color'];
$pad_cmd = "pad=$pad_width:$pad_height";
$pad_cmd .= ":".$rinfo['pad_x'].":".$rinfo['pad_y'];
$pad_cmd .= ":".$pad_color;
$cmd_array['vf']['pad'] = $pad_cmd;
}
/**
* Attaching subtitles..
* subtitles are array and must be only ttf
*/
if($params['subtitles'])
{
}
//Adding Watermark
if($params['watermark'])
{
$cmd_array['vf']['overlay'] =
$this->_genWatermark($params['watermark'],
$params['watermarl_position'],
$params['watermark_offset']);
}
//Adding Rotation
if($params['auto_rotate'])
{
$rotationCMD = $this->_getRotation($this->inDetails['rotation']);
if($rotationCMD)
{
$cmd_array['vf']['rotation'] = $rotationCMD;
}
}
//Disabling audio in case there is no audio
if(!$this->hasAudio())
$cmd_array['an'] = '';
switch($params['format'])
{
//FLV and Mp4 uses almost same method to get the output
//unless Mp4 is for mobile, however both are converted
//Using same codecs (mostly libx264) thats why
//we will use same code for both
case "flv":
case "mp4":
case "m4v":
case "f4v":
default:
{
$f = $params['format'];
if($params['preset'])
$cmd_array['vpre'] = $params['preset'];
/**
* - f
* Force input or output file format. The format is normally
* auto detected for input files and guessed from file extension
* for output files, so this option is not needed in most cases.
*/
/*if($f=='f4v' || $f=='mp4' || $f=='m4v')
$cmd_array['f'] = 'mp4';
if($f=='flv')
$cmd_array['f'] = 'flv';*/
}
break;
case "webm":
{
$cmd_array['vcodec'] = 'libvpx';
$cmd_array['acodec'] = 'libvorbis';
$cmd_array['f'] = 'webm';
}
case "mobile":
case "mobile-mp4":
{
//Add mobile conditions here..
}
break;
case "3gp":
{
//Auto-detect by ffmpeg :)
/*$cmd_array['vcodec'] = 'h263';
$cmd_array['acodec'] = 'libamr_nb';*/
unset($cmd_array['vcodec']);
unset($cmd_array['acodec']);
unset($cmd_array['ar']);
//Ideal video bitrate for 3gp is 4.7k
$cmd_array['b:v'] = '4.7k';
//Idea audio rate for 3gp is 8k
$cmd_array['ar'] = 8000;
//3gp supports following dimensions
//128x96,176x144,352x288,704x576,1408x1152
$widths = array('128','176','352','704','1408');
$closest_width = $this->getClosest($params['width'],$widths);
$dims = array(
'128' => array('width'=>128,'height'=>96),
'176' => array('width'=>176,'height'=>144),
'352' => array('width'=>352,'height'=>288),
'704' => array('width'=>704,'height'=>576),
'1408' => array('width'=>1408,'height'=>1152)
);
$dimInfo['resize_width'] = $dims[$closest_width]['width'];
$dimInfo['resize_height'] = $dims[$closest_width]['height'];
$dimInfo['resize_ratio'] = 1.222222222222222;
$dimInfo['resize'] = 'fit';
//Recalculating Video Dimension
$rinfo = $this->calculateResize($dimInfo);
//Setting Padding and Resize parameters
$cmd_array['s'] = $rinfo['width'].'x'.$rinfo['height'];
//Padding
if($rinfo['pad_x'] || $rinfo['pad_y'])
{
$pad_width = $rinfo['width'] + ($rinfo['pad_x']*2);
$pad_height = $rinfo['height'] + ($rinfo['pad_y']*2);
if(!$params['padding_color'])
$pad_color = 'black';
else
$pad_color = $params['padding_color'];
$cmd_array['vf']['pad'] = "pad=$pad_width:$pad_height";
$cmd_array['vf']['pad'] .= ":".$rinfo['pad_x'].":".$rinfo['pad_y'];
$cmd_array['vf']['pad'] .= ":".$pad_color;
}
$cmd_array['ac'] = 1;
}
break;
case 'ogg';
{
//Add ogg conditions here...
unset($cmd_array['vcodec']);
unset($cmd_array['acodec']);
}
break;
}
$CMD = FFMPEG;
foreach($cmd_array as $opt => $val)
{
if($val)
{
if(is_array($val))
{
foreach($val as $k => $v)
{
if($v)
{
$CMD .= " -".$opt;
$CMD .= " '".$v."' ";
}
}
}else
{
$CMD .= " -".$opt;
$CMD .= " ".$val;
}
}
}
$CMD .= " ".$output_file;
$log = $this->exec($CMD);
2012-04-23 06:15:53 +00:00
return $log;
2012-04-23 06:15:53 +00:00
}
/**
* Function used to calculate video padding
*/
private function calculateResize($params)
{
$p = $params;
switch( $p['resize'] ) {
# dont resize, use same size as source, and aspect ratio
# WARNING: some codec will NOT preserve the aspect ratio
case 'no':
default:
$width = $p['width' ];
$height = $p['height' ];
$ratio = $p['wh_ratio'];
$pad_x = 0;
$pad_y = 0;
break;
# resize to parameters width X height, use same aspect ratio
# WARNING: some codec will NOT preserve the aspect ratio
case 'WxH':
case "wxh":
$width = $p['resize_width' ];
$height = $p['resize_height' ];
$ratio = $p['wh_ratio'];
$pad_y = 0;
$pad_x = 0;
break;
# make pixel square
# reduce video size if bigger than p[width] X p[height]
# and preserve aspect ratio
case 'max':
$width = (float)$p['width' ];
$height = (float)$p['height' ];
$ratio = (float)$p['wh_ratio'];
$max_width = (float)$p['resize_width' ];
$max_height = (float)$p['resize_height' ];
# make pixels square
if( $ratio > 1.0 )
$width = $height * $ratio;
else
$height = @$width / $ratio;
# reduce width
if( $width > $max_width ) {
$r = $max_width / $width;
$width *= $r;
$height *= $r;
}
# reduce height
if( $height > $max_height ) {
$r = $max_height / $height;
$width *= $r;
$height *= $r;
}
# make size even (required by many codecs)
$width = (integer)( ($width + 1 ) / 2 ) * 2;
$height = (integer)( ($height + 1 ) / 2 ) * 2;
break;
case "fit":
{
$width = (float)$p['width' ];
$height = (float)$p['height' ];
$ratio = (float)$p['wh_ratio'];
$max_width = (float)$p['resize_width' ];
$max_height = (float)$p['resize_height' ];
# make pixels square
if( $ratio > 1.0 )
$width = $height * $ratio;
else
$height = @$width / $ratio;
# reduce width
if( $width > $max_width ) {
$r = $max_width / $width;
$width *= $r;
$height *= $r;
}
# reduce height
if( $height > $max_height ) {
$r = $max_height / $height;
$width *= $r;
$height *= $r;
}
# make size even (required by many codecs)
$width = (integer)( ($width + 1 ) / 2 ) * 2;
$height = (integer)( ($height + 1 ) / 2 ) * 2;
$output_width = $p['resize_width'];
$output_height = $p['resize_height'];
$pad_x = $output_width-$width;
$pad_x /= 2;
$pad_y = $output_height-$height;
$pad_y = $pad_y/2;
}
}
return array('width'=>$width,'height'=>$height,'pad_x'=>
$pad_x,'pad_y'=>$pad_y,'ratio'=>$ratio);
}
/**
* @name : pregMatch
* @todo : Simplifies Pregmatch by added slashes
* @return STRING
*/
function pregMatch($in,$str)
{
preg_match("/$in/",$str,$args);
return $args;
}
/**
* Find closest value..
* @param STRING search in numeric
* @param ARRAY an array of values to be matched
* @return Matched string
*/
function getClosest($search, $arr)
{
$closest = null;
foreach($arr as $item)
{
if($closest == null || abs($search - $closest) > abs($item - $search))
{
$closest = $item;
}
}
return $closest;
}
/**
* function used to generate watermark command
* @params STRING watermark file
* @params STRING position
* @params STRING offset array(x,y)
*/
private function _genWatermark($file,$position='tr',$offset=NULL)
{
if(!$offset)
$offset = array(10,10);
//This will only generate overlay command
if(file_exists($file)){
$yOffset = $offset[1] ? $offset[1] : '0';
$xOffset = $offset[0] ? $offset[0] : '0';
$positions = array(
'tr' => 'W-w-'.$xOffset.':'.$yOffset,
'tl' => $xOffset.':'.$yOffset,
'bl' => $xOffset.':H-h-'.$yOffset,
'br' => 'W-w-'.$xOffset.':H-h-'.$yOffset,
);
if(!$positions[$position])
$position = 'tr';
$LOGO = $file;
$cmd = 'movie='.$LOGO.'[logo];[in][logo]overlay='.$positions[$position].'[out]';
return $cmd;
}
return false;
}
/**
* Function used to add watermark on a video
* @param ARRAY
* - input
* - output
* - watermark
* - position (tl,tr,bl,bf)
* - offest array(x,y)
*/
function addWatermark($file,$output,$watermark,$position='tr',$offset=array(10,10))
{
if(!$file || !file_exists($file))
return false;
if(!$watermark || !file_exists($watermark))
return false;
//using _getWatermark function to get the command
$overlay_cmd = $this->_genWatermark($watermark,$position,$offset);
$CMD = FFMPEG;
$CMD .= " -i '$file' ";
//force overwrite
$CMD .= " -y ";
$CMD .= $output;
$output = $this->exec($CMD,true);
//Todo : Create result parser and output resutls
return true;
}
/**
* Function used to generate rotate video command
* @param FILE
*/
private function _getRotation($rotation)
{
if($rotation)
{
switch($rotation)
{
case "90":
{
$cmd = "transpose=1";
}
break;
case "270":
{
$cmd = "transpose=2";
}
break;
case "90-vflip":
{
$cmd = "transpose=0";
}
break;
case "270-vflip":
{
$cmd = "transpose=3";
}
break;
case "vflip":
{
$cmd = "vflip";
}
break;
case "hflip":
{
$cmd = "hflip";
}
}
if($cmd)
{
return $cmd;
}
}
return false;
}
/**
* Function used to rotate video
*
*/
function rotateVideo($file,$rotation)
{
if(!$file || !file_exists($file))
return false;
$rotateCmd = $this->_getRotation($rotation);
$CMD = FFMPEG;
$CMD .= " -i '$file' ";
//force overwrite
$CMD .= " -y ";
$CMD .= $output;
$output = $this->exec($CMD,true);
//Todo : Create result parser and output resutls
return true;
}
/**
* function used to extract image from a video
* @param STRING input file
* @param array(
* 'num' => number of images..
* 'size' => WidthxHeight
* 'time' => sepecific time
* '
* )
*/
function extractThumb($input=false,$params=false)
{
$defaults = array
(
'size' => 'same',
'time' => '5',
'num' => '20',
'increment' => true,
'outname' => getName($input),
'outdir' => TEMP_DIR,
'resize' => 'fit'
);
if(!$input)
{
$input = $this->input;
$iDetails = $this->inDetails;
}else
{
if(file_exists($input))
{
$iDetails = $this->_getInfo($input);
}else{
//log the fishy error
}
}
if(!$iDetails)
{
//Log an error...
return false;
}
if($params)
$params = array_merge($defaults,$params);
else
$params = $defaults;
//If there is no outname then re-create1
if(!$params['outname'])
{
$params['outname'] = getname($this->input);
}
$count = 0;
$outname = $params['outname'];
$outputname = $outname.'.jpg';
//Adding increment
while(1)
{
if($count>0)
$outputname = $outname.'-'.$count.'.jpg';
if(!file_exists($params['outdir'].'/'.$outputname))
{
break;
}else
{
if(!$params['increment'])
{
unlink($params['outdir'].'/'.$outputname);
break;
}
}
$count++;
}
//Setting upt the size
$size = $params['size'];
if($size!='same')
{
$sizes = explode('x',$size);
$width = $sizes[0];
$height = $sizes[1];
$dimInfo = array(
'height' => $iDetails['height'],
'width' => $iDetails['width'],
'resize_height' => $height,
'resize_width' => $width,
'wh_ratio' => $iDetails['width']/$iDetails['height'],
'resize_ratio' => $width/$height,
'resize' => $params['resize'],
);
$rinfo = $this->calculateResize($dimInfo);
$pad_width = $rinfo['width'] + ($rinfo['pad_x']*2);
$pad_height = $rinfo['height'] + ($rinfo['pad_y']*2);
2012-04-23 06:15:53 +00:00
if(!$params['padding_color'])
$pad_color = 'black';
else
$pad_color = $params['padding_color'];
$cmd_array['vf']['pad'] = "pad=$pad_width:$pad_height";
$cmd_array['vf']['pad'] .= ":".$rinfo['pad_x'].":".$rinfo['pad_y'];
$cmd_array['vf']['pad'] .= ":".$pad_color;
}
//Setting Time
if($params['time'])
{
$time = $params['time'];
}
//Setting numbers
$vframes = 1;
$rateCMD = "";
if($params['num'])
{
if($params['num']>1)
{
$outputname = $params['outdir'].'/'
.$params['outname'].'-%03d.jpg';
$vframes = $params['num'];
$rateCMD = " -r ".$vframes.'/'.$iDetails['duration'];
}
}
$CMD = FFMPEG;
if($time)
{
$CMD .= ' -ss '.$time;
}
$CMD .= ' -i '.$input;
$CMD .= " -y ";
$CMD .= " -an ";
$CMD .= " -sameq ";
$CMD .= " -vframes ".$vframes;
$CMD .= " -f image2";
$CMD .= " -vcodec mjpeg";
if($rateCMD)
{
$CMD .= $rateCMD;
}
if($size!='same')
{
$CMD .= " -s ".$rinfo['width']."x".$rinfo['height'];
$CMD .= " -vf '";
$CMD .= "pad=$pad_width:$pad_height";
$CMD .= ":".$rinfo['pad_x'].":".$rinfo['pad_y'];
$CMD .= ":".$pad_color;
$CMD .= "' ";
}
$CMD .= " ".$outputname;
return $CMD;
}
/**
* FFmpeg log praser
*
* This function will look for errors, warnings and anything from ffmpeg
* which causing problem while conversion or anything. We will keep
* updating this functions as we will have more new errors in future
*
* @param STRING $LOG
* @return ARRAY $ERRORS
*/
function ffmpegLogParser($log)
{
$errors = array();
/* Checking if there is some ffmepg execution error */
preg_match();
/* Checking for codec missing error */
2012-04-23 06:15:53 +00:00
/* Checking for bitrate/width/etc issue */
/* Checking for preset error */
/* Checking for file missing error */
}
/**
* function used to set the log file
* Simple set the value for output_log
*
* @param STRING $file
*/
function set_log($file=false)
{
if(!$file)
$file = $outputFile = TEMP_DIR.'/'.time().mt_rand(5, 6);
$this->output_log = $file;
return $file;
}
2012-04-23 06:15:53 +00:00
}
?>