Errores extraños al usar ffmpeg en un bucle

Errores extraños al usar ffmpeg en un bucle

Tengo un script bash que recorre los resultados de una búsqueda y realiza una codificación ffmpeg de algunos archivos FLV. Mientras se ejecuta el script, la salida de ffmpeg parece estar interrumpida y genera algunos errores de aspecto extraño como el que se muestra a continuación. No tengo idea de lo que está pasando aquí. ¿Alguien puede indicarme la dirección correcta?

Es como si el bucle todavía estuviera ejecutándose cuando no debería e interrumpiendo el proceso ffmpeg.

El error específico es:

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'

Algunos detalles más de la salida de 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'

El guión es el siguiente.

#!/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

Respuesta1

Tu pregunta es en realidadPreguntas frecuentes sobre Bash n.º 89: simplemente agregue </dev/nullpara evitar ffmpegleer su entrada estándar.


Me tomé la libertad de arreglar su script porque contiene muchos errores potenciales. Algunos de los puntos importantes:

  • Los nombres de archivos son difíciles de manejar, porque la mayoría de los sistemas de archivos les permiten contener todo tipo de caracteres no imprimibles que la gente normal vería como basura. Hacer suposiciones simplificadoras como "los nombres de archivos contienen sólo caracteres 'normales'" tiende a generar scripts de shell frágiles queaparecertrabajar con nombres de archivos "normales" y luego romper el día en que se encuentran con un nombre de archivo particularmente desagradable que no sigue las suposiciones del script. Por otro lado, manejar correctamente los nombres de los archivos puede ser una molestia tal que puede que no valga la pena el esfuerzo si se espera que la posibilidad de encontrar un nombre de archivo extraño sea cercana a cero (es decir, solo usa el script en sus propios archivos y usted le da a sus propios archivos nombres "simples"). A veces es posible evitar esta decisión por completo si no analizamos los nombres de los archivos en absoluto. Afortunadamente, eso es posible con la opción find(1)'s -exec. Simplemente ingrese {}el argumento to -execy no tendrá que preocuparse por analizar findel resultado.

  • El uso sedde otros procesos externos para realizar operaciones de cadenas simples, como eliminar extensiones y prefijos, es ineficiente. En su lugar, utilice expansiones de parámetros que formen parte del shell (ningún proceso externo significa que será más rápido). A continuación se enumeran algunos artículos útiles sobre el tema:

  • Usar $( )y no usar ``más: Preguntas frecuentes sobre Bash 82.

  • Evite el uso de nombres de variables en MAYÚSCULAS. Ese espacio de nombres generalmente lo reserva el shell para propósitos especiales (como PATH), por lo que usarlo para sus propias variables es una mala idea.

Y ahora, sin más preámbulos, aquí tienes un script limpio:

#!/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: Utilicé POSIX shporque no utilizaste ni necesitabas ninguna bashcaracterística específica en tu original.

Respuesta2

He encontradola solución. El script bash parece producir una entrada (es decir, la tecla 'c') que interfiere con el ffmpegproceso.

Agregando < /dev/nulla la ffmpeglínea de comando, así:

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

soluciona el problema.

Respuesta3

Como solución alternativa a ffmpeg [...] < /dev/null, puede utilizar:

ffmpeg -nostdin [...]

Detalles de ladocumentación ffmpeg:

Para deshabilitar explícitamente la interacción, debe especificar -nostdin.

Deshabilitar la interacción en la entrada estándar es útil, por ejemplo, si ffmpeg está en el grupo de procesos en segundo plano. Se puede lograr aproximadamente el mismo resultado con ffmpeg ... < /dev/null pero requiere un shell.

Respuesta4

En el whilecircuito, me he enfrentado a problemas similares. Puedes usar forloop, y en forloop, puedes evitar tomar la lista de audios y ejecutarla en loop usando el findcomando.

He usado findy sedpara tomar la lista de audios en mi directorio porque he visto situaciones en las que el uso de caracteres comodín genera "argument list too long"un error.

Ahora, si simplemente hacemos la búsqueda, nos dará la ruta absoluta de los archivos, lo que provocará que ffmpegfalle, por lo que hemos eliminado la ruta absoluta usando sed.

Puedes usar un comando como este (lo he usado muchas veces y funciona perfectamente)

for f1 in `find . -maxdepth 1 -name "*.mkv" | sed 's/^\.\///g'`; do ffmpeg -i "$f1" -q:a 0 -map a ../wav/"${f1%.*}.wav"; done

información relacionada