Audio 使用ffmpeg从视频中提取每个音频和字幕

Audio 使用ffmpeg从视频中提取每个音频和字幕,audio,video,cmd,ffmpeg,mkv,Audio,Video,Cmd,Ffmpeg,Mkv,我在一个.mkv文件中提取了多个音频曲目和字幕。我不熟悉ffmpeg命令,这是我尝试过的(音频): ffmpeg-i VIDEO.mkv-vn-acodec copy AUDIO.aac 它只提取1个音频。我想要的是告诉ffmpeg将每个音频文件和字幕文件提取到目标,并保留每个文件和扩展名的原始名称。(因为我不知道音频文件是哪个扩展名,有时可能是.flac或.aac) 我不确定我在网上找到的解决方案是什么,因为它相当复杂,我需要解释它是如何工作的,这样我将来就可以操纵这个命令了。顺便说一下,我计

我在一个.mkv文件中提取了多个音频曲目和字幕。我不熟悉
ffmpeg
命令,这是我尝试过的(音频):

ffmpeg-i VIDEO.mkv-vn-acodec copy AUDIO.aac

它只提取1个音频。我想要的是告诉
ffmpeg
将每个音频文件和字幕文件提取到目标,并保留每个文件和扩展名的原始名称。(因为我不知道音频文件是哪个扩展名,有时可能是.flac或.aac)


我不确定我在网上找到的解决方案是什么,因为它相当复杂,我需要解释它是如何工作的,这样我将来就可以操纵这个命令了。顺便说一下,我计划从Windows CMD运行代码。

谢谢。

首先列出所有音频流:

ffmpeg -i VIDEO.mkv
然后根据输出,您可以编译命令以单独提取音频曲目

使用一些shell脚本,您可以在脚本文件中自动执行此操作,这样您就可以对任何mkv文件执行此操作

字幕几乎是一样的。字幕将打印在信息中,然后您可以提取它们,类似于:

ffmpeg -threads 4 -i VIDEO.mkv -vn -an -codec:s:0.2 srt myLangSubtitle.srt

0.2是您必须从信息中读取的标识符。

ffmpeg
中还没有自动将所有流提取到适当容器中的选项,但当然可以手动执行

您只需要知道要提取的格式的适当容器

默认情况下,每个流类型只选择一个流,因此您必须使用
-map
选项手动映射每个流

1.获取输入信息 使用
ffmpeg
ffprobe
可以获得每个流中的信息,并且有一个(xml、json、cvs等)可满足您的需要

ffmpeg
示例 结果输出(我删掉了一些额外的内容,流编号和格式信息才是重要的):

ffprobe
示例 结果输出:

[STREAM]
index=0
codec_name=h264
codec_type=video
[/STREAM]
[STREAM]
index=1
codec_name=vorbis
codec_type=audio
[/STREAM]
[STREAM]
index=2
codec_name=aac
codec_type=audio
[/STREAM]
[STREAM]
index=3
codec_name=flac
codec_type=audio
[/STREAM]
[STREAM]
index=4
codec_name=ass
codec_type=subtitle
[/STREAM]
2.提取溪流 使用上述命令之一的信息:

ffmpeg -i input.mkv \
-map 0:v -c copy video_h264.mkv \
-map 0:a:0 -c copy audio0_vorbis.oga \
-map 0:a:1 -c copy audio1_aac.m4a \
-map 0:a:2 -c copy audio2.flac \
-map 0:s -c copy subtitles.ass
在这种情况下,上述示例与:

ffmpeg -i input.mkv \
-map 0:0 -c copy video_h264.mkv \
-map 0:1 -c copy audio0_vorbis.oga \
-map 0:2 -c copy audio1_aac.m4a \
-map 0:3 -c copy audio2.flac \
-map 0:4 -c copy subtitles.ass
  • 我更喜欢第一个示例,因为
    输入文件索引:流说明符:流索引
    更灵活、更高效;它也不太容易出现不正确的映射

  • 请参阅和的文档以完全理解语法。其他信息在对的答复中

  • 这些示例将(重新多路复用),因此不会发生重新编码

容器格式 用于将流与某些常见格式的输出扩展名相匹配的部分列表:

Video Format         Compatible extension(s)
H.264                .mp4, .m4v, .h264, .264
H.265/HEVC           .mp4, .h265, .265
VP8/VP9              .webm
AV1                  .mp4
MPEG-4               .mp4, .avi
MPEG-2               .mpg, .vob, .ts
DV                   .dv, .avi
Theora               .ogv/.ogg
FFV1                 .mkv
Almost anything      .mkv, .nut

