使用ffmpeg把mkv转成mp4

最近因为要帮球球找一些经典的动画片,突然想起自己当年看的《灌篮高手》,看的很是热水沸腾,那就给球球找一下也看看吧。

不过夸克上面都是1080P的mkv格式的。每集20分钟左右都要1.3G的样子。

由于最近硬盘涨价实在太猛了,买不新盘扩容了。那就想着如何节省空间上想办法了。

首先想到的就是H265,H265原生就比H264要节省一半的空间。

由于我自己xubuntu上用的就是vlc player,这个默认就可以转的,于是就试试看了。

看着还是非常多格式的。

用H265+AAC的压缩完,1.4G的mkv居然就变成了178M的样子了。这效果还是非常明显的啊。

压缩完的MP4文件打开感觉非常卡啊,而且我的极米H3S默认的播放器居然无法播放,但是能获取到视频长度这些信息,而且投影仪安装vlc也是可以播放的。而且我记得MediaTek MT9669这个芯片是支持H265的。

那我只能怀疑vlc转的时候丢失了什么信息,或者压缩率太高了,导致卡和无法播放。

既然是Linux下,那就用ffmpeg来转吧。

首先我需要确认下原视频信息,可以看到这个就是用H264编码的,然后包含了国语,粤语,日语三种语言,同时字幕又包含了简体中文和日语的双语字幕和日文的单字幕两种选择。

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# ffprobe -show_format -show_streams 灌篮高手.1080P.国粤日三语.软字幕.AVC.默认国语音频.003.mkv
Input #0, matroska,webm, from '灌篮高手.1080P.国粤日三语.软字幕.AVC.默认国语音频.003.mkv':
Metadata:
encoder : libebml v1.3.6 + libmatroska v1.4.9
creation_time : 2018-06-13T04:04:51.000000Z
Duration: 00:18:59.59, start: 0.000000, bitrate: 10016 kb/s
Stream #0:0(jpn): Video: h264 (High 10), yuv420p10le(progressive), 1440x1080, SAR 1:1 DAR 4:3, 23.98 fps, 23.98 tbr, 1k tbn (default)
Metadata:
title : [Kagura] Slam Dunk - 003 [BDRip 1440x1080 x264 Hi10P FLAC]
BPS-eng : 9314136
DURATION-eng : 00:18:59.013000000
NUMBER_OF_FRAMES-eng: 27309
NUMBER_OF_BYTES-eng: 1326115285
_STATISTICS_WRITING_APP-eng: mkvmerge v24.0.0 ('Beyond The Pale') 64-bit
_STATISTICS_WRITING_DATE_UTC-eng: 2018-06-13 04:04:51
_STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:1(chi): Audio: aac (LC), 48000 Hz, stereo, fltp (default) (forced)
Metadata:
title : 国语Mandarin
BPS-eng : 159644
DURATION-eng : 00:18:58.622000000
NUMBER_OF_FRAMES-eng: 53373
NUMBER_OF_BYTES-eng: 22721912
_STATISTICS_WRITING_APP-eng: mkvmerge v24.0.0 ('Beyond The Pale') 64-bit
_STATISTICS_WRITING_DATE_UTC-eng: 2018-06-13 04:04:51
_STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(chi): Audio: aac (HE-AAC), 44100 Hz, stereo, fltp
Metadata:
title : 粤语Cantonese
BPS-eng : 32318
DURATION-eng : 00:18:58.613000000
NUMBER_OF_FRAMES-eng: 24518
NUMBER_OF_BYTES-eng: 4599793
_STATISTICS_WRITING_APP-eng: mkvmerge v24.0.0 ('Beyond The Pale') 64-bit
_STATISTICS_WRITING_DATE_UTC-eng: 2018-06-13 04:04:51
_STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(jpn): Audio: flac, 48000 Hz, stereo, s16
Metadata:
BPS-eng : 512022
DURATION-eng : 00:18:59.029000000
NUMBER_OF_FRAMES-eng: 13348
NUMBER_OF_BYTES-eng: 72901045
_STATISTICS_WRITING_APP-eng: mkvmerge v24.0.0 ('Beyond The Pale') 64-bit
_STATISTICS_WRITING_DATE_UTC-eng: 2018-06-13 04:04:51
_STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:4(chi): Subtitle: ass (default)
Metadata:
title : 诸神简日双语字幕
BPS-eng : 246
DURATION-eng : 00:18:58.860000000
NUMBER_OF_FRAMES-eng: 582
NUMBER_OF_BYTES-eng: 35103
_STATISTICS_WRITING_APP-eng: mkvmerge v24.0.0 ('Beyond The Pale') 64-bit
_STATISTICS_WRITING_DATE_UTC-eng: 2018-06-13 04:04:51
_STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:5(jpn): Subtitle: ass
Metadata:
title : 诸神日文单语字幕
BPS-eng : 131
DURATION-eng : 00:18:58.860000000
NUMBER_OF_FRAMES-eng: 292
NUMBER_OF_BYTES-eng: 18780
_STATISTICS_WRITING_APP-eng: mkvmerge v24.0.0 ('Beyond The Pale') 64-bit
_STATISTICS_WRITING_DATE_UTC-eng: 2018-06-13 04:04:51
_STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

