更正ffmpeg字幕脚本中的变量名称

时间:2017-06-20 05:57:16

标签: bash ffmpeg

我有175个 mp4 视频文件和字幕文件,扩展名为 .ass 。不幸的是,我的智能电视无法读取那些字幕。我计划将字幕刻录(硬编码)到视频中。

我使用这个命令:

bash

有效。所以我计划使用ffmpeg脚本来自动化这个过程。

脚本中的所有内容都有效,但for f in *.mp4 do new="${f%%.mp4} (CHT).mp4" subtitle="${f%%.mp4}.chi.ass" < /dev/null ffmpeg -i "$f" -vf subtitles="$subtitle" "$new" done 命令行无法检索字幕变量。

在谷歌搜索后,我发现我的文件名有特殊的字符和空格,导致我的脚本失败。如果视频文件名和字幕文件很简单,那么脚本应该没问题。

这是我的剧本:

ffmpeg

{{1}}行在读取字幕文件变量时遇到问题。有人可以帮忙吗?

3 个答案:

答案 0 :(得分:1)

尝试更改:

new="${f%%.mp4} (CHT).mp4"
subtitle="${f%%.mp4}.chi.ass"
< /dev/null ffmpeg -i "$f" -vf subtitles="$subtitle" "$new"

要:

new="${f%%.mp4}.CHT.mp4"
subtitle="${f%%.mp4}.chi.ass"
# make a temp hardlink to evade `ffmpeg`'s 
# onerous quoting requirements.
x=`mktemp -u -p . --suffix=.ass`
ln "$subtitle" $x
< /dev/null ffmpeg -i "$f" -vf subtitles=$x "${new}"
rm $x

工作原理。由于ffmpeg难以使用带转义的字幕文件,只需将字幕文件链接到名称$x 而不用转义,然后让ffmpeg将其翻过来,然后删除链接。

更简洁的方法是使用名为ffescape的工具翻译$subtitle变量;遗憾的是,该工具目前尚未打包在ffmpeg的源代码树之外。

答案 1 :(得分:1)

我设法使用此脚本解决问题。如果你可以帮助缩短它,它将是完美的。

for f in *.mp4
do
    new="${f%%.mp4} (CHT).mp4"
    subtitle="${f%%.mp4}.chi.ass"
    newsubtitle="${subtitle// /\\ }"
    echo $newsubtitle
    secsubtitle="${newsubtitle//[/\\[}"
    echo $secsubtitle
    thirdtitle="${secsubtitle//]/\\]}"
    echo $thirdtitle
    fourthtitle="${thirdtitle//(/\\(}"
    echo $fourthtitle
    fifthtitle="${fourthtitle//)/\\)}"
    echo $fifthtitle
    ffmpeg -i "$f" -vf subtitles="$fifthtitle" "$new"
done

谢谢

答案 2 :(得分:0)

可能是,以下内容有助于阐明它:

一个小的测试程序,它反映了命令行参数的传递方式:

$ cat >print-arg.c <<EOF
#include <stdio.h>

int main(int argc, char **argv)
{
  for (int i = 0; i < argc; ++i) printf("argv[%d]: '%s'\n", i, argv[i]);
  return 0;
}
EOF

$ gcc -o print-arg print-arg.c

$

这可以用来反映论点:

$ ./print-arg Hello\ World "Hello World"
argv[0]: './print-arg'
argv[1]: 'Hello World'
argv[2]: 'Hello World'

$

为了确保终端不会欺骗我们,我们甚至可以这样做:

$ ./print-arg Hello\ World "Hello World" | hexdump -C
00000000  61 72 67 76 5b 30 5d 3a  20 27 2e 2f 70 72 69 6e  |argv[0]: './prin|
00000010  74 2d 61 72 67 27 0a 61  72 67 76 5b 31 5d 3a 20  |t-arg'.argv[1]: |
00000020  27 48 65 6c 6c 6f 20 57  6f 72 6c 64 27 0a 61 72  |'Hello World'.ar|
00000030  67 76 5b 32 5d 3a 20 27  48 65 6c 6c 6f 20 57 6f  |gv[2]: 'Hello Wo|
00000040  72 6c 64 27 0a                                    |rld'.|
00000045

