Manipulating MKV audio and subtitle tracks with mkvtoolnix


Updated: 2018-08-19

Matroska files often contain multiple audio or subtitle tracks. The former can take up quite a bit of space in HD rips with multiple audio streams. Editing MKV containers is not only interesting if you want remove streams; you can also integrate subtitles, set a track as default, or have Kodi generate smart playlists based on certain properties.

Obtaining information from the Matroska container

Mediainfo is a popular tool to extract information from media files. Further on we'll see mkvinfo will output almost identical information, but in a less readable format. For now, consider the mediainfo output for the language track of a French movie:

$ mediainfo Intouchables.2011.576p.BluRay.x264-Soul.mkv | grep -A 15 Audio
Audio
ID                                       : 2
Format                                   : AC-3
Format/Info                              : Audio Coding 3
Mode extension                           : CM (complete main)
Format settings, Endianness              : Big
Codec ID                                 : A_AC3
Duration                                 : 1h 52mn
Bit rate mode                            : Constant
Bit rate                                 : 448 Kbps
Channel(s)                               : 6 channels
Channel positions                        : Front: L C R, Side: L R, LFE
Sampling rate                            : 48.0 KHz
Bit depth                                : 16 bits
Compression mode                         : Lossy
Stream size                              : 359 MiB (7%)
Title                                    : Original
Language                                 : French
Default                                  : Yes

Two things are important here:

  • The Language entry tells you the audio track is French (this may occasionally be mislabeled).
  • The Default entry defines the track the media player should pick as e.g. default audio or subtitle track. If you have multiple audio or subtitle tracks, it can be handy to set a default one.

While mediainfo returns the full name of the language, mkvinfo uses three-letter ISO codes (defined by the ISO 639-2 standard). Compare the mkvinfo output for the same movie:

$ mkvinfo Intouchables.2011.576p.BluRay.x264-Soul.mkv|grep Language
|  + Language: fre

Kodi will use those same ISO codes for language information.

Now let's inspect the output of a Japanese anime.

$ mediainfo Paprika.2006.Bluray.576p.x264-BTC.mkv | grep -A 15 Audio
Audio
ID                                       : 2
Format                                   : AC-3
Format/Info                              : Audio Coding 3
Mode extension                           : CM (complete main)
Format settings, Endianness              : Big
Codec ID                                 : A_AC3
Duration                                 : 1h 30mn
Bit rate mode                            : Constant
Bit rate                                 : 640 Kbps
Channel(s)                               : 6 channels
Channel positions                        : Front: L C R, Side: L R, LFE
Sampling rate                            : 48.0 KHz
Bit depth                                : 16 bits
Compression mode                         : Lossy
Stream size                              : 414 MiB (19%)
Default                                  : Yes
Forced                                   : No

While the audio track is indeed Japanese, it has not been defined, and as such mediainfo does not display any language info. Since we'll be using smart playlists to filter out the Japanese movies from our collection, this means the smart playlist won't pick up this movie. We'll fix this with mkvmerge.

Mkvmerge identifies each stream with a number starting from zero. These numbers do not match the IDs mediainfo uses. Make sure not to mix them up. Let's see what mkvinfo shows for our anime.

$ mkvinfo Paprika.2006.Bluray.576p.x264-BTC.mkv
| + A track
|  + Track number: 2 (track ID for mkvmerge & mkvextract: 1)
|  + Track UID: 2617432213
|  + Track type: audio
|  + Enabled: 1
|  + Default flag: 1
|  + Forced flag: 0
|  + Lacing flag: 1
|  + MinCache: 0
|  + Timecode scale: 1
|  + Max BlockAddition ID: 0
|  + Codec ID: A_AC3
|  + Codec decode all: 1
|  + Default duration: 32.000ms (31.250 frames/fields per second for a video track)
|  + Language: und
|  + Audio track
|   + Sampling frequency: 48000
|   + Channels: 6

Mkvinfo explicitly mentions the track number to use when manipulating the container. Also note that, unlike mediainfo, it does show a Language entry, set to und - 'undefined'.

Setting audio or subtitle tracks as default

