Convert MKV to MP4 in Ubuntu VOBSUB English VOBSUB Thai

You have videos using the MKV container but need them to use the MP4 container to, for example, stream from your Ubuntu computer to a Samsung tablet using DLNA (see my notes on streaming using minidlna). How to do the conversion in Ubuntu? Its rather easy, assuming the MKV contains H.264 encoded video.

A recommended approach is to use Handbrake. Has a simple to use GUI, and even a command line interface. But lets try something different ...

Another approach is to use mkvtomp4. This works well, and is what I've used to learn the steps below. Its a python script that conveniently calls the correct command line programs for the conversion. The problem I've had on occasions is extracting the correct audio track when there are multipled in the MKV. For example , my MKV has H.264 video, an English AC3 audio track and a Thai AAC audio track. I found mkvtomp4 would use the AAC audio track, when I wanted the English AC3 track. Luckily mkvtomp4 has the --dry-run option that prints the commands used. The following summarises the steps that mkvtomp4 takes so you can tailor the conversion to your needs (without using mkvtomp4).

First, install the necessary software: MP4Box (in gpac package), mkvextract (in mkvtoolnix package) and FFMPEG.

$ sudo apt-get install gpac mkvtoolnix ffmpeg

Remember that MKV and MP4 are just container formats. The video and audio in the containers can be created with different codecs. In my case the video in the MKV container is H.264 and the audio is AC3. The MP4 container commonly uses H.264 video and AAC audio. So the video does not need to be transcoded, only the audio (from AC3 to AAC). It would be even better (faster) if the MKV contained AAC audio.

The steps are to extract the video and audio tracks from the MKV container, transcode the tracks (if necessary) into H.264 and AAC, and then combine the resulting tracks putting them in a MP4 container. Note that the original MKV may have multiple audio tracks, e.g. in different languages. To view the track information use mkvinfo:

$ mkvinfo file.mkv
+ EBML head
|+ EBML version: 1
|+ EBML read version: 1
|+ EBML maximum ID length: 4
|+ EBML maximum size length: 8
|+ Doc type: matroska
|+ Doc type version: 2
|+ Doc type read version: 2
+ Segment, size 1192766636

info about chapters etc.

|+ Segment tracks
| + A track
|  + Track number: 1
|  + Track UID: 245466022
|  + Track type: video
|  + Lacing flag: 0
|  + Codec ID: V_MPEG4/ISO/AVC
|  + CodecPrivate, length 49 (h.264 profile: High @L3.0)
|  + Default duration: 40.000ms (25.000 fps for a video track)
|  + Default flag: 1
|  + MinCache: 1
|  + Video track
|   + Pixel width: 720
|   + Pixel height: 432
|   + Display width: 760
|   + Display height: 432
| + A track
|  + Track number: 2
|  + Track UID: 1695069656
|  + Track type: audio
|  + Lacing flag: 0
|  + Codec ID: A_AC3
|  + Language: eng
|  + Default flag: 1
|  + Audio track
|   + Sampling frequency: 48000
|   + Channels: 6
| + A track
|  + Track number: 3
|  + Track UID: 101896736
|  + Track type: audio
|  + Lacing flag: 0
|  + Codec ID: A_AAC
|  + CodecPrivate, length 2
|  + Language: tha
|  + Default flag: 0
|  + Audio track
|   + Sampling frequency: 48000
|   + Channels: 2
| + A track
|  + Track number: 4
|  + Track UID: 1616739605
|  + Track type: subtitles
|  + Lacing flag: 0
|  + Codec ID: S_VOBSUB
|  + CodecPrivate, length 349
|  + Language: eng
|  + Default flag: 0
| + A track
|  + Track number: 5
|  + Track UID: 1932451514
|  + Track type: subtitles
|  + Lacing flag: 0
|  + Codec ID: S_VOBSUB
|  + CodecPrivate, length 349
|  + Language: tha
|  + Default flag: 0
|+ Cluster

From the above example, note there are five tracks:

  1. Video: H2.64
  2. Audio: AC3 English
  3. Audio: AAC Thai
  4. Subtitle: VOBSUB English
  5. Subtitle: VOBSUB Thai

I want to extract tracks 1 and 2. Use mkvextract to do so:

$ mkvextract tracks file.mkv 1:file.mkv.h264
$ mkvextract tracks file.mkv 2:file.mkv.ac3

The video file (file.mkv.h264) can be included as is in the MP4 container. But the audio needs to be converted to AAC. For the conversion I'll use FFMPEG (other software, like MEncoder, should work as well):

$ ffmpeg -i file.mkv.ac3 -ac6 -acodec libfaac -ab 328k file.mkv.ac3.aac

The above command uses 6 channels in the output and a bit rate of 328kb/s. These and other options may be modified to suit your needs. Note that the audio conversion is the most time consuming step, usually taking minutes. The other steps should completed in seconds.

Now we have the two individual files for video (H.264) and audio (AAC), they need to be combined into a MP4 container. Use MP4Box for this:

$ MP4Box -add 'file.mkv.h264#video:trackID=1' -hint -fps 25.000 -add 'file.mkv.ac3.aac#audio:trackID=2' file.mp4

The above command adds the video track and the audio track. Thats it! Test by opening the MP4 in VLC or streaming to your Galaxy tab.