$

现在,这个print-arg工具可用于调试bash脚本test-subtitle.sh

#/bin/bash
for f in *.mp4
do
  new="${f%%.mp4} (CHT).mp4"
  subtitle="${f%%.mp4}.chi.ass"
  ./print-arg < /dev/null ffmpeg -i "$f" -vf subtitles="$subtitle" "$new"
done

进行测试:

$ touch file1.mp4 file\ 2.mp4 "file 3.mp4"

$ ./test-subtitle.sh
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file 2.mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file 2.chi.ass'
argv[6]: 'file 2 (CHT).mp4'
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file 3.mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file 3.chi.ass'
argv[6]: 'file 3 (CHT).mp4'
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file1.mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file1.chi.ass'
argv[6]: 'file1 (CHT).mp4'

$

此测试应该清楚地说明ffmpeg将如何获得命令行参数。

<强>更新

请在命令行上尝试:

$ < /dev/null ffmpeg -i '[アニメ] FAIRY TAIL 第001話「妖精の尻尾(ようせいのしっぽ)」(1280x720 x264 AAC).mp4' -vf 'subtitles=[アニメ] FAIRY TAIL 第001話「妖精の尻尾(ようせいのしっぽ)」(1280x720 x264 AAC).chi.ass' '[アニメ] FAIRY TAIL 第001話「妖精の尻尾(ようせいのしっぽ)」(1280x720 x264 AAC) (CHT).mp4'

在阅读完答案后,我相信字幕确实被提供反斜杠转义。我很好奇引用是否会起作用。

所以,请在命令行上进行最后一次测试:

$ < /dev/null ffmpeg -i '[アニメ] FAIRY TAIL 第001話「妖精の尻尾(ようせいのしっぽ)」(1280x720 x264 AAC).mp4' -vf 'subtitles="[アニメ] FAIRY TAIL 第001話「妖精の尻尾(ようせいのしっぽ)」(1280x720 x264 AAC).chi.ass"' '[アニメ] FAIRY TAIL 第001話「妖精の尻尾(ようせいのしっぽ)」(1280x720 x264 AAC) (CHT).mp4'

根据你的评论,反斜杠转义似乎是传递字幕文件的唯一方法。实际上,我在Stackoverflow中发现了一个更短(可能更强大)的解决方案:Escape FileNames Using The Same Way Bash Do It

应用于您的脚本:

#/bin/bash
for f in *.mp4
do
  new="${f%%.mp4} (CHT).mp4"
  subtitle=$(printf '%q' "${f%%.mp4}.chi.ass")
  < /dev/null ffmpeg -i "$f" -vf subtitles="$subtitle" "$new"
done

我分别更改了基本脚本test-subtitle.sh

#/bin/bash
for f in *.mp4
do
  new="${f%%.mp4} (CHT).mp4"
  subtitle=$(printf '%q' "${f%%.mp4}.chi.ass")
  ./print-arg < /dev/null ffmpeg -i "$f" -vf subtitles="$subtitle" "$new"
done

得到了:

$ touch file1.mp4 file\ 2.mp4 "file 3.mp4" 'file[4].mp4'

$ ./test-subtitle.sh 
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file 2.mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file\ 2.chi.ass'
argv[6]: 'file 2 (CHT).mp4'
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file 3.mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file\ 3.chi.ass'
argv[6]: 'file 3 (CHT).mp4'
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file1.mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file1.chi.ass'
argv[6]: 'file1 (CHT).mp4'
argv[0]: './print-arg'
argv[1]: 'ffmpeg'
argv[2]: '-i'
argv[3]: 'file[4].mp4'
argv[4]: '-vf'
argv[5]: 'subtitles=file\[4\].chi.ass'
argv[6]: 'file[4] (CHT).mp4'

$