Now let's look at mkvmerge. It will output the result of its operations to a new file. I'll use a dual-audio rip of the Studio Ghibli classic Spirited Away on which the English audio track has been set to default. We will switch this to Japanese.

$ mkvmerge -o test.mkv --default-track 2 Spirited.Away.2001.Dual-Audio.Ac3.DVDRip.x264.mkv

Now Japanese will be set as the default audio stream:

$ mediainfo test.mkv |grep -A 2 Japanese
Language                                 : Japanese
Default                                  : Yes

Kodi will pick up the Japanese audio as default next time. No more fiddling.

Defining audio or subtitle language

Remember the Paprika rip? It had its audio (and subtitle track) undefined, this will confuse Kodi - it can't tell what language both tracks are in. Let's fix this.

$ mkvmerge -o test.mkv --language 1:jpn --language 2:eng Paprika.2006.Bluray.576p.x264-BTC.mkv
$ mkvinfo test.mkv
Audio
ID                                       : 2
Format                                   : AC-3
Format/Info                              : Audio Coding 3
Mode extension                           : CM (complete main)
Format settings, Endianness              : Big
Codec ID                                 : A_AC3
Duration                                 : 1h 30mn
Bit rate mode                            : Constant
Bit rate                                 : 640 Kbps
Channel(s)                               : 6 channels
Channel positions                        : Front: L C R, Side: L R, LFE
Sampling rate                            : 48.0 KHz
Bit depth                                : 16 bits
Compression mode                         : Lossy
Stream size                              : 414 MiB (19%)
Language                                 : Japanese
Default                                  : Yes
Forced                                   : No

Text
ID                                       : 3
Format                                   : UTF-8
Codec ID                                 : S_TEXT/UTF8
Codec ID/Info                            : UTF-8 Plain Text
Language                                 : English
Default                                  : Yes
Forced                                   : No

VoilĂ , there you have it.

Generating Kodi smart playlists based on Matroska container properties

As an added bonus, you can build a smart playlist in Kodi based on the language properties. For example, my movie collection sits in one folder, and I have a smart playlist for Japanese movies that is generated based on the audio track being Japanese:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<smartplaylist type="movies">
  <name>Japanse cinema</name>
  <match>all</match>
  <rule field="audiolanguage" operator="is">
    <value>jpn</value>
  </rule>
  <rule field="path" operator="startswith">
    <value>/media/films/</value>
  </rule>
  <order direction="ascending">sorttitle</order>
</smartplaylist>

This can all be configured through Kodi's GUI.

Stripping audio streams

If space is at a premium, you can strip audio tracks; some rips are particularly generous with them. Let's return to the Spirited Away dual-audio rip. We set the track with ID 2 (Japanese audio) as default before, now we'll retain it as the only audio stream.

$ mkvmerge -a 2 -o test.mkv Spirited.Away.2001.Dual-Audio.Ac3.DVDRip.x264.mkv

Now compare the original rip and the new single audio track file:

$ ll *mkv
-rw-r--r-- 1 anon anon 2.6G Jan 27 20:30 Spirited.Away.2001.Dual-Audio.Ac3.DVDRip.x264.mkv
-rw-r--r-- 1 anon anon 2.2G Mar 30 16:07 test.mkv

As you can see this saves some 400 MB. Size gains will mostly be in that order (unless you're stripping multiple or heavy audio tracks).

$ mkvmerge -a 1 -s 2 -o test.mkv --language 1:jpn Akira.1988.576p.Dual-Audio.Ac3.x264.mkv 
[...]
$ ll *mkv
-rw-r--r-- 1 anon anon 3.2G Jun 21 16:39 Akira.1988.576p.Dual-Audio.Ac3.x264.mkv
-rw-r--r-- 1 anon anon 2.6G Jun 21 16:50 test.mkv

Bonus: merging multiple Matroska files into one

I'll throw this in because this might come in handy at some point, and it turns out you cannot just concatenate multiple video files into one like you might with e.g. regular text files and cat. Mkvmerge can do this, but you need to append all other files to the first input file.

$ mkvmerge -o output.mkv input-1.mkv +input-2.mkv +input-3.mkv