Merkwürdige Fehler bei der Verwendung von ffmpeg in einer Schleife

23

Ich habe ein Bash-Skript, das die Ergebnisse einer Suche durchläuft und eine ffmpeg-Codierung einiger FLV-Dateien durchführt. Während das Skript ausgeführt wird, scheint die ffmpeg-Ausgabe unterbrochen zu sein und gibt einige seltsam aussehende Fehler aus, wie den folgenden. Ich habe keine Ahnung, was hier los ist. Kann mich jemand in die richtige Richtung weisen?

Es ist, als ob die Schleife immer noch läuft, wenn es nicht sein sollte, und den ffmpeg-Prozess unterbricht.

Der spezifische Fehler ist:

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'

Einige weitere Details aus der ffmpeg-Ausgabe:

[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'

Das Skript sieht wie folgt aus

#!/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
quelle
Ich bin kein großer Schreiber, aber ein offensichtlicher Vorschlag: Lassen Sie Ihr Skript die Zeilen ausdrucken, die es ausführt. Sie können nicht sein, was Sie denken, dass sie sind.
Faheem Mitha
Als Nebenproblem: mp4filename=$(basename "$f" mp4)könnte nützlich sein (siehe man basenameund man dirnamefür weitere Informationen)
Peter.O
Nehmen wir bash -x myscriptan, Sie erhalten eine zeilenweise Verfolgung der Skriptausführung, wobei alle Variablen erweitert werden. Oh, und übrigens, Sie haben das basenameRad auf der FILENAME=Strecke neu erfunden . :)
Warren Young
1
Ich habe die Lösung gefunden. Das Bash-Skript scheint eine Produkteingabe (nämlich die Taste 'c') zu haben, die den ffmpeg-Prozess stört. Piping "</ dev / null" in ffmpeg wie folgt: ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset slow -b: v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128 KB "./mp4s/$MP4FILENAME" </ dev / null Behebt das Problem. via [ linuxquestions.org/questions/programming-9/… [1]: linuxquestions.org/questions/programming-9/…
Mark Williams

Antworten:

56

Ihre Frage ist eigentlich Bash FAQ # 89 : Fügen Sie einfach hinzu </dev/null, um zu verhindern, dass ffmpegdie Standardeingabe gelesen wird.


Ich habe mir erlaubt, Ihr Skript für Sie zu reparieren, da es viele potenzielle Fehler enthält. Einige wichtige Punkte:

  • Dateinamen sind schwierig zu handhaben, da die meisten Dateisysteme es ihnen erlauben, alle Arten von nicht druckbaren Zeichen zu enthalten, die normale Leute als Müll ansehen würden. Herstellung von vereinfachenden Annahmen wie „Dateinamen enthalten nur‚normale‘Zeichen“ neigt dazu , zerbrechlich Shell - Skripten zu führen, erscheinenUm an "normalen" Dateinamen zu arbeiten und dann den Tag zu unterbrechen, an dem sie auf einen besonders unangenehmen Dateinamen stoßen, der nicht den Annahmen des Skripts entspricht. Andererseits kann der richtige Umgang mit Dateinamen so störend sein, dass Sie den Aufwand möglicherweise nicht wert finden, wenn die Wahrscheinlichkeit, auf einen seltsamen Dateinamen zu stoßen, voraussichtlich nahe Null liegt (dh Sie verwenden das Skript nur für Ihre eigenen Dateien und Sie geben Ihren eigenen Dateien "einfache" Namen). Manchmal ist es möglich, diese Entscheidung ganz zu vermeiden, indem die Dateinamen überhaupt nicht analysiert werden. Glücklicherweise ist das mit find(1)der -execOption von möglich. Geben Sie einfach {}das Argument ein, -execund Sie müssen sich keine Gedanken über das Parsen der findAusgabe machen.

  • Das Verwenden sedoder anderer externer Prozesse, um einfache Zeichenfolgenoperationen wie das Entfernen von Erweiterungen und Präfixen auszuführen, ist ineffizient. Verwenden Sie stattdessen Parametererweiterungen, die Teil der Shell sind (kein externer Prozess bedeutet, dass sie schneller sind). Einige hilfreiche Artikel zu diesem Thema sind nachfolgend aufgeführt:

  • Verwenden $( )und nicht ``mehr verwenden: Bash FAQ 82 .

  • Vermeiden Sie die Verwendung von UPPERCASE-Variablennamen. Dieser Namespace wird in der Regel von der Shell für bestimmte Zwecke (z. B. PATH) reserviert. Daher ist es eine schlechte Idee, ihn für Ihre eigenen Variablen zu verwenden.

Und jetzt, ohne weitere Umstände, hier ein aufgeräumtes Skript für Sie:

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

Hinweis: Ich habe POSIX verwendet, shweil Sie bashin Ihrem Original keine spezifischen Funktionen verwendet haben oder benötigen .

jw013
quelle
3
Es ist eine brillante Antwort! Vielen Dank für die Mühe, das korrigierte Skript zu verfassen. Ich frage mich nur, ob es einen ähnlichen Wiki-Leitfaden wie Greg für zsh gibt. Vielen Dank!
Art
1
@Art Tut mir leid, ich weiß nicht viel darüber zsh. Vielleicht würden einige der zsh-Leute auf der Seite Bescheid wissen.
jw013
Das Problem ist, dass ich überprüfen muss, ob ffmpeg einen Fehler erzeugt, um später im Skript zu entscheiden, ob die vorherige Version der konvertierten Datei gelöscht werden soll oder nicht. Ich konvertiere mkv zu mp4 für einen Plex Media Server. Ich habe mit großen mkv-Dateien gestottert, also habe ich beschlossen, alle mkv in mp4 umzuwandeln. Ein weiteres Problem besteht darin, dass ich den Fehler bei der Konvertierung von Untertitelströmen für bildbasierte Formate überprüfen muss. In diesem Fall verwende ich einen anderen Prozess, um die Untertitel zu extrahieren. Wie führe ich ffmpeg aus, erhalte die Ausgabe und stoße nicht auf dieses Problem?
Dacabdi
15

Ich habe die Lösung gefunden . Das Bash-Skript scheint Eingaben zu erzeugen (namentlich die 'c'-Taste), die den ffmpegProzess stören .

So fügen Sie < /dev/nullder ffmpegBefehlszeile Folgendes hinzu :

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

behebt das Problem.

Mark Williams
quelle