在循环中使用ffmpeg时出现奇怪的错误


23

我有一个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

我不是一个脚本编写者,而是一个明显的建议-让您的脚本打印出正在执行的行。它们可能不是您认为的那样。
Faheem Mitha 2012年

附带说明:mp4filename=$(basename "$f" mp4)可能有用(请参阅man basenameman dirname获得更多信息)
Peter.O 2012

bash -x myscript要逐行跟踪脚本的执行情况,并扩展所有变量。哦,顺便说一句,您已经重新发明了basename车轮上的轮子FILENAME=。:)
沃伦·杨

1
我找到了解决方案。bash脚本似乎影响了ffmpeg进程的产品输入(即'c'键)。将“ </ dev / null”插入ffmpeg,如下所示:ffmpeg -i“ ./$f” -vcodec libx264 -vprofile high-预设慢-b:v 500k-最大500k -bufsize 1000k-线程0 -acodec libfaac -ab 128k“ ./mp4s/$MP4FILENAME” </ dev / null修复此问题。通过[ linuxquestions.org/questions/programming-9/... [1]:linuxquestions.org/questions/programming-9/...
威廉姆斯

Answers:


56

您的问题实际上是Bash常见问题解答#89:添加只是</dev/null为了防止ffmpeg阅读其标准输入。


我很乐意为您修复脚本,因为它包含很多潜在的错误。一些要点:

  • 文件名很难处理,因为大多数文件系统都允许它们包含各种普通人会视为垃圾的不可打印字符。做出简化的假设,例如“文件名仅包含'正常'字符”,往往会导致出现脆弱的Shell脚本来处理“普通”文件名,然后打破它们变成一个特别讨厌的文件名的日子,该文件名不符合脚本的假设。另一方面,正确处理文件名可能会很麻烦,如果遇到奇怪文件名的机会预计接近零(例如,您仅在自己的文件上使用脚本,并且您为自己的文件指定“简单”名称)。有时完全不解析文件名就可以完全避免此决定。幸运的是,可以使用find(1)-exec选项。只需将{}参数放到中,-exec就不必担心解析find输出。

  • 使用sed或其他外部过程执行简单的字符串操作(如剥离扩展名和前缀)效率低下。取而代之的是使用参数扩展,它是外壳程序的一部分(没有外部进程意味着它会更快)。下面列出了一些有关该主题的有用文章:

  • 使用$( ),并且不再使用``Bash 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在原始文档中没有使用或不需要任何特定于功能的功能。


3
这是一个绝妙的答案!感谢您为编写更正的脚本所做的努力。只是想知道是否有类似于Greg的zsh Wiki指南?谢谢!
艺术

1
@Art抱歉,我不太了解zsh。也许网站上的某些zsh人员会知道。
2012年

问题是我需要检查ffmpeg是否产生错误,以便稍后在脚本中决定是否删除转换后文件的先前版本。我将Plex Media Server的mkv转换为mp4。我的mkv文件很大,因此结结巴巴,所以我决定将所有mkv都转换为mp4。另一个问题是,我需要检查基于图片格式的字幕流转换失败,在这种情况下,我将使用另一个过程来提取字幕。因此,如何运行ffmpeg,获取其输出,并且不遇到此问题?
dacabdi

15

我找到了解决方案。bash脚本似乎产生了干扰ffmpeg过程的输入(即“ c”键)。

像这样添加< /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

解决此问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.