Erros estranhos ao usar o ffmpeg em um loop

Erros estranhos ao usar o ffmpeg em um loop

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/nullpara evitar ffmpega 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 -exece você não precisa se preocupar em analisar finda saída.

  • Usar sedou 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:

  • 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 shporque você não usou nem precisou de nenhum bashrecurso específico em seu original.

Responder2

encontreia solução. O script bash parece produzir uma entrada (ou seja, a tecla 'c') que interfere no ffmpegprocesso.

Adicionando < /dev/nullà ffmpeglinha 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 whilecircuito, enfrentei problemas semelhantes. Você pode usar forloop, e em forloop, você pode evitar pegar a lista de áudios e executá-la no loop usando o findcomando.

Eu usei finde sedpara 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 ffmpegfalha, 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

informação relacionada