在循環中使用 ffmpeg 時出現奇怪的錯誤

在循環中使用 ffmpeg 時出現奇怪的錯誤

我有一個 bash 腳本循環查找結果並對某些 FLV 檔案執行 ffmpeg 編碼。當腳本運行時,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

你的問題實際上是Bash 常見問題 #89:只需添加</dev/null以防止ffmpeg讀取其標準輸入。


我冒昧地為您修復了您的腳本,因為它包含許多潛在的錯誤。一些要點:

  • 檔案名稱處理起來很棘手,因為大多數檔案系統允許它們包含各種普通人視為垃圾的不可列印字元。做出諸如「檔案名稱僅包含『正常』字元」之類的簡化假設往往會導致脆弱的 shell 腳本,出現處理「正常」檔案名,然後打破它們遇到一個不遵循腳本假設的特別令人討厭的檔案名稱的日子。另一方面,正確處理檔案名稱可能會很麻煩,如果預計遇到奇怪檔案名稱的機會接近零(即您只在自己的檔案上使用腳本並且您為自己的檔案指定「簡單」名稱)。有時,可以透過根本不解析檔名來完全避免此決定。幸運的是,透過find(1)s選項可以做到這一點-exec。只需輸入{}參數即可-exec,您不必擔心解析find輸出。

  • 使用sed或其他外部程序執行簡單的字串操作(例如剝離擴展名和前綴)效率很低。相反,使用屬於 shell 一部分的參數擴展(沒有外部進程意味著它會更快)。下面列出了一些有關該主題的有用文章:

  • 使用$( ),不再使用``Bash 常見問題 82

  • 避免使用大寫變數名。這個命名空間通常由 shell 保留用於特殊目的(例如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
' _ {} +

注意:我使用 POSIX 是因為您在原始版本中sh沒有使用或不需要任何特定功能。bash

答案2

我發現了解決方案。 bash 腳本似乎會產生幹擾該過程的輸入(即“c”鍵)ffmpeg

新增< /dev/nullffmpeg命令列,如下所示:

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 可以實現大致相同的結果,但它需要 shell。

答案4

while循環中,我也遇到類似的問題。您可以使用for循環,並且在for循環中,您可以避免使用該命令來獲取音訊列表並在循環中運行它find

我使用了findsed來獲取目錄中的音訊列表,因為我見過使用通配符會引發"argument list too long"錯誤的情況。

現在,如果我們只進行查找,那麼它將給出文件的絕對路徑,這將導致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

相關內容