Audio Format         Compatible extension(s)
AAC                  .m4a, .aac
MP3                  .mp3
PCM                  .wav
vorbis               .oga/.ogg
opus                 .opus, .oga/.ogg, .mp4
flac                 .flac, .oga/.ogg
Almost anything      .mka, .nut

Subtitle Format      Compatible extension(s)
Subrip/SRT           .srt
SubStation Alpha/ASS .ass

以下脚本从当前目录中的文件中提取所有音频流

ls |parallel "ffmpeg -i {} 2>&1 |\
 sed -n 's/.*Stream \#\(.\+\)\:\(.\+\)\: Audio\: \([a-zA-Z0-9]\+\).*$/-map \1:\2 -c copy \"{.}.\1\2.\3\"/p' |\
 xargs -n5 ffmpeg -i {} "
我是这样解决的:

ffprobe -show_entries stream=index,codec_type:stream_tags=language -of compact $video1 2>&1 | { while read line; do if $(echo "$line" | grep -q -i "stream #"); then echo "$line"; fi; done; while read -d $'\x0D' line; do if $(echo "$line" | grep -q "time="); then echo "$line" | awk '{ printf "%s\r", $8 }'; fi; done; }
输出:

仅在命令之前设置$video1变量


享受吧

如果有人使用现代版本的
ffmpeg
来回答这个问题,他们会在那里添加这个选项。 我需要通过维护所有轨迹来转换文件:

ffmpeg -i "${input_file}" -vcodec hevc -crf 28 -map 0 "${output_file}"
为了达到原始问题的要求,可能可以使用以下方法:

mappings="`ffmpeg -i \"${filein}\" |& awk 'BEGIN { i = 1 }; /Stream.*Audio/ {gsub(/^ *Stream #/, \"-map \"); gsub(/\(.*$/, \" -acodec mp3 audio\"i\".mp3\"); print; i +=1}'`"
ffmpeg -i "${input_file}" ${mappings}

第一行(mappings=…)提取现有音频流并将其转换为“-map X:Y-acodec mp3 FILENAME”,而第二行执行提取

-map 0:a:0中的零前缀是什么?我们可以有多个“索引”(例如
0:a:0
1:a:0
)吗?我认为后缀(
0
)实际上是流索引。有关于这些“超级”索引的文档吗?很抱歉有点离题。@这些值表示
输入id:stream说明符:stream id
。例如,
2:a:5
将是来自第三个输入的第六个音频流(
ffmpeg
从0开始计数)。它比简单地声明
2:5
更灵活,因为流索引值可能并不总是表示所需的流。它让你更懒惰,只需从第二个输入中选择第八个视频流:
1:v:8
。有关更多信息,请参阅和。谢谢回答!有道理,我已经阅读了-map文档,但我不知道为什么会错过它。@Mihai的主要优点是,您不必提前知道特定流的确切数字。值得注意的是,在libavformat版本57.82.100之前,无法提取Bluray字幕(hdmv_pgs_subtitle)使用此命令以*.sup格式,因此如果需要,请确保使用的是最新版本的ffmpeg可执行文件。
ffmpeg
的stderr输出不用于机器解析。这就是
ffprobe
的目的。如果我对ffmpeg有更好的理解,我当然可以设计出更好的解决方案。所以这是一个早期的解决方案,对于Matroska(MKV)格式,这很容易处理。
ffprobe -show_entries stream=index,codec_type:stream_tags=language -of compact $video1 2>&1 | { while read line; do if $(echo "$line" | grep -q -i "stream #"); then echo "$line"; fi; done; while read -d $'\x0D' line; do if $(echo "$line" | grep -q "time="); then echo "$line" | awk '{ printf "%s\r", $8 }'; fi; done; }
ffmpeg -i "${input_file}" -vcodec hevc -crf 28 -map 0 "${output_file}"
mappings="`ffmpeg -i \"${filein}\" |& awk 'BEGIN { i = 1 }; /Stream.*Audio/ {gsub(/^ *Stream #/, \"-map \"); gsub(/\(.*$/, \" -acodec mp3 audio\"i\".mp3\"); print; i +=1}'`"
ffmpeg -i "${input_file}" ${mappings}