Erros estranhos ao usar o ffmpeg em um loop

20

Eu tenho um script bash percorrendo os resultados de um find e executando uma codificação ffmpeg de alguns arquivos FLV. Enquanto o script está rodando, a saída ffmpeg parece estar interrompida e está produzindo alguns erros estranhos, 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 rodando quando não deveria estar e interrompendo o processo do 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 script é 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
    
por Mark Williams 12.04.2012 / 15:18

2 respostas

43

Sua pergunta é, na verdade, Bash FAQ # 89 : basta adicionar </dev/null para impedir que ffmpeg leia o padrão entrada.

Eu tomei a liberdade de consertar seu script porque ele contém muitos erros potenciais. Alguns dos pontos importantes:

  • Os nomes dos arquivos são difíceis de manipular, porque a maioria dos sistemas de arquivos permite que eles contenham todos os tipos de caracteres não imprimíveis que as pessoas normais considerariam lixo. Fazer suposições simplificadoras como "nomes de arquivos contêm apenas caracteres 'normais'" tende a resultar em scripts de shell frágeis que aparecem para trabalhar em nomes de arquivos "normais" e quebram o dia em que são executados em um nome de arquivo particularmente desagradável que não segue as suposições do roteiro. Por outro lado, lidar corretamente com nomes de arquivos pode ser um incômodo que você pode achar que não vale a pena se a chance de encontrar um nome de arquivo estranho é próxima de zero (ou seja, você só usa o script em seus próprios arquivos e você dá seus próprios arquivos "simples" nomes). Às vezes, é possível evitar completamente essa decisão, não analisando os nomes dos arquivos. Felizmente, isso é possível com a opção find(1) -exec . Basta colocar {} no argumento para -exec e você não precisa se preocupar com a análise de find output.

  • Usar o sed ou outros processos externos para fazer operações com cadeias de caracteres simples, 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:

  • Use $( ) e não use mais '' : FAQ da Bash 82 .

  • Evite usar nomes de variáveis UPPERCASE. Esse namespace é geralmente reservado pelo shell para propósitos especiais (como PATH ), então usá-lo para suas próprias variáveis é uma má idéia.

E agora, sem mais delongas, aqui está um roteiro 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
' _ {} +

Observação: usei POSIX sh porque você não usou ou precisou de nenhum recurso bash específico no original.

    
por 14.04.2012 / 04:47
11

Encontrei a solução . O script bash parece produzir entrada (ou seja, a chave 'c') que interfere no processo ffmpeg .

Adicionando < /dev/null à linha de comando ffmpeg , da seguinte forma:

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.

    
por 13.04.2012 / 11:12

Tags