ffmpeg提取与合并音视频和字幕
提取
假设有一个视频文件名字叫demo.mkv
,有两条音频,一条字幕。
# 打印视频信息
$ ffprobe -i demo.mkv
# 以下是简化后的视频信息
视频1:Stream 0:0 hevc
音频1:Stream 0:1 eac3
音频2:Stream 0:2 aac
字幕1:Stream 0:3 subrip
# `Stream [i]:[j]`是指第i个输入中的第j个流。
# 视频、音频、字幕、缩略图等等都称为流。
# 此处的i=0即`demo.mkv`,j=0即视频1。
# 导出视频,无音频
# 参数`-map [i]:[j]`是指第i个输入中的第j个流(Stream)
# 参数`-vcodec copy`和`-c:v copy`表示不重新编码视频,直接复制。
# 参数`-acodec copy`和`-c:a copy`表示不重新编码音频,直接复制。
# 参数`-scodec copy`和`-c:s copy`表示不转换字幕,直接复制。
# 参数`-an`和`-vn`表示不导出音频和视频。
# 参数`-y`是指如果输出文件已存在,不询问直接覆盖。
$ ffmpeg -i demo.mkv -map 0:0 -vcodec copy -an -y "video.mp4"
# 导出第1条音频,无视频
$ ffmpeg -i demo.mkv -map 0:1 -acodec copy -vn -y "audio_1.ac3"
# 导出第2条音频,无视频
$ ffmpeg -i demo.mkv -map 0:2 -c:a copy -vn -y "audio_2.m4a"
# 导出字幕
$ ffmpeg -i demo.mkv -map 0:3 -c:s copy -an -vn -y "subtitle.srt"
# 合并为mkv
# 参数`-map [i]:v`是指第i个输入作为视频流
# 参数`-map [i]:a`是指第i个输入作为音频流
# 参数`-map [i]:s`是指第i个输入作为字幕流
# 参数`-metadata:s:a:1`表示指定第2个音频流的metadata
# 参数`-disposition:a:0 default`表示默认使用第1个音频流
# 参数`-disposition:a:1 0`表示取消默认使用第2个音频流
# 参数`-disposition:s:0 default`表示默认使用第1个字幕流
# 输出视频中流的位置按添加顺序编号
$ ffmpeg -i "video.mp4" \
-i "audio_1.ac3" -i "audio_2.m4a" \
-i "subtitle.srt" \
-map 0:v -map 1:a -map 2:a -map 3:s \
-c:v copy -c:a copy -c:s copy \
-metadata:s:a:0 title="中文" -metadata:s:a:0 language=Chinese \
-metadata:s:a:1 title="英语" -metadata:s:a:1 language=English \
-metadata:s:s:0 title="简体中文" -metadata:s:s:0 language="Simplified Chinese" \
-disposition:a:0 default \
-disposition:a:1 0 \
-disposition:s:0 default \
-y "output.mkv"
根据音频格式返回扩展名和流索引
$ get_audio() {
INFO="$1"
MANDARIN=`cat "${INFO}" | grep "Audio.*default"`
MANDARIN_STREAM_INDEX="${MANDARIN#*:}"
MANDARIN_STREAM_INDEX="${MANDARIN_STREAM_INDEX%%:*}"
MANDARIN_STREAM_INDEX="${MANDARIN_STREAM_INDEX%%(*}"
MANDARIN_STREAM_CODEC="${MANDARIN%%,*}"
MANDARIN_STREAM_CODEC="${MANDARIN_STREAM_CODEC##*: }"
if [[ "${MANDARIN_STREAM_CODEC}" == "eac3" ]]; then
MANDARIN_STREAM_CODEC="ac3"
else
MANDARIN_STREAM_CODEC="m4a"
fi
SHANGHAI=`cat "${INFO}" | grep "Audio" | grep -v "default"`
SHANGHAI_STREAM_INDEX="${SHANGHAI#*:}"
SHANGHAI_STREAM_INDEX="${SHANGHAI_STREAM_INDEX%%:*}"
SHANGHAI_STREAM_INDEX="${SHANGHAI_STREAM_INDEX%%(*}"
SHANGHAI_STREAM_CODEC="${SHANGHAI%%,*}"
SHANGHAI_STREAM_CODEC="${SHANGHAI_STREAM_CODEC##*: }"
SHANGHAI_STREAM_CODEC="${SHANGHAI_STREAM_CODEC%% *}"
if [[ "${SHANGHAI_STREAM_CODEC}" == "eac3" ]]; then
SHANGHAI_STREAM_CODEC="ac3"
else
SHANGHAI_STREAM_CODEC="m4a"
fi
echo "${SHANGHAI_STREAM_INDEX}" "${SHANGHAI_STREAM_CODEC}" "${MANDARIN_STREAM_INDEX}" "${MANDARIN_STREAM_CODEC}"
}
$ INFO="info.log"
$ ffprobe -i "demo.mkv" > "${INFO}" 2>&1
$ INDEX_CODEC=($(get_audio "$INFO"))
$ SH_I="${INDEX_CODEC[0]}"
$ SH_C="${INDEX_CODEC[1]}"
$ CN_I="${INDEX_CODEC[2]}"
$ CN_C="${INDEX_CODEC[3]}"
# echo "audio: ${SH_I}, ext: ${SH_C}"
# echo "audio: ${CN_I}, ext: ${CN_C}"