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; //Preset paths are location where ffmpeg can load //Preset files from, usually we don't need to //Add the path as it is already defined in $HOME variable //But due to limitation on server this variable is quite //$this->set_preset_path() to set the preset path //Helpful. var $preset_path = NULL; /** * 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)) { $this->log(''.$input.' File does not exist...'); 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; $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); } if(file_exists($outputFile) && !$this->output_log) 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, ); if($params && $defaults) $params = array_merge($defaults, $params); elseif($defaults) $params = $defaults; $output_file = $params['output_file']; //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']) { if($this->preset_path) $cmd_array['vpre'] = $this->preset_path.'/'.$vcodec.'-'.$params['preset'].'.ffpreset'; else $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; } } } echo $CMD .= " ".$output_file; $log = $this->exec($CMD); return $log; } /** * 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-vflip": { $cmd = "transpose=0"; } break; case "90": { $cmd = "transpose=1"; } break; case "270": { $cmd = "transpose=2"; } 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' && $size!='original') { $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); 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 .= "\" "; } echo $CMD .= " ".$outputname; $this->exec($CMD); 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 */ /* 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; } /** * Set the preset path to load presets from * specified directory * * @param STRING path */ function set_preset_path($path){ $this->preset_path = $path; } } ?>