我有一些用 The Criterion Collection 编码的视频,他们的视频使用这些称为“章节原子”的东西。真正奇怪的是它ffprobe
没有检测到这些。我假设章节原子是 H.264/H.265/MP4/MOV 的东西,但 Matroska 视频容器可能有自己的章节元数据,对吧?不确定...
例如,当我使用时ffprobe -show_chapters <video file>
,它只会给我一个章节,如下所示:
[CHAPTER]
id=0
time_base=1/1000000000
start=7235652000000
start_time=7235.652000
end=7235652000000
end_time=7235.652000
TAG:title=XXXXXX
[/CHAPTER]
但是当我用 MKVToolNix GUI 打开它并使用他们的“信息工具”时,我在最底部看到一个可折叠的菜单项,上面写着“章节”,我将其展开为“版本条目”,它有“版本标志隐藏”、“版本标志默认”、“版本 UID”等内容,最后还有多个“章节原子”。这些都是 ffmpeg/ffprobe 无法通过正常方式检测到的东西。
ffmpeg
好了,现在来谈谈我要解决的问题。我用来保存的带有命令行的脚本全部数据(除字幕外)如下:
#!/bin/sh
if [ $# -eq 0 ]; then
>&2 echo "Error: No filename(s) specified."
exit 1
fi
# TODO: Sometimes it does not copy over chapter info
for f in "$@"; do
ffmpeg -i "$f" -threads 4 \
-c:v copy -c:a copy -sn \
-map 0 -map_metadata 0 -map_chapters 0 \
-movflags use_metadata_tags \
"${f%.*}-subs-removed.${f##*.}"
done
我这样做的原因主要是因为强迫症。我一直希望我的字幕是分开的。原因有很多。有时字幕中会有错误或失误,我想修复这些错误或失误,格式不精确的问题,OCR 转换错误,删除字幕中烦人的第三方网站版权/水印,调整字幕时间、同步和持续时间,让人们更容易在重新分发时翻译成其他语言,从一种字幕格式转换为另一种字幕格式,等等……
我觉得我已经尽我所能尝试将一个视频文件中的所有数据(包括元数据)保留到另一个视频文件中。但 FFmpeg 似乎还不足以胜任这项工作确切地我希望它做什么,因为它总是缺少文件中一些自定义标签和元数据,否则这些标签和元数据应该被复制过去。
那么 ffmpeg 是不是不适合这个工作的工具?看起来mkvextract
frommkvtoolnix
能够检测并提取这些章节原子,但ffmpeg
实际上却不能。这是为什么呢?
也许有办法将章节单元转换成常规的 Matroska 视频章节?不过,我希望有更自动化的方法,因为我有几个 shell 脚本ffmpeg-subs-remove.sh
,并且ffmpeg-subs-extract.sh
,删除字幕的那个是我上面发布的代码片段,如果能让它再次正常工作就太好了。
答案1
这实际上并不是 FFMpeg 的解决方案,但它可以与 MKVToolNix 一起工作。
#!/bin/sh
if [ $# -eq 0 ]; then
>&2 echo "Error: No filename(s) specified."
exit 1
fi
for f in "$@"; do
destfile="${f%.*}-subs-removed.${f##*.}"
ffmpeg -i "$f" -threads 4 \
-c:v copy -c:a copy -sn \
-map 0 -map_metadata 0 -map_chapters 0 \
-movflags use_metadata_tags+faststart \
"$destfile"
# We need to do more post-processing with mkvtoolnix because ffmpeg
# is not an advanced enough tool yet to copy over all MKV container data
if mkvinfo "$f" > /dev/null 2>&1; then
tagsfile="/tmp/mkv-tags.xml"
chaptersfile="/tmp/mkv-chapters.xml"
echo "Notice: Matroska container format detected. Copying over extra data."
mkvextract -f "$f" tags "$tagsfile"
mkvextract -f "$f" chapters "$chaptersfile"
if [ -r "$tagsfile" ]; then
mkvpropedit "$destfile" --tags all:"$tagsfile"
rm -f "$tagsfile"
fi
if [ -r "$chaptersfile" ]; then
mkvpropedit "$destfile" --chapters "$chaptersfile"
rm -f "$chaptersfile"
fi
fi
done
我还没有用多个文件测试过,可能还有其他测试用例我遗漏了。虽然不完美,但目前对我来说还算可以。