ffmpeg Barra de progreso-Porcentaje de codificación en PHP
regex parsing (3)
De acuerdo, he encontrado lo que necesitaba, ¡y espero que esto ayude a alguien más también!
En primer lugar, desea enviar los datos de ffmpeg a un archivo de texto en el servidor.
ffmpeg -i path/to/input.mov -vcodec videocodec -acodec audiocodec path/to/output.flv 1> block.txt 2>&1
Entonces, la salida de ffmpeg es block.txt. Ahora en PHP, ¡hagámoslo!
$content = @file_get_contents(''../block.txt'');
if($content){
//get duration of source
preg_match("/Duration: (.*?), start:/", $content, $matches);
$rawDuration = $matches[1];
//rawDuration is in 00:00:00.00 format. This converts it to seconds.
$ar = array_reverse(explode(":", $rawDuration));
$duration = floatval($ar[0]);
if (!empty($ar[1])) $duration += intval($ar[1]) * 60;
if (!empty($ar[2])) $duration += intval($ar[2]) * 60 * 60;
//get the time in the file that is already encoded
preg_match_all("/time=(.*?) bitrate/", $content, $matches);
$rawTime = array_pop($matches);
//this is needed if there is more than one match
if (is_array($rawTime)){$rawTime = array_pop($rawTime);}
//rawTime is in 00:00:00.00 format. This converts it to seconds.
$ar = array_reverse(explode(":", $rawTime));
$time = floatval($ar[0]);
if (!empty($ar[1])) $time += intval($ar[1]) * 60;
if (!empty($ar[2])) $time += intval($ar[2]) * 60 * 60;
//calculate the progress
$progress = round(($time/$duration) * 100);
echo "Duration: " . $duration . "<br>";
echo "Current Time: " . $time . "<br>";
echo "Progress: " . $progress . "%";
}
Esto produce el porcentaje de tiempo restante.
Puede tener esto como la única pieza de texto repetida en una página, y desde otra página puede realizar una solicitud AJAX utilizando jQuery para tomar esta pieza de texto y enviarla a un div, por ejemplo, para actualizar en su página cada 10 segundos. :)
He escrito todo un sistema en PHP y bash en el servidor para convertir y transmitir videos en HTML5 en mi VPS. La conversión se realiza mediante ffmpeg en segundo plano y los contenidos se envían a block.txt .
Habiendo examinado las siguientes publicaciones:
¿Puede ffmpeg mostrar una barra de progreso?
y
Barra de progreso de codificación de video ffmpeg
entre otros, no puedo encontrar un ejemplo de trabajo.
Necesito tomar el progreso codificado actualmente como un porcentaje.
La primera publicación que he vinculado anteriormente me da:
$log = @file_get_contents(''block.txt'');
preg_match("/Duration:([^,]+)/", $log, $matches);
list($hours,$minutes,$seconds,$mili) = split(":",$matches[1]);
$seconds = (($hours * 3600) + ($minutes * 60) + $seconds);
$seconds = round($seconds);
$page = join("",file("$txt"));
$kw = explode("time=", $page);
$last = array_pop($kw);
$values = explode('' '', $last);
$curTime = round($values[0]);
$percent_extracted = round((($curTime * 100)/($seconds)));
echo $percent_extracted;
La variable $ percent_extracted repite cero, y como las matemáticas no son mi punto fuerte, realmente no sé cómo progresar aquí.
Aquí hay una línea de la salida ffmpeg de block.txt (si es útil)
time = 00: 19: 25.16 bitrate = 823.0kbits / s frame = 27963 fps = 7 q = 0.0 size = 117085kB time = 00: 19: 25.33 bitrate = 823.1kbits / s frame = 27967 fps = 7 q = 0.0 size = 117085kB time = 00: 19: 25.49 bitrate = 823.0kbits / s frame = 27971 fps = 7 q = 0.0 size = 117126kB
Por favor, ayúdenme a dar salida a este porcentaje, una vez hecho puedo crear mi propia barra de progreso. Gracias.
ffmpeg ahora tiene una opción de progreso, que le da un resultado más fácil de analizar.
ffmpeg -progress block.txt -i ruta / a / entrada.mov -vcodec videocodec -acodec audiocodec ruta / a / salida.flv 2> & 1
Antes de comenzar a codificar puedes obtener el total de cuadros y mucha otra información con esto (esto es lo que harías con Bash. Soy un programador de Perl, así que no sé cómo obtendrías la información en tu Script PHP).
eval $ (ffprobe -of flat = s = _ -show_entries stream = height, width, nb_frames, duration, codec_name path / to / input.mov);
width = $ {streams_stream_0_width};
height = $ {streams_stream_0_height};
frames = $ {streams_stream_0_nb_frames};
videoduración = $ {streams_stream_0_duration};
audioduration = $ {streams_stream_1_duration};
codec = $ {streams_stream_0_codec_name};
echo $ width, $ height, $ frames, $ videoduration, $ audioduration, $ codec;
-of flate = s = _ dice que ponga cada nombre = valor en una línea separada. -show_entries le dice que muestre las entradas a partir de lo que sigue (stream para -show_streams, formato para -show_format, etc.) stream = ... dice que muestre esos elementos desde la salida -show_streams. Intente lo siguiente para ver lo que está disponible:
ffprobe -show_streams path / to / input.mov
El resultado del archivo de progreso se agrega aproximadamente una vez por segundo. El contenido, una vez finalizada la codificación, tiene el siguiente aspecto. En mi script, una vez por segundo estoy colocando el archivo en una matriz y atravesando la matriz en orden inverso, usando solo lo que está entre la primera [última antes de la reversión] dos líneas de "progreso" que encuentro, de modo que estoy usando el la información más reciente del final del archivo. Puede haber mejores maneras. Esto es de un mp4 sin audio por lo que solo hay una transmisión.
fotograma = 86
fps = 0.0
stream_0_0_q = 23.0
total_size = 103173
out_time_ms = 1120000
out_time = 00: 00: 01.120000
dup_frames = 0
drop_frames = 0
progreso = continuar
fotograma = 142
fps = 140.9
stream_0_0_q = 23.0
total_size = 415861
out_time_ms = 3360000
out_time = 00: 00: 03.360000
dup_frames = 0
drop_frames = 0
progreso = continuar
marco = 185
fps = 121.1
stream_0_0_q = 23.0
total_size = 1268982
out_time_ms = 5080000
out_time = 00: 00: 05.080000
dup_frames = 0
drop_frames = 0
progreso = continuar
marco = 225
fps = 110.9
stream_0_0_q = 23.0
total_size = 2366000
out_time_ms = 6680000
out_time = 00: 00: 06.680000
dup_frames = 0
drop_frames = 0
progreso = continuar
marco = 262
fps = 103.4
stream_0_0_q = 23.0
total_size = 3810570
out_time_ms = 8160000
out_time = 00: 00: 08.160000
dup_frames = 0
drop_frames = 0
progreso = continuar
fotograma = 299
fps = 84.9
stream_0_0_q = -1.0
total_size = 6710373
out_time_ms = 11880000
out_time = 00: 00: 11.880000
dup_frames = 0
drop_frames = 0
progreso = fin
si javascript actualiza su barra de progreso, javascript podría realizar el paso 2 "directamente":
[este ejemplo requiere dojo ]
dojo php: inicia la conversión y escribe el estado en un archivo de texto - sintaxis de ejemplo:
exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1");
Para la segunda parte, solo necesitamos javascript para leer el archivo. El siguiente ejemplo usa dojo.request para AJAX, pero también puedes usar jQuery o vainilla o lo que sea:
[2] js: toma el progreso del archivo:
var _progress = function(i){
i++;
// THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] :
var logfile = ''path/to/output.txt'';
/* (example requires dojo) */
request.post(logfile).then( function(content){
// AJAX success
var duration = 0, time = 0, progress = 0;
var result = {};
// get duration of source
var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
if( matches.length>0 ){
var rawDuration = matches[1];
// convert rawDuration from 00:00:00.00 to seconds.
var ar = rawDuration.split(":").reverse();
duration = parseFloat(ar[0]);
if (ar[1]) duration += parseInt(ar[1]) * 60;
if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
// get the time
matches = content.match(/time=(.*?) bitrate/g);
console.log( matches );
if( matches.length>0 ){
var rawTime = matches.pop();
// needed if there is more than one match
if (lang.isArray(rawTime)){
rawTime = rawTime.pop().replace(''time='','''').replace('' bitrate'','''');
} else {
rawTime = rawTime.replace(''time='','''').replace('' bitrate'','''');
}
// convert rawTime from 00:00:00.00 to seconds.
ar = rawTime.split(":").reverse();
time = parseFloat(ar[0]);
if (ar[1]) time += parseInt(ar[1]) * 60;
if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
//calculate the progress
progress = Math.round((time/duration) * 100);
}
result.status = 200;
result.duration = duration;
result.current = time;
result.progress = progress;
console.log(result);
/* UPDATE YOUR PROGRESSBAR HERE with above values ... */
if(progress==0 && i>20){
// TODO err - giving up after 8 sec. no progress - handle progress errors here
console.log(''{"status":-400, "error":"there is no progress while we tried to encode the video" }'');
return;
} else if(progress<100){
setTimeout(function(){ _progress(i); }, 400);
}
} else if( content.indexOf(''Permission denied'') > -1) {
// TODO - err - ffmpeg is not executable ...
console.log(''{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }'');
}
},
function(err){
// AJAX error
if(i<20){
// retry
setTimeout(function(){ _progress(0); }, 400);
} else {
console.log(''{"status":-400, "error":"there is no progress while we tried to encode the video" }'');
console.log( err );
}
return;
});
}
setTimeout(function(){ _progress(0); }, 800);