barra di avanzamento ffmpeg – Percentuale di codifica in PHP

Ho scritto un integer sistema in PHP e bash sul server per convertire e trasmettere video in HTML5 sul mio VPS. La conversione viene eseguita da ffmpeg in background e il contenuto viene printingto in block.txt .

Dopo aver esaminato i seguenti messaggi:

Ffmpeg può mostrare una barra di avanzamento?

e

barra di avanzamento della codifica video ffmpeg

tra l'altro, non riesco a trovare un esempio funzionante.

Ho bisogno di afferrare il progresso attualmente codificato come percentuale.

Il primo post che ho linkato sopra fornisce:

$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 = arrays_pop($kw); $values = explode(' ', $last); $curTime = round($values[0]); $percent_extracted = round((($curTime * 100)/($seconds))); echo $percent_extracted; 

La variabile $ percent_extracted echi zero e, poiché la math non è il mio punto di forza, non so davvero come procedere qui.

Ecco una row dall'output ffmpeg da block.txt (se è utile)

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

Per favore aiutami a produrre questa percentuale, una volta fatto posso creare la mia barra di avanzamento. Grazie.

Ok, ho trovato quello di cui avevo bisogno – e spero che questo aiuti anche qualcun altro!

Innanzi tutto, si desidera esportre i dati ffmpeg in un file di text sul server.

 ffmpeg -i path/to/input.mov -vcodec videocodec -acodec audiocodec path/to/output.flv 1> block.txt 2>&1 

Quindi, l'output ffmpeg è block.txt. Ora in PHP, facciamolo!

 $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 = arrays_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 = arrays_pop($matches); //this is needed if there is more than one match if (is_arrays($rawTime)){$rawTime = arrays_pop($rawTime);} //rawTime is in 00:00:00.00 format. This converts it to seconds. $ar = arrays_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 . "%"; } 

Questo produce la percentuale di tempo rimasto.

Puoi avere questo come l'unica parte di text che viene rimandata ad una pagina, e da un'altra pagina puoi eseguire una richiesta AJAX usando jQuery per afferrare questa porzione di text e inviarla in un div, ad esempio, per aggiornare sulla tua pagina each 10 secondi. 🙂

ffmpeg ora ha un'opzione di avanzamento, che consente di analizzare più facilmente l'output.

ffmpeg -progress block.txt -i path / to / input.mov -vcodec videocodec -acodec audiocodec path / to / output.flv 2> & 1

Prima di iniziare la codifica puoi get i frame totali e molte altre informazioni con questo (questo è ciò che sarebbe fatto con bash. Sono un programmatore Perl quindi non so come faresti a get le informazioni nel tuo Script PHP).

eval $ (ffprobe -of flat = s = _ -show_entries stream = altezza, width, nb_frames, durata, nome_codice path / a / input.mov);
width = $ {} streams_stream_0_width;
height = $ {} streams_stream_0_height;
cornici = $ {} streams_stream_0_nb_frames;
videoduration = $ {} streams_stream_0_duration;
audioduration = $ {} streams_stream_1_duration;
codec = $ {} streams_stream_0_codec_name;
echo $ width, $ height, $ frames, $ videoduration, $ audioduration, $ codec;

-di flate = s = _ dice di mettere each nome = valore su una row separata. -show_entries dice di mostrare le voci da quanto segue (stream for -show_streams, format for -show_format, ecc.) stream = … dice di mostrare quegli elementi dall'output di -show_streams. Prova quanto segue per vedere cosa è disponibile:

ffprobe -show_streams path / to / input.mov

L'output del file di avanzamento viene aggiunto a circa una volta al secondo. Il contenuto, una volta terminata la codifica, ha il seguente aspetto. Nel mio script, una volta al secondo inserisco il file in un arrays, e attraversando l'arrays in ordine inverso, usando solo ciò che è tra il primo [ultimo prima dello storno] due linee "progresso" che trovo, così che sto usando il le informazioni più recenti dalla fine del file. Ci possono essere modi migliori. Questo è da un mp4 senza audio quindi c'è solo un stream.

frame = 86
fps = 0.0
stream_0_0_q = 23.0
TOTAL_SIZE = 103.173
out_time_ms = 1120000
out_time = 00: 00: 01,120000
dup_frames = 0
drop_frames = 0
il progresso = continua
frame = 142
fps = 140,9
stream_0_0_q = 23.0
TOTAL_SIZE = 415.861
out_time_ms = 3360000
out_time = 00: 00: 03,360000
dup_frames = 0
drop_frames = 0
il progresso = continua
frame = 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
il progresso = continua
frame = 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
il progresso = continua
frame = 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
il progresso = continua
frame = 299
fps = 84.9
stream_0_0_q = -1.0
TOTAL_SIZE = 6710373
out_time_ms = 11880000
out_time = 00: 00: 11,880 mila
dup_frames = 0
drop_frames = 0
progressi = fine

se javascript aggiorna la barra di avanzamento, javascript potrebbe eseguire il passaggio 2 "direttamente":

[questo esempio richiede il dojo ]


1 php: avvia la conversione e lo stato di scrittura in un file di text – syntax di esempio:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1"); 

Per la seconda parte abbiamo bisogno solo di javascript per leggere il file. Nell'esempio seguente viene utilizzato dojo.request per AJAX, ma è ansible utilizzare jQuery o vanilla o qualsiasi altra cosa:

[2] js: acquisisci il progresso dal file:

 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);