用ffmpeg把mkv中的eac3音频转成aac编码

起因

最近有一部韩剧火了,从网上下载下来之后打算用局域网共享的方式,在小米盒子上播放。花生薯片汽水都准备好之后,在电视一打开,发现只有画面没有声音。用手机连上NAS一看,是可以正常播放的,就是电视盒子不行。

意兴阑珊。

换作一般人,可能就退而求其次放在电脑或者手机上面看算了,但很明显,我不是一般人。

排查

既然是用手机播放正常,用电视盒子不正常,那很明显就是电视盒子对电影文件里面的音频流没有正确的解码库了。

先用ffmpeg看看电影文件,发现两条音轨用的音频流都是eac3编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Input #0, matroska,webm, from '鱿鱼游戏_-_S01E01_-_一二三,木头人.mkv':
Metadata:
encoder : libebml v1.4.2 + libmatroska v1.6.4
Duration: 00:59:42.21, start: 0.000000, bitrate: 3549 kb/s
Stream #0:0(kor): Video: h264 (Main), yuv420p(progressive), 1280x720 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
Metadata:
BPS : 2007688
DURATION : 00:59:42.162000000
NUMBER_OF_FRAMES: 85886
NUMBER_OF_BYTES : 898983345
_STATISTICS_WRITING_APP: mkvmerge v61.0.0 ('So') 64-bit
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:1(kor): Audio: eac3, 48000 Hz, 5.1, fltp (default)
Metadata:
BPS : 768000
DURATION : 00:59:42.208000000
NUMBER_OF_FRAMES: 111944
NUMBER_OF_BYTES : 343891968
_STATISTICS_WRITING_APP: mkvmerge v61.0.0 ('So') 64-bit
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(eng): Audio: eac3, 48000 Hz, 5.1, fltp
Metadata:
BPS : 768000
DURATION : 00:59:42.208000000
NUMBER_OF_FRAMES: 111944
NUMBER_OF_BYTES : 343891968
_STATISTICS_WRITING_APP: mkvmerge v61.0.0 ('So') 64-bit
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(kor): Subtitle: subrip (default) (forced)
Metadata:
title : Forced
BPS : 0
DURATION : 00:58:05.857000000
NUMBER_OF_FRAMES: 7
NUMBER_OF_BYTES : 180
_STATISTICS_WRITING_APP: mkvmerge v61.0.0 ('So') 64-bit
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

而播放不出声音的小米盒子,是小米盒子4 SE,支持的音频格式如下:

mibox4se

可以看到,虽然官方介绍的参数里面很巧妙地用了一个“等”字,但结合网上的其他搜索结果,基本可以确认,这一型号的小米盒子是不支持我下载的这个电影里面的eac3音频流的。

方案

我在网上搜到的解决方案里面,大多都是教你选择用什么样的第三方播放器,实现软解。但尴尬的是,当初买的这个盒子就是贪便宜买的低配置,自带的存储空间太小,而且很多时候运行一些主流的视频平台app都已经抓襟见肘,卡顿非常严重。所以,最后我还是决定给转个格式就算了。

结合上面ffmpeg的输出来看,我下载下来的是一个用MKV封装的文件,里面包含一个h264编码的视频流,和两个eac3编码的音轨,再有一些字幕。而我的需求就是,把这个mkv直接转成一个mp4文件,视频不需要重新转码,音频使用aac编码,再加一个简体中文字幕。

该如何实现呢?

经过一番摸索,成功编出一条ffmpeg命令:

1
ffmpeg -i 鱿鱼游戏_-_S01E01_-_一二三,木头人.mkv -map 0:0 -map 0:1 -map 0:36 -c:v copy -c:a aac -c:s mov_text -y youyu-1.mp4

参数解释:

参数 作用
-i 指定输入的源文件
-map 选择数据流,在这个文件中,Stream 0:0 是视频流,0:1是音频流,0:36是我需要的简体中文字幕
-c 选择codec,即解码器或者编码器(decoder/encoder),当-c参数出现在-i参数之前,则是指定解码器(decoder);相反,当-c出现在output文件之前,则是指定编码器(encoder)。但一般来说ffmpeg会自动选择解码器,在转码的时候,我们只需要指定编码器即可。
-c:v 指定视频流(video)的编码器,在这个例子中,我们使用copy参数,意思是无需重新编码
-c:a 指定音频(audio)的编码器,这就是我们的目的,使用aac
-c:s 由于我们使用的是MP4文件格式,不支持源文件中使用的subrip格式字幕,所以字幕也需要转格式。使用mov_text编码器转成MP4所支持的3GPP Timed Text subtitle格式。详见:https://en.wikipedia.org/wiki/MPEG-4_Part_17
-y 指定输出文件的文件名,并且强制覆盖同名文件

通过一番骚操作,我们就可以成功把一个MKV容器里面的eac3音轨重新编码成aac了:

ffmpeg-running

批量转换要怎么办呢?也不难,在cmd上面跑一个for循环就可以了:

1
for %a in ("*.mkv") do ffmpeg -i "%a" -map 0:0 -map 0:1 -map 0:36 -c:v copy -c:a aac -c:s mov_text -y "G:\%~na.mp4"

心得

说来惭愧,笔者在2016年就知道有ffmpeg这个东西,并且因为玩nas经常下载电影的关系,从2018年开始偶尔会高强度使用。但是一直以来对ffmpeg的认识还停留在上网搜索一串命令,摸索着改一改然后就直接套用这样的程度上,对于里面很多细节的东西从来都不求甚解。

甚至说,要是我没有想着把这个事情以博文的方式记录下来,大概率也只会简单把那一句ffmpeg命令收录到自己的云笔记本中。而通过这一次用输出倒逼输入,好歹是多了一些深刻记忆。

  • mkv是一种文件容器(container),mp4也是。文件里面可以包含多个视频、音频、字幕或者是文本的数据流。
  • 不同的文件容器支持的格式范围不一样,在这里mkv支持的格式就比mp4多。
  • 使用ffmpeg的时候,根据自己的需求选择合适的编码器(encoder)。
  • 可以用map参数直接选择自己需要的stream。
  • 对于mkv文件,其实还有一个更趁手的工具:mkvmerge,后面有时间摸索一下。
  • 贫穷使我博学

彩蛋

在这部电视剧中,第一集的标题是一二三,木头人,这里是意译,韩文原文是무궁화 꽃이 피던 날(mugunghwa kkoch-i pideon nal)

直译过来是:”木槿花盛开的日子。”