Errores extraños al usar ffmpeg en un bucle

23

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

Es como si el ciclo todavía se estuviera ejecutando cuando no debería estar 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 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
Mark Williams
fuente
No soy un gran guionista, sino una sugerencia obvia: haga que su guión imprima las líneas que está ejecutando. Puede que no sean lo que crees que son.
Faheem Mitha
Como un problema secundario: mp4filename=$(basename "$f" mp4)podría ser útil (ver man basenamey man dirnamepara más información)
Peter.O
Decir bash -x myscriptpara obtener un seguimiento línea por línea de la ejecución del script, con todas las variables expandidas. Ah, y por cierto, has reinventado la basenamerueda en la FILENAME=línea. :)
Warren Young
1
He encontrado la solución. El script bash parece ser una entrada del producto (principalmente la tecla 'c') que interfiere con el proceso ffmpeg. Canalizando "</ dev / null" en ffmpeg de esta manera: 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. a través de [ linuxquestions.org/questions/programming-9/… [1]: linuxquestions.org/questions/programming-9/…
Mark Williams

Respuestas:

56

Su pregunta es en realidad Bash FAQ # 89 : solo agregue </dev/nullpara evitar ffmpegleer su entrada estándar.


Me he tomado la libertad de arreglar tu script porque contiene muchos errores potenciales. Algunos de los puntos importantes:

  • Los nombres de archivo son difíciles de manejar, porque la mayoría de los sistemas de archivos les permite contener todo tipo de caracteres no imprimibles que la gente normal vería como basura. Hacer suposiciones simplificadoras como "los nombres de archivo contienen solo caracteres 'normales'" tiende a generar scripts de shell frágiles que aparecenpara trabajar en nombres de archivo "normales" y luego romper el día en que se encuentran con un nombre de archivo particularmente desagradable que no sigue los supuestos del script. Por otro lado, manejar correctamente los nombres de los archivos puede ser tan molesto que es posible 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 le das a tus propios archivos nombres "simples"). A veces es posible evitar esta decisión por completo al no analizar los nombres de los archivos. Afortunadamente, eso es posible con find(1)la -execopción de. Simplemente ponga {}el argumento -execay no tendrá que preocuparse por analizar la findsalida.

  • Usar sedu otros procesos externos para realizar operaciones de cadena simples como quitar extensiones y prefijos es ineficiente. En su lugar, use expansiones de parámetros que son 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: Bash FAQ 82 .

  • Evite usar los nombres de las variables MAYÚSCULAS. Ese espacio de nombres generalmente está reservado por el shell para fines especiales (como PATH), por lo que usarlo para sus propias variables es una mala idea.

Y ahora, sin más preámbulos, aquí hay un script limpio para usted:

#!/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: Usé POSIX shporque no bashusaste o no necesitabas características específicas en tu original.

jw013
fuente
3
¡Es una respuesta brillante! Gracias por el esfuerzo redactado guión corregido. Me pregunto si hay una guía similar a la Wiki de Greg para zsh. ¡Gracias!
Arte
1
@Art Lo siento, no sé mucho al respecto zsh. Tal vez algunas de las personas zsh en el sitio lo sabrían.
jw013
El problema es que necesito verificar si ffmpeg está produciendo un error para luego borrar el script y decidir si borrar o no la versión anterior del archivo convertido. Estoy convirtiendo mkv a mp4 para un servidor Plex Media. Tartamudeo con grandes archivos mkv, así que decidí convertir todos los mkv a mp4. Otro problema es que necesito verificar la falla de conversión de flujo de subtítulos para formatos basados ​​en imágenes, en cuyo caso uso otro proceso para extraer los subs. Entonces, ¿cómo ejecuto ffmpeg, obtengo su salida y no me encuentro con este problema?
dacabdi
15

He encontrado la solución . El script bash parece producir una entrada (principalmente 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.

Mark Williams
fuente