
私は、検索の結果をループし、いくつかの FLV ファイルの ffmpeg エンコードを実行する bash スクリプトを持っています。スクリプトの実行中、ffmpeg 出力が中断されたようで、以下のような奇妙なエラーが出力されています。何が起こっているのか全くわかりません。誰か正しい方向を指し示してくれませんか?
ループが実行中であるべきではないのに実行されていて、ffmpeg プロセスを中断しているかのようです。
具体的なエラーは次のとおりです:
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'
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'
スクリプトは以下のとおりです
#!/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
答え1
あなたの質問は実はバッシュ FAQ #89:標準入力の読み取りを</dev/null
防ぐために追加するだけです。ffmpeg
あなたのスクリプトには多くの潜在的なエラーが含まれているため、私は勝手に修正させて頂きました。重要な点をいくつか挙げます。
ファイル名は扱いが難しい。なぜなら、ほとんどのファイルシステムでは、普通の人がゴミと見なすあらゆる種類の印刷不可能な文字をファイル名に含めることができるからだ。「ファイル名には「通常の」文字だけが含まれている」といった単純な仮定をすると、脆弱なシェルスクリプトになりがちである。現れる「通常の」ファイル名で処理し、スクリプトの想定に従わない特に厄介なファイル名に遭遇した日に処理を中断する。一方、ファイル名を正しく処理するのは非常に面倒なため、奇妙なファイル名に遭遇する可能性がほぼゼロであると予想される場合 (つまり、スクリプトを自分のファイルにのみ使用し、自分のファイルに「単純な」名前を付ける場合)、労力に見合わないと感じるかもしれません。ファイル名をまったく解析しないことで、この決定を完全に回避できる場合があります。幸いなことに、これは
find(1)
の-exec
オプションで可能です。{}
に引数を入力する-exec
だけで、出力の解析について心配する必要はありませんfind
。または他の外部プロセスを使用して、
sed
拡張子やプレフィックスの削除などの単純な文字列操作を実行するのは非効率的です。代わりに、シェルの一部であるパラメータ拡張を使用します (外部プロセスがないため、処理が高速になります)。この件に関する役立つ記事を以下に示します。- バッシュ FAQ 73: パラメータ拡張
- バッシュ FAQ 100: 文字列操作
を使用してください
$( )
。今後は使用しないでください``
。 バッシュ FAQ 82。大文字の変数名の使用は避けてください。その名前空間は通常、特別な目的 ( など) のためにシェルによって予約されている
PATH
ため、独自の変数に使用するのはお勧めできません。
さて、これ以上前置きはこれくらいにして、整理されたスクリプトをご紹介します。
#!/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
' _ {} +
注:元のバージョンでは 固有の機能はsh
使用されていないか必要がなかったため、POSIX を使用しました。bash
答え2
私は見つけたソリューションbash スクリプトは、ffmpeg
プロセスに干渉する入力 (つまり「c」キー) を生成するようです。
< /dev/null
次のようにコマンドラインに追加しますffmpeg
。
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
問題を修正します。
答え3
の代替ソリューションとしてffmpeg [...] < /dev/null
、以下を使用できます。
ffmpeg -nostdin [...]
詳細はffmpeg ドキュメント:
明示的に相互作用を無効にするには、-nostdin を指定する必要があります。
たとえば、ffmpeg がバックグラウンド プロセス グループにある場合、標準入力での対話を無効にすると便利です。ffmpeg ... < /dev/null でもほぼ同じ結果を得ることができますが、シェルが必要です。
答え4
ループではwhile
、同様の問題に直面しました。ループを使用できます。ループfor
ではfor
、コマンドを使用してオーディオのリストを取得し、ループ内で実行することを回避できますfind
。
ワイルドカード文字を使用するとエラーが発生する状況があったため、ディレクトリ内のオーディオのリストを取得するためにfind
と を使用しました。sed
"argument list too long"
ここで find だけを実行すると、ファイルの絶対パスが提供され、 がffmpeg
失敗する原因となるため、 を使用して絶対パスを削除しましたsed
。
次のようなコマンドを使用できます(何度も使用しましたが、完璧に動作しています)
for f1 in `find . -maxdepth 1 -name "*.mkv" | sed 's/^\.\///g'`; do ffmpeg -i "$f1" -q:a 0 -map a ../wav/"${f1%.*}.wav"; done