Seltsame Fehler bei der Verwendung von ffmpeg in einer Schleife

Seltsame Fehler bei der Verwendung von ffmpeg in einer Schleife

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 ffmpegdas 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 -execOption möglich. Geben Sie einfach {}das Argument to ein -execund Sie müssen sich keine Gedanken über die Analyse findder Ausgabe machen.

  • Die Verwendung von sedoder 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:

  • 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 shkeine -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 ffmpegVorgang stören.

Hinzufügen < /dev/nullzur ffmpegBefehlszeile 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/nullkö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 whileSchleife hatte ich ähnliche Probleme. Sie können foreine Schleife verwenden und in forder Schleife können Sie vermeiden, die Liste der Audios zu nehmen und sie mit dem findBefehl in der Schleife auszuführen.

Ich habe findund 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 ffmpegFehlschlagen 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

verwandte Informationen