
Eu tenho um script bash percorrendo os resultados de uma localização e executando uma codificação ffmpeg de alguns arquivos FLV. Enquanto o script está sendo executado, a saída do ffmpeg parece ser interrompida e está gerando alguns erros de aparência estranha, como o mostrado abaixo. Não tenho ideia do que está acontecendo aqui. Alguém pode me apontar na direção certa?
É como se o loop ainda estivesse em execução quando não deveria e interrompesse o processo ffmpeg.
O erro específico é:
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'
Mais alguns detalhes da saída do 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'
O roteiro é o seguinte
#!/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
Responder1
Sua pergunta é na verdadePerguntas frequentes sobre o Bash nº 89: basta adicionar </dev/null
para evitar ffmpeg
a leitura de sua entrada padrão.
Tomei a liberdade de corrigir seu script porque ele contém muitos erros potenciais. Alguns dos pontos importantes:
Nomes de arquivos são difíceis de manusear, porque a maioria dos sistemas de arquivos permite que eles contenham todos os tipos de caracteres não imprimíveis que pessoas normais veriam como lixo. Fazer suposições simplificadas como "nomes de arquivos contêm apenas caracteres 'normais'" tende a resultar em scripts de shell frágeis queaparecerpara trabalhar em nomes de arquivos "normais" e, em seguida, quebrar o dia em que eles se deparam com um nome de arquivo particularmente desagradável que não segue as suposições do script. Por outro lado, lidar corretamente com nomes de arquivos pode ser tão incômodo que você pode achar que não vale a pena o esforço se a chance de encontrar um nome de arquivo estranho for próxima de zero (ou seja, você só usa o script em seus próprios arquivos e você dá nomes "simples" aos seus próprios arquivos). Às vezes é possível evitar totalmente essa decisão simplesmente não analisando os nomes dos arquivos. Felizmente, isso é possível com a opção
find(1)
de-exec
. Basta inserir{}
o argumento to-exec
e você não precisa se preocupar em analisarfind
a saída.Usar
sed
ou outros processos externos para realizar operações simples de string, como remover extensões e prefixos, é ineficiente. Em vez disso, use expansões de parâmetros que fazem parte do shell (nenhum processo externo significa que será mais rápido). Alguns artigos úteis sobre o assunto estão listados abaixo:- Perguntas frequentes sobre bash 73: Expansões de parâmetros
- Bash Perguntas frequentes 100: Manipulações de strings
Use
$( )
e não use``
mais: Perguntas frequentes sobre bash 82.Evite usar nomes de variáveis em MAIÚSCULAS. Esse namespace geralmente é reservado pelo shell para fins especiais (como
PATH
), portanto, usá-lo para suas próprias variáveis é uma má ideia.
E agora, sem mais delongas, aqui está um script limpo para você:
#!/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: usei POSIX sh
porque você não usou nem precisou de nenhum bash
recurso específico em seu original.
Responder2
encontreia solução. O script bash parece produzir uma entrada (ou seja, a tecla 'c') que interfere no ffmpeg
processo.
Adicionando < /dev/null
à ffmpeg
linha de comando, assim:
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
corrige o problema.
Responder3
Como solução alternativa para ffmpeg [...] < /dev/null
, você pode usar:
ffmpeg -nostdin [...]
Detalhes dodocumentação do ffmpeg:
Para desativar explicitamente a interação, você precisa especificar -nostdin.
Desabilitar a interação na entrada padrão é útil, por exemplo, se o ffmpeg estiver no grupo de processos em segundo plano. Aproximadamente o mesmo resultado pode ser alcançado com ffmpeg ... < /dev/null mas requer um shell.
Responder4
No while
circuito, enfrentei problemas semelhantes. Você pode usar for
loop, e em for
loop, você pode evitar pegar a lista de áudios e executá-la no loop usando o find
comando.
Eu usei find
e sed
para pegar a lista de áudios em meu diretório porque vi situações em que o uso de caracteres curinga gerava "argument list too long"
erros.
Agora, se apenas fizermos a localização, ele fornecerá o caminho absoluto dos arquivos que causarão ffmpeg
falha, então removemos o caminho absoluto usando sed
.
Você pode usar um comando como este (já usei muitas vezes e está funcionando perfeitamente)
for f1 in `find . -maxdepth 1 -name "*.mkv" | sed 's/^\.\///g'`; do ffmpeg -i "$f1" -q:a 0 -map a ../wav/"${f1%.*}.wav"; done