Erreurs étranges lors de l'utilisation de ffmpeg dans une boucle

23

J'ai un script bash parcourant les résultats d'une recherche et effectuant un encodage ffmpeg de certains fichiers FLV. Pendant que le script s'exécute, la sortie ffmpeg semble être interrompue et génère des erreurs étranges comme celle ci-dessous. Je n'ai aucune idée de ce qui se passe ici. Est-ce que quelqu'un peut-il me montrer la bonne direction?

C'est comme si la boucle était toujours en cours d'exécution alors qu'elle ne devrait pas l'être et interrompant le processus ffmpeg.

L'erreur spécifique est:

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'

Quelques détails supplémentaires sur la sortie 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'

Le script est le suivant

#!/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
la source
Je ne suis pas vraiment un scripteur, mais une suggestion évidente - demandez à votre script d'imprimer les lignes qu'il exécute. Ils ne sont peut-être pas ce que vous pensez qu'ils sont.
Faheem Mitha
Comme problème secondaire: mp4filename=$(basename "$f" mp4)pourrait être utile (voir man basenameet man dirnamepour plus d'informations)
Peter.O
Dites bash -x myscriptpour obtenir une trace ligne par ligne de l'exécution du script, avec toutes les variables développées. Oh, et d'ailleurs, vous avez réinventé la basenameroue sur la FILENAME=ligne. :)
Warren Young
1
J'ai trouvé la solution. Le script bash semble produire des entrées (à savoir la touche «c») qui interfèrent avec le processus ffmpeg. Piping "</ dev / null" dans ffmpeg comme ceci: 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 Résout le problème. via [ linuxquestions.org/questions/programming-9/… [1]: linuxquestions.org/questions/programming-9/…
Mark Williams

Réponses:

56

Votre question est en fait Bash FAQ # 89 : ajoutez simplement </dev/nullpour empêcher ffmpegde lire son entrée standard.


J'ai pris la liberté de réparer votre script pour vous car il contient beaucoup d'erreurs potentielles. Quelques points importants:

  • Les noms de fichiers sont difficiles à gérer, car la plupart des systèmes de fichiers leur permettent de contenir toutes sortes de caractères non imprimables que les gens normaux considéreraient comme des ordures. Faire des hypothèses simplificatrices comme «les noms de fichiers ne contiennent que des caractères« normaux »» tend à produire des scripts shell fragiles qui apparaissentpour travailler sur des noms de fichiers "normaux", puis casser le jour où ils tombent sur un nom de fichier particulièrement méchant qui ne suit pas les hypothèses du script. D'un autre côté, une gestion correcte des noms de fichiers peut être si gênante que vous pouvez trouver que cela ne vaut pas la peine si la chance de rencontrer un nom de fichier étrange est proche de zéro (c'est-à-dire que vous n'utilisez le script que sur vos propres fichiers et vous donnez à vos propres fichiers des noms "simples"). Il est parfois possible d'éviter complètement cette décision en n'analysant pas du tout les noms de fichiers. Heureusement, c'est possible avec find(1)l' -execoption de. Mettez simplement {}l'argument dans -execet vous n'avez pas à vous soucier de l'analyse de la findsortie.

  • L'utilisation de sedou d'autres processus externes pour effectuer des opérations de chaîne simples comme supprimer les extensions et les préfixes est inefficace. Utilisez plutôt des extensions de paramètres qui font partie du shell (aucun processus externe ne signifie qu'il sera plus rapide). Quelques articles utiles sur le sujet sont listés ci-dessous:

  • Utilisez $( )et n'utilisez ``plus: Bash FAQ 82 .

  • Évitez d'utiliser des noms de variable UPPERCASE. Cet espace de noms est généralement réservé par le shell à des fins spéciales (comme PATH), donc l'utiliser pour vos propres variables est une mauvaise idée.

Et maintenant, sans plus tarder, voici un script nettoyé pour vous:

#!/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
' _ {} +

Remarque: J'ai utilisé POSIX shparce que vous n'avez pas utilisé ou n'avez pas besoin de bashfonctionnalités spécifiques à votre original.

jw013
la source
3
C'est une brillante réponse! Merci pour l'effort de rédaction du script corrigé. Je me demande simplement s'il existe un guide similaire à Greg's Wiki pour zsh? Merci!
Art
1
@Art Désolé, je ne sais pas grand-chose zsh. Peut-être que certaines des personnes zsh sur le site le sauraient.
jw013
Le problème est que je dois vérifier si ffmpeg produit une erreur pour plus tard dans le script décider s'il faut effacer ou non la version précédente du fichier converti. Je convertis mkv en mp4 pour un serveur multimédia Plex. J'ai bégayé avec de gros fichiers mkv, j'ai donc décidé de convertir tous les mkv en mp4. Un autre problème est que je dois vérifier l'échec de la conversion du flux de sous-titres pour les formats basés sur l'image, auquel cas j'utilise un autre processus pour extraire les sous-marins. Alors, comment puis-je exécuter ffmpeg, obtenir sa sortie et ne pas rencontrer ce problème?
dacabdi
15

J'ai trouvé la solution . Le script bash semble produire une entrée (à savoir la touche «c») qui interfère avec le ffmpegprocessus.

Ajout < /dev/nullà la ffmpegligne de commande, comme ceci:

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

résout le problème.

Mark Williams
la source