Skip to content

Instantly share code, notes, and snippets.

@gangstaJS
Created October 13, 2015 09:59
Show Gist options
  • Save gangstaJS/7a93427c8f3c274aae44 to your computer and use it in GitHub Desktop.
Save gangstaJS/7a93427c8f3c274aae44 to your computer and use it in GitHub Desktop.
<?php
set_time_limit(0);
/* ----------------------------- CONFIG -----------------------------*/
$master_server = "dev2.muvik.tv";
$file_server = 1;
// -- API MASTER
define('MASTER_CONVERT_RESULT', 'http://'.$master_server.'/api/convert_result/dota2/', true);
define('MUVIK_GET_TASK', 'http://'.$master_server.'/api/task/dota2/?', true);
define('MUVIK_SEND_STAT', 'http://'.$master_server.'/api/stat/', true);
define('SET_SERVER_LOCATION', 'http://'.$master_server.'/api/set_server_location/dota2/', true);
// -- FILE SERVER CONFIGS
define( 'ROOT_PATH', '/home/muvik/fs'.$file_server.'.muvik.tv/www/', true );
define('CONVERT_PATH', '/home/muvik/fs'.$file_server.'.muvik.tv/www/convert_file/', true);
define('SYS_PATH', '/home/muvik/fs'.$file_server.'.muvik.tv/sys/', true);
define( 'REAL_FILE_PATH', 'files/', true );
// --------------------------------------------
define('BASE_DOMAIN', 'muvik.tv/', true );
define('MUVIK_API_SECRET', 'I44sC8AQerm6Fc236da1jr4dOn9Cn', true );
define('THIS_SERVER', $file_server, true);
define('COUNT_WORKERS', 1, true); // !important;
// --
define('RESULT_LOG', SYS_PATH."convertor_result.log", true);
define('ERRORS_LOG', SYS_PATH.'convertor_errors.log', true);
/*--------------------------- END CONFIGS -----------------------------*/
if(disk_free_space('/') < 1073741824) {
log_write(ERRORS_LOG, 'ERROR: not free space');
die;
}
/* - ---------------------------------- */
$worker = 0;
if ($handle = opendir(CONVERT_PATH)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
if (preg_match("/\.proccess$/", $entry)) {
$worker++;
}
}
}
closedir($handle);
}
if($worker >= COUNT_WORKERS) die("WORKERS LIMIT OVER \r\n");
/* ------------------------------------ */
$task = json_decode(file_get_contents(MUVIK_GET_TASK."secret=".MUVIK_API_SECRET, false), true);
if($task['status'] == 1) {
// --
$progress_log = CONVERT_PATH.$task['md5_file'].".progress.log";
$proccess = CONVERT_PATH.$task['md5_file'].".proccess";
// --
if($task['server_location'] != THIS_SERVER) {
$fs_location = "http://fs".intval($task['server_location']).".".BASE_DOMAIN."giveme/".$task['md5_file'];
$copy_res = copy($fs_location, CONVERT_PATH.$task['md5_file']);
if(!$copy_res) {
log_write(ERRORS_LOG, 'ERROR: copy file '.$task['md5_file'].', from '.$fs_location);
die('ERROR: copy file '.PHP_EOL);
} else {
$res_server_loaction = set_server_loaction($task['md5_file'], $task['object_id']);
if(!isset($res_server_loaction['status']) || ( $res_server_loaction['status'] == 0 )) {
log_write(ERRORS_LOG, 'ERROR: file is copy '.$task['md5_file'].', but cant set server loaction');
die;
}
}
}
$input_file = CONVERT_PATH.$task['md5_file'];
// get info about video;
$movie = new ffmpeg_movie($input_file, false);
$params = [];
// size
$params['height'] = $movie->getFrameHeight();
$params['width'] = $movie->getFrameWidth();
// --
/* ------------------------------------ */
$good_v_codecs = array('h264', 'vp8');
$good_a_codecs = array('aac', 'vorbis');
$good_ext = array('mp4', 'webm');
$good_ext_bool = false;
$a_codec = '';
$v_codec = $movie->getVideoCodec();
if($movie->hasAudio()) {
$a_codec = $movie->getAudioCodec();
}
// --------------------------------
if(in_array($task['extension'], $good_ext)) {
$good_ext_bool = true;
}
// --------------------------------
/* ------------------------------------- */
$duration = $movie->getDuration();
$sizes = array(
'720p' => array(1280, 720),
'480p' => array(640, 480),
//'360p' => array(480, 320),
);
// --
function getwidth($h0, $h1, $w1) { // $h0/$h1*$w1
$w = round($h0/$h1*$w1);
return $w-($w%2);
}
// -----------------------------
$copy_v = false;
$copy_a = false;
$copy_params = array();
if($good_ext_bool) { // if good extension try copy audio or video streams;
if(in_array($v_codec, $good_v_codecs)) {
$copy_v = true;
}
if(!empty($a_codec) && in_array($a_codec, $good_a_codecs)) {
$copy_a = true;
}
$copy_params = array('ext' => $task['extension'], 'q' => 'sd', 'v_c' => $copy_v, 'a_c' => $copy_a);
}
// --
$go = array(); // масив заданий на конвертацию;
// если пригодно для 720p;
if ($params['height'] >= $sizes['720p'][1]) {
$width720 = getwidth($sizes['720p'][1], $params['height'], $params['width']);
$height720 = $sizes['720p'][1];
//array_push($go, array('webm', 'hd', array($width720,$height720)));
array_push($go, array('mp4', 'hd', array($width720,$height720)));
if(!empty($copy_params)) {
$copy_params['q'] = 'hd';
}
}
// -----------------------
$width480 = '';
$height480 = '';
// получаем новый размер с учетом пропорций;
if ($params['height'] >= $sizes['480p'][1]) {
$width480 = getwidth($sizes['480p'][1], $params['height'], $params['width']);
$height480 = $sizes['480p'][1];
} else {
// если размер меньше 480p;
$width480 = $params['width'];
$height480 = $params['height'];
}
// array('mp4', 'sd', array($width480,$height480), true, true); /extension/quality/sizes/copy a:stream/copy v:stream
array_push($go, array('mp4', 'sd', array($width480,$height480)));
//array_push($go, array('webm', 'sd', array($width480,$height480)));
// ###########################################################################################################
$res = true;
$st = 2; //для прогресса, что бы понять какой по счету формат конвертится;
foreach($go as $format) {
if(!$res) break;
// --
$v_c = false;
$a_c = false;
if(!empty($copy_params) && ($copy_params['ext'] == $format[0]) && ($copy_params['q'] == $format[1]) ) {
$v_c = $copy_params['v_c'];
$a_c = $copy_params['a_c'];
}
// --
log_write(RESULT_LOG, "START CONVERT: format -".$format[0].", quality -".$format[1].", size -".$format[2][0]."x".$format[2][1]);
$res = convert($format[0]/*формат*/, $format[1]/*quality*/, $format[2]/*размерность*/, $input_file/*входящий файл*/, $proccess, $progress_log, $duration, $st, $v_c, $a_c);
$st++;
if($res) {
// шлем запрос мастеру готово некоторое качество;
$ready_q = array('format' => $format[0], 'quality' => $format[1], 'md5_file' => $task['md5_file'], 'object_id' => $task['object_id']);
some_ready($ready_q);
} else {
break;
}
}
// ---
if(!$res) {
log_write(ERRORS_LOG, 'ERROR CONVER: '.json_encode($formats));
die('Error convert');
}
convert_complit($task['object_id']);
log_write(RESULT_LOG, '########################## CONVERT COMPLIT: '. $task['md5_file']." ###########################");
// --
} else {
die("Error server response, or not tasks".PHP_EOL);
}
// -------------------
function convert($format, $q, $size = array(), $input_file, $proccess, $progress_log, $duration, $st, $copy_v = false, $copy_a = false) {
list($width, $height) = $size;
$out_file = $input_file."-".$q.".".$format;
$max_bitrate = round(filesize($input_file)/1048576*8192/$duration);
$cmd = '';
$crf_mp4 = array('hd' => 21, 'sd' => 28);
$crf_webm = array('hd' => 5, 'sd' => 10);
$bt_webm = array('hd' => 3, 'sd' => 1);
// --
switch ($format) {
case 'mp4':
$cmd = "ffmpeg -i {$input_file} -y -s {$width}x{$height} -crf ".$crf_mp4[$q]." {$out_file}";
break;
case 'webm':
$cmd = "ffmpeg -i {$input_file} -y -s {$width}x{$height} -c:v libvpx -qmin 0 -qmax 50 -crf ".$crf_webm[$q]." -b:v ".$bt_webm[$q]."M -c:a libvorbis {$out_file}";
break;
}
if($copy_v && $copy_a && ($max_bitrate <= 4500)) {
$cmd = "ffmpeg -i {$input_file} -y -codec copy {$out_file}";
}
log_write(RESULT_LOG, "FILE IN PROCCESS ".$cmd);
echo $cmd.PHP_EOL;
// отправляем файл на конвертацию;
$pipes = array();
$descriptors = array(2 => array('file', $progress_log, 'a'));
$p = proc_open($cmd, $descriptors, $pipes);
// статус процесса конвертации;
$status = proc_get_status($p);
// если конвертация в процессе создаем блокирующий файл;
if($status['running']) {
file_put_contents($proccess, $st);
}
while(1) {
sleep(3);
$status = proc_get_status($p);
if(!$status['running']) break;
}
if($status['exitcode'] == 0) {
proc_close($p);
// удаляем лог прогресса и блокирующий файл;
unlink($proccess);
unlink($progress_log);
return true;
} else {
return false;
}
}
// --------
function log_write($path, $msg){
file_put_contents($path , "[".date('y.m.d H:i:s ')."] ".$msg."\r\n", FILE_APPEND|LOCK_EX );
}
// -------
function some_ready($formats_result = array()) {
$c_res = http_build_query(array(
'secret' => MUVIK_API_SECRET,
'convert_result' => 3,
'formats_result' => json_encode($formats_result)
));
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => $c_res,
),
);
$context = stream_context_create($options);
return file_get_contents(MASTER_CONVERT_RESULT, false, $context);
}
// -------
function set_server_loaction($md5_file, $object_id) {
$c_res = http_build_query(array(
'secret' => MUVIK_API_SECRET,
'server_location' => THIS_SERVER,
'object_id' => $object_id,
));
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => $c_res,
),
);
$context = stream_context_create($options);
return json_decode(file_get_contents(SET_SERVER_LOCATION, false, $context), true);
}
// ----------------------------------------
function convert_complit($object_id) {
$c_res = http_build_query(array(
'secret' => MUVIK_API_SECRET,
'convert_result' => 4,
'object_id' => $object_id
));
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => $c_res,
),
);
$context = stream_context_create($options);
return file_get_contents(MASTER_CONVERT_RESULT, false, $context);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment