Salve, ho bisogno di estrarre i frame dai video usando ffmpeg .. C'è un modo più veloce per farlo:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Salve, ho bisogno di estrarre i frame dai video usando ffmpeg .. C'è un modo più veloce per farlo:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Risposte:
Se la fase di codifica JPEG è troppo impegnativa per le prestazioni, è sempre possibile memorizzare i fotogrammi non compressi come immagini BMP:
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
Ciò ha anche il vantaggio di non incorrere in una maggiore perdita di qualità attraverso la quantizzazione mediante la transcodifica in JPEG. (PNG è anche senza perdita di dati, ma tende a richiedere molto più tempo del JPEG per la codifica.)
ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png
, vero? (ti mancava il -i
)
Mi sono imbattuto in questa domanda, quindi ecco un rapido confronto. Confronta questi due diversi modi per estrarre un fotogramma al minuto da un video di 38 m 07 s:
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1m36.029s
Questo richiede molto tempo perché ffmpeg analizza l'intero file video per ottenere i fotogrammi desiderati.
time for i in {0..39} ; do ffmpeg -accurate_seek -ss `echo $i*60.0 | bc` -i input.mp4 -frames:v 1 period_down_$i.bmp ; done
0m4.689s
Questo è circa 20 volte più veloce. Usiamo la ricerca veloce per andare all'indice temporale desiderato ed estrarre un frame, quindi chiamare ffmpeg più volte per ogni indice temporale. Nota che -accurate_seek
è l'impostazione predefinita
e assicurati di aggiungere -ss
prima -i
dell'opzione video di input .
Nota che è meglio usare -filter:v -fps=fps=...
invece di -r
perché quest'ultimo potrebbe essere impreciso. Sebbene il ticket sia contrassegnato come risolto , ho comunque riscontrato alcuni problemi, quindi è meglio giocare sul sicuro.
bc
non è un pacchetto nativo di Ubuntu, invece si può usare bash: let "i = $i * 60"
. A proposito - ottima idea
-ss
prima -i
. In caso contrario, l'intero video verrà decodificato e i fotogrammi non richiesti verranno scartati
ffmpeg
per core del tuo host - che (per bmp) produce miglioramenti quasi lineari nella velocità (fino a quando non incontri qualche altro collo di bottiglia, come il disco).
Se sai esattamente quali frame estrarre, ad esempio 1, 200, 400, 600, 800, 1000, prova a utilizzare:
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
-vsync vfr -q:v 2
Lo sto usando con una pipe al montaggio di Imagemagick per ottenere un'anteprima di 10 fotogrammi da qualsiasi video. Ovviamente i numeri di telaio che dovrai capire usandoffprobe
ffmpeg -i myVideo.mov -vf \
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)',scale=320:-1 \
-vsync vfr -q:v 2 -f image2pipe -vcodec ppm - \
| montage -tile x1 -geometry "1x1+0+0<" -quality 100 -frame 1 - output.png
.
Piccola spiegazione:
+
stanno per OR e *
per AND\,
è semplicemente sfuggire al ,
personaggio-vsync vfr -q:v 2
non sembra funzionare ma non so perché - qualcuno?L'ho provato. 3600 frame in 32 secondi. il tuo metodo è molto lento. Dovresti provare questo.
ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
ffmpeg -i "input URL" -vf fps=1/5 out%d.png
dove l'URL di input deve essere un collegamento https.
ffmpeg -i file.mpg -vf fps=1 %d.jpg
Nel mio caso ho bisogno di frame almeno ogni secondo. Ho usato l'approccio "cerca di" sopra, ma mi chiedevo se potevo parallelizzare l'attività. Ho usato i processi N con l'approccio FIFO qui: /unix/103920/parallelize-a-bash-for-loop/216475#216475
open_sem(){
mkfifo /tmp/pipe-$$
exec 3<>/tmp/pipe-$$
rm /tmp/pipe-$$
local i=$1
for((;i>0;i--)); do
printf %s 000 >&3
done
}
run_with_lock(){
local x
read -u 3 -n 3 x && ((0==x)) || exit $x
(
"$@"
printf '%.3d' $? >&3
)&
}
N=16
open_sem $N
time for i in {0..39} ; do run_with_lock ffmpeg -ss `echo $i` -i /tmp/input/GOPR1456.MP4 -frames:v 1 /tmp/output/period_down_$i.jpg & done
Essenzialmente ho biforcato il processo con & ma ho limitato il numero di thread simultanei a N.
Ciò ha migliorato l'approccio "cerca di" da 26 secondi a 16 secondi nel mio caso. L'unico problema è che il thread principale non esce in modo pulito al terminale poiché lo stdout viene inondato.
Questo ha funzionato per me
ffmpeg -i file.mp4 -vf fps=1 %d.jpg