由于我的电脑是有一块nvidia geforce gtx 1060 super的显卡,所以有些参数就需要修改下,毕竟纯cpu编码还是非常慢的。下面这个是我最后批量进行的转码脚本。

1
2
3
4
#!/bin/bash
for file in *.mkv; do
sudo ffmpeg -i "$file" -map 0:v -map 0:a:0 -map 0:s:m:language:chi -c:v hevc_nvenc -preset p7 -tune hq -cq 28 -c:a aac -b:a 192k -c:s mov_text "${file%.mkv}.mp4"
done

其中

-cq 28

这个就是清晰度的,一般是23到28之间的数字,数字越小越清晰,我其他参数不改,把28改成23后,压缩完大小从287M变成了500M多,但是转换的速度是一致的。

1
2
3
[out#0/mp4 @ 0x5ad496648140] video:553740kB audio:27024kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.179328%
frame=27309 fps=211 q=19.0 Lsize= 581805kB time=00:18:58.84 bitrate=4185.1kbits/s speed=8.82x
[aac @ 0x5ad497281cc0] Qavg: 681.596

-c:v hevc_nvenc

这个是表示H265,因为我是gpu编码的,所以用这个,如果是cpu的话那就写libx265

-preset p7

p1-p7 是 NVIDIA NVENC 的编码预设等级,用于控制编码速度和质量的平衡

其中p7是编码速度最慢,但是质量最高,得到的最终文件也是最小。

-tune hq

后面的参数有: llhq (低延迟高质量) 和 hq (高质量) 可能重叠, hp (高性能) 和 llhp (低延迟高性能) 质量不可预测

具体信息可以参考 https://developer.nvidia.com/blog/introducing-video-codec-sdk-10-presets/

这里有官方做的一些测试,不过这个是针对sdk10和sdk9对比的数据,后面的我也没找到最新的。

不过上面这些是我自己实践下来压缩率最高,同时H3S的播放器也可以直接播放的。

下面这个是转码的效率显示

1
2
[out#0/mp4 @ 0x61ae1cd78280] video:265614kB audio:27024kB subtitle:31kB other streams:0kB global headers:0kB muxing overhead: 0.361503%
frame=27309 fps=216 q=24.0 Lsize= 293727kB time=00:18:58.84 bitrate=2112.8kbits/s speed=8.99x

可以看到基本是9x的速度,这个可以比完全cpu搞快多了。

压缩完的大小如下:

1
-rwxr-xr-x 1 root root 287M Jan 25 23:19 灌篮高手.1080P.H265.国语.003-p7.mp4

虽然跟vlc压缩的要大很多,但是跟1.4G比起来还是小了很多。原先需要140G的磁盘空间,现在在码率不变的情况下变成了29G。这就是实打实的省钱。

当然我实际搞的时候还测试了很多种。

下面这个是p4到p6的压缩数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-preset p4
[out#0/mp4 @ 0x5656c4ad1100] video:273390kB audio:27024kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.346680%
frame=27309 fps=424 q=24.0 Lsize= 301455kB time=00:18:58.84 bitrate=2168.4kbits/s speed=17.7x
[aac @ 0x5656c570ad40] Qavg: 681.596


-preset p5 -tune hq
[out#0/mp4 @ 0x5f211f680140] video:266981kB audio:27024kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.354236%
frame=27309 fps=390 q=24.0 Lsize= 295046kB time=00:18:58.84 bitrate=2122.3kbits/s speed=16.3x
[aac @ 0x5f21202b9cc0] Qavg: 681.596


-preset p6 -tune hq
[out#0/mp4 @ 0x5f21cef0b140] video:265591kB audio:27024kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.355920%
frame=27309 fps=236 q=24.0 Lsize= 293656kB time=00:18:58.84 bitrate=2112.3kbits/s speed=9.86x
[aac @ 0x5f21cfb44cc0] Qavg: 681.596

可以明显的看到p4和p5的速度是差不多的,p6和上面p7的速度是差不多的。

同时p4压缩完的大小也是最大的。p6和p7几乎就一样了。

同时还观测了一下gpu的占用情况,几乎还是比较闲的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# nvidia-smi
Sun Jan 25 22:18:42 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.95.05 Driver Version: 580.95.05 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce GTX 1660 ... Off | 00000000:01:00.0 On | N/A |
| 51% 54C P2 58W / 125W | 613MiB / 6144MiB | 13% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 1550 G /usr/lib/xorg/Xorg 306MiB |
| 0 N/A N/A 2077 G xfwm4 2MiB |
| 0 N/A N/A 2776 G ...rack-uuid=3190708988185955192 48MiB |
| 0 N/A N/A 23447 C ffmpeg 234MiB |
+-----------------------------------------------------------------------------------------+

除了压缩率本身,另外音轨和字幕也是占用空间的,但是我实际测试,无论外挂字幕或者嵌入字幕,这个都几乎不占用空间的。但是音轨确实是比较大的。

下面是我的测试结果

1
2
3
4
5
6
# 带2个音轨(国语和粤语)和字幕
-rwxr-xr-x 1 root root 341M Jan 25 22:55 灌篮高手.1080P.H265.国语.003-p7.mp4


# 只带第一个音轨(国语)和中文字幕
-rwxr-xr-x 1 root root 287M Jan 25 23:19 灌篮高手.1080P.H265.国语.003-p7.mp4

以上一个20分钟的音轨就占用了54M,但是这也是我音轨使用192K的缘故,如果是128K的话还能更小的,但是我个人还是希望声音好听点。

关于多音轨和多字幕的,我们如果只想要其中一个,那我们就需要提前看下音轨和字幕信息

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
# ffprobe -v error -show_entries stream=index:stream_tags=language:stream_tags=title -select_streams a  '灌篮高手.1080P.国粤日三语.软字幕.AVC.默认国语音频.003.mkv
[STREAM]
index=1
TAG:language=chi
TAG:title=国语Mandarin
[/STREAM]
[STREAM]
index=2
TAG:language=chi
TAG:title=粤语Cantonese
[/STREAM]
[STREAM]
index=3
TAG:language=jpn
[/STREAM]


# fprobe -v error -show_entries stream=index:stream_tags=language:stream_tags=title -select_streams s '灌篮高手.1080P.国粤日三语.软字幕.AVC.默认国语音频.003.mkv'
[STREAM]
index=4
TAG:language=chi
TAG:title=诸神简日双语字幕
[/STREAM]
[STREAM]
index=5
TAG:language=jpn
TAG:title=诸神日文单语字幕
[/STREAM]

然后在转码的时候加上对应参数,不过这里的index应该都是从0来的,不要看这里index=1 就写1

1
-map 0:v -map 0:a:0 -map 0:s:m:language:chi

上面的0: a:0 这里的最后一个0就表示第一个index, a表示audio音频, 后面的 0: s:m: 这里也可以写index的方式,但是因为我这里中文就一个简体中文就行了,所以就写 language:chi 来匹配简体中文,如果要写index格式的话,那就写 0: s:0 就可以了。

最后还是要感谢这些字幕组搞出来这些,什么《七龙珠》这些居然都有。