Strani errori quando si utilizza ffmpeg in un ciclo


23

Ho uno script bash che scorre tra i risultati di una ricerca ed eseguendo una codifica ffmpeg di alcuni file FLV. Mentre lo script sta eseguendo l'output di ffmpeg sembra essere interrotto e sta producendo alcuni strani errori dall'aspetto come quello qui sotto. Non ho idea di cosa stia succedendo qui. Qualcuno può indicarmi la giusta direzione?

È come se il ciclo fosse ancora in esecuzione quando non dovrebbe essere e interrompendo il processo ffmpeg.

L'errore specifico è:

frame=   68 fps= 67 q=28.0 00000000000000000000000000001000size=      22kB time=00:00:00.50 bitrate= 363.2kbits/s dup=1 drop=0    
Enter command: <target> <time> <command>[ <argument>]
Parse error, at least 3 arguments were expected, only 1 given in string 'om/pt_br/nx/R3T4N2_HD3D_demoCheckedOut.flv'

Alcuni ulteriori dettagli dall'output di ffmpeg:

[buffer @ 0xa30e1e0] w:800 h:600 pixfmt:yuv420p tb:1/1000000 sar:0/1 sws_param:flags=2
[libx264 @ 0xa333240] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.1 Cache64
[libx264 @ 0xa333240] profile High, level 3.1
[libx264 @ 0xa333240] 264 - core 122 r2184 5c85e0a - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x3:0x113 me=umh subme=8 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=2 b_bias=0 direct=3 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=50 rc=cbr mbtree=1 bitrate=500 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 vbv_maxrate=500 vbv_bufsize=1000 nal_hrd=none ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to './mp4s/pt_br/teamcenter/tc8_interactive/videos/8_SRM_EN.mp4':
  Metadata:
    audiodelay      : 0
    canSeekToEnd    : true
    encoder         : Lavf54.3.100
    Stream #0:0: Video: h264 (![0][0][0] / 0x0021), yuv420p, 800x600, q=-1--1, 500 kb/s, 30k tbn, 29.97 tbc
    Stream #0:1: Audio: aac (@[0][0][0] / 0x0040), 44100 Hz, mono, s16, 128 kb/s
Stream mapping:
  Stream #0:1 -> #0:0 (vp6f -> libx264)
  Stream #0:0 -> #0:1 (mp3 -> libfaac)
Press [q] to stop, [?] for help
error parsing debug value0 00000000000000000000000000000000size=      13kB time=00:00:00.-3 bitrate=-3165.5kbits/s dup=1 drop=0    
debug=0
frame=   68 fps= 67 q=28.0 00000000000000000000000000001000size=      22kB time=00:00:00.50 bitrate= 363.2kbits/s dup=1 drop=0    
Enter command: <target> <time> <command>[ <argument>]
Parse error, at least 3 arguments were expected, only 1 given in string 'om/pt_br/nx/R3T4N2_HD3D_demoCheckedOut.flv'

Lo script è il seguente

#!/bin/bash
LOGFILE=encodemp4ize.log
echo '' > $LOGFILE
STARTTIME=date
echo "Started at `$STARTTIME`" >> $LOGFILE
rsync -avz flvs/ mp4s/ --exclude '*.flv'
#find flvs/ -name "*.flv" > flv-files
# The loop
find flvs/ -name "*.flv" | while read f
do
FILENAME=`echo $f | sed 's#flvs/##'`
MP4FILENAME=`echo $FILENAME | sed 's#.flv#.mp4#'`
ffmpeg -i "$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME"
echo "$f MP4 done" >> $LOGFILE
done

Non sono uno sceneggiatore, ma un ovvio suggerimento: chiedi alla tua sceneggiatura di stampare le righe che sta eseguendo. Potrebbero non essere quello che pensi che siano.
Faheem Mitha,

Come problema secondario: mp4filename=$(basename "$f" mp4)potrebbe essere utile (vedi man basenamee man dirnameper maggiori informazioni)
Peter.O

Dire bash -x myscriptdi ottenere una traccia riga per riga dell'esecuzione dello script, con tutte le variabili espanse. Oh, e per inciso, hai reinventato la basenameruota sulla FILENAME=linea. :)
Warren Young,

