
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/null
para evitar ffmpeg
leer 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-exec
y no tendrá que preocuparse por analizarfind
el resultado.El uso
sed
de 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:- Preguntas frecuentes sobre Bash 73: Ampliaciones de parámetros
- Preguntas frecuentes 100 sobre Bash: manipulaciones de cuerdas
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 sh
porque no utilizaste ni necesitabas ninguna bash
caracterí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 ffmpeg
proceso.
Agregando < /dev/null
a la ffmpeg
lí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 while
circuito, me he enfrentado a problemas similares. Puedes usar for
loop, y en for
loop, puedes evitar tomar la lista de audios y ejecutarla en loop usando el find
comando.
He usado find
y sed
para 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 ffmpeg
falle, 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