
Ich habe ein Bash-Skript, das die Ergebnisse einer Suche durchläuft und eine FFMPEG-Kodierung 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 wie den folgenden aus. Ich habe keine Ahnung, was hier vor sich geht. Kann mir jemand den richtigen Weg weisen?
Es ist, als ob die Schleife immer noch läuft, obwohl sie es nicht sollte, und den FFMPEG-Prozess unterbricht.
Der konkrete 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 lautet wie folgt
#!/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
Antwort1
Ihre Frage ist eigentlichBash-FAQ #89: einfach hinzufügen </dev/null
, um ffmpeg
das Lesen der Standardeingabe zu verhindern.
Ich habe mir die Freiheit genommen, Ihr Skript für Sie zu korrigieren, da es viele potenzielle Fehler enthält. Einige der wichtigsten Punkte:
Dateinamen sind schwierig zu handhaben, da die meisten Dateisysteme es ihnen erlauben, alle möglichen nicht druckbaren Zeichen zu enthalten, die normale Leute als Müll ansehen würden. Vereinfachende Annahmen wie „Dateinamen enthalten nur ‚normale‘ Zeichen“ führen tendenziell zu instabilen Shell-Skripten, dieerscheinenan „normalen“ Dateinamen zu arbeiten und dann an dem Tag abzubrechen, an dem sie auf einen besonders hässlichen Dateinamen stoßen, der nicht den Annahmen des Skripts entspricht. Andererseits kann die korrekte Handhabung von Dateinamen so lästig sein, dass Sie den Aufwand möglicherweise nicht für lohnenswert halten, wenn die Wahrscheinlichkeit, auf einen seltsamen Dateinamen zu stoßen, voraussichtlich gegen Null geht (d. h. Sie verwenden das Skript nur für Ihre eigenen Dateien und 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 dies mit
find(1)
der-exec
Option möglich. Geben Sie einfach{}
das Argument to ein-exec
und Sie müssen sich keine Gedanken über die Analysefind
der Ausgabe machen.Die Verwendung von
sed
oder anderen externen Prozessen zum Ausführen einfacher Zeichenfolgenoperationen wie dem Entfernen von Erweiterungen und Präfixen ist ineffizient. Verwenden Sie stattdessen Parametererweiterungen, die Teil der Shell sind (kein externer Prozess bedeutet, dass es schneller ist). Nachfolgend sind einige hilfreiche Artikel zu diesem Thema aufgeführt:- Bash-FAQ 73: Parametererweiterungen
- Bash FAQ 100: String-Manipulationen
Verwenden Sie
$( )
und verwenden Sie nicht``
mehr: Bash-FAQ 82.Vermeiden Sie die Verwendung von Variablennamen in GROSSBUCHSTABEN. Dieser Namespace ist im Allgemeinen von der Shell für spezielle Zwecke (wie
PATH
) reserviert. Daher ist es keine gute Idee, ihn für Ihre eigenen Variablen zu verwenden.
Und nun, ohne weitere Umschweife, hier ein bereinigtes 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, da Sie in Ihrem Original sh
keine -spezifischen Funktionen verwendet oder benötigt haben .bash
Antwort2
Ich habe gefundendie Lösung. Das Bash-Skript scheint Eingaben zu erzeugen (nämlich die Taste „c“), die den ffmpeg
Vorgang stören.
Hinzufügen < /dev/null
zur ffmpeg
Befehlszeile wie folgt:
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.
Antwort3
Als alternative Lösung zu ffmpeg [...] < /dev/null
können Sie Folgendes verwenden:
ffmpeg -nostdin [...]
Details aus derffmpeg-Dokumentation:
Um die Interaktion explizit zu deaktivieren, müssen Sie -nostdin angeben.
Das Deaktivieren der Interaktion mit der Standardeingabe ist beispielsweise nützlich, wenn sich ffmpeg in der Hintergrundprozessgruppe befindet. Mit ffmpeg ... < /dev/null lässt sich ungefähr das gleiche Ergebnis erzielen, allerdings ist dafür eine Shell erforderlich.
Antwort4
In der while
Schleife hatte ich ähnliche Probleme. Sie können for
eine Schleife verwenden und in for
der Schleife können Sie vermeiden, die Liste der Audios zu nehmen und sie mit dem find
Befehl in der Schleife auszuführen.
Ich habe find
und verwendet sed
, um die Liste der Audios in meinem Verzeichnis zu übernehmen, da ich Situationen gesehen habe, in denen die Verwendung von Platzhalterzeichen "argument list too long"
einen Fehler verursacht.
Wenn wir jetzt einfach die Suche ausführen, wird der absolute Pfad der Dateien zurückgegeben, was zum ffmpeg
Fehlschlagen führen würde. Daher haben wir den absoluten Pfad mithilfe von entfernt sed
.
Sie können einen Befehl wie diesen verwenden (habe ihn oft verwendet und er funktioniert perfekt)
for f1 in `find . -maxdepth 1 -name "*.mkv" | sed 's/^\.\///g'`; do ffmpeg -i "$f1" -q:a 0 -map a ../wav/"${f1%.*}.wav"; done