我在一个 .mkv 文件中提取了多个音轨和字幕。我是ffmpeg
命令的新手,这是我尝试过的(音频):
ffmpeg -i VIDEO.mkv -vn -acodec copy AUDIO.aac
它只提取1个音频。我想要的是告诉ffmpeg
将每个音频文件和字幕文件提取到目的地,并保留每个文件和扩展名的原始名称。 (因为我不知道音频文件是哪个扩展名,有时可能是 .flac 或 .aac )。
我不确定我在网上找到的解决方案,因为它非常复杂,我需要解释才能知道它是如何工作的,以便我可以在未来。顺便说一句,我计划从Windows CMD运行代码。
谢谢。
答案 0 :(得分:30)
ffmpeg
中没有选项可以自动将所有流提取到适当的容器中,但当然可以手动执行。默认stream selection仅为每种流类型选择一个流,因此您必须手动映射每个流。
使用ffmpeg
或ffprobe
,您可以获取每个流中的信息,并且可以使用wide variety of formats(xml,json,cvs等)来满足您的需求。< / p>
ffmpeg
示例ffmpeg -i input.mkv
结果输出(我删除了一些额外的东西,流数和格式信息是重要的):
Input #0, matroska,webm, from 'input.mkv':
Metadata:
Duration: 00:00:05.00, start: 0.000000, bitrate: 106 kb/s
Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p, 320x240 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
Stream #0:1: Audio: vorbis, 44100 Hz, mono, fltp (default)
Stream #0:2: Audio: vorbis, 44100 Hz, mono, fltp (default)
Stream #0:3: Audio: vorbis, 44100 Hz, mono, fltp (default)
Stream #0:4: Subtitle: ass (default)
ffprobe
示例ffprobe -v error -show_entries stream=index,codec_name,codec_type input.mkv
结果输出:
[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=vorbis
codec_type=audio
[/STREAM]
[STREAM]
index=3
codec_name=vorbis
codec_type=audio
[/STREAM]
[STREAM]
index=4
codec_name=ass
codec_type=subtitle
[/STREAM]
使用上述命令之一的信息:
ffmpeg -i input.mkv \
-map 0:v -c copy video.mkv \
-map 0:a:0 -c copy audio0.oga \
-map 0:a:1 -c copy audio1.oga \
-map 0:a:2 -c copy audio2.oga \
-map 0:s -c copy subtitles.ass
在这种情况下,上面的例子与:
相同ffmpeg -i input.mkv \
-map 0:0 -c copy video.mkv \
-map 0:1 -c copy audio0.oga \
-map 0:2 -c copy audio1.oga \
-map 0:3 -c copy audio2.oga \
-map 0:4 -c copy subtitles.ass
我更喜欢第一个例子,因为input file index:stream specifier:stream index
更灵活,更有效率;它也不太容易出现错误的映射。
请参阅stream specifiers和-map
option上的文档,以完全理解语法。其他信息在FFmpeg mux video and audio (from another video) - mapping issue的答案中。
这些示例将stream copy(重新多路复用),因此不会进行重新编码。
答案 1 :(得分:2)
首先列出所有音频流:
ffmpeg -i VIDEO.mkv
然后根据输出你可以编译命令来单独提取音轨。
使用某些shell脚本,您可以在脚本文件中自动执行此操作,以便您可以对任何mkv文件执行此操作。
字幕几乎相同。字幕将打印在信息中,然后您可以提取它们,类似于:
ffmpeg -threads 4 -i VIDEO.mkv -vn -an -codec:s:0.2 srt myLangSubtitle.srt
0.2是您必须从信息中读取的标识符。
答案 2 :(得分:1)
如果有人使用现代版本的 ffmpeg
,it looks like 来解决这个问题,他们会在那里添加选项。
我需要通过维护所有轨道来转换文件:
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”中进行转换,而第二行执行提取
答案 3 :(得分:0)
以下脚本从当前目录中的文件中提取所有音频流
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 {} "
答案 4 :(得分:0)
我这样解决了:
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 var。
享受吧!