1
Ho trovato la soluzione Lo script bash sembra l'input del prodotto (ovvero il tasto 'c') che interferisce con il processo ffmpeg. Piping "</ dev / null" in ffmpeg in questo modo: ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset slow -b: v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME" </ dev / null Risolve il problema. via [ linuxquestions.org/questions/programming-9/… [1]: linuxquestions.org/questions/programming-9/…
Mark Williams

Risposte:


56

La tua domanda è in realtà Bash FAQ # 89 : basta aggiungere </dev/nullper impedire la ffmpeglettura del suo input standard.


Mi sono preso la libertà di sistemare la tua sceneggiatura perché contiene molti potenziali errori. Alcuni dei punti importanti:

  • I nomi dei file sono difficili da gestire, poiché la maggior parte dei filesystem consente loro di contenere tutti i tipi di caratteri non stampabili che le persone normali vedrebbero come immondizia. Fare ipotesi di semplificazione come "i nomi dei file contengono solo caratteri" normali "tende a produrre fragili script di shell che appaionoper lavorare su nomi di file "normali" e poi interrompere il giorno in cui si imbattono in un nome di file particolarmente brutto che non segue i presupposti dello script. D'altra parte, gestire correttamente i nomi dei file può essere un tale fastidio che potresti non valerne la pena se la probabilità di incontrare un nome di file strano dovrebbe essere vicino allo zero (cioè usi lo script solo sui tuoi file e dai ai tuoi file nomi "semplici"). A volte è possibile evitare del tutto questa decisione non analizzando affatto i nomi dei file. Fortunatamente, ciò è possibile con l find(1)' -execopzione. Basta inserire {}l'argomento -exece non devi preoccuparti di analizzare l' findoutput.

  • L'uso sedo altri processi esterni per eseguire semplici operazioni su stringa come l'eliminazione di estensioni e prefissi è inefficiente. Invece, usa le espansioni dei parametri che fanno parte della shell (nessun processo esterno significa che sarà più veloce). Alcuni articoli utili sull'argomento sono elencati di seguito:

  • Usa $( )e non usare ``più: FAQ Bash 82 .

  • Evitare di utilizzare i nomi delle variabili MAIUSCOLI. Quello spazio dei nomi è generalmente riservato dalla shell per scopi speciali (come PATH), quindi usarlo per le proprie variabili è una cattiva idea.

E ora, senza ulteriori indugi, ecco uno script pulito per te:

#!/bin/sh

logfile=encodemp4ize.log
echo "Started at $(date)." > "$logfile"
rsync -avz --exclude '*.flv' flvs/ mp4s/

find flvs/ -type f -name '*.flv' -exec sh -c '
for flvsfile; do
    file=${flvsfile#flvs/}
    < /dev/null ffmpeg -i "$flvsfile" -vcodec libx264 -vprofile high \
        -preset slow -b:v 500k -maxrate 500k -bufsize 1000k \
        -threads 0 -acodec libfaac -ab 128k \
        "mp4s/${file%flv}"mp4
    printf %s\\n "$flvsfile MP4 done." >> "$logfile"
done
' _ {} +

Nota: ho usato POSIX shperché non hai utilizzato o non hai bisogno di bashfunzionalità specifiche per l'originale.


3
È una risposta brillante! Grazie per lo sforzo di scrivere la sceneggiatura corretta. Mi chiedo solo che c'è una simile alla guida Wiki di Greg a zsh? Grazie!
Art

1
@Art Siamo spiacenti, non ne so molto zsh. Forse alcune delle persone zsh sul sito lo saprebbero.
jw013,

Il problema è che ho bisogno di verificare se ffmpeg sta producendo un errore per in seguito giù lo script per decidere se cancellare o meno la versione precedente del file convertito. Sto convertendo mkv in mp4 per un Plex Media Server. Ho una balbuzie con file mkv di grandi dimensioni, quindi ho deciso di convertire tutti i mkv in mp4. Un altro problema è che devo verificare l'errore di conversione dello stream dei sottotitoli per i formati basati su immagini, nel qual caso utilizzo un altro processo per estrarre i sottotitoli. Quindi, come posso eseguire ffmpeg, ottenere il suo output e non incorrere in questo problema?
dacabdi,

15

Ho trovato la soluzione . Lo script bash sembra produrre input (vale a dire il tasto 'c') che interferisce con il ffmpegprocesso.

Aggiungendo < /dev/nullalla ffmpegriga di comando, in questo modo:

ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME" < /dev/null

risolve il problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.