Sunday, June 29, 2008

HOWTO: Remux .mkv to .m2ts on linux

A super fast'n'easy way to convert .mkv to a PS3 accepted format without any quality loss.

The script below can be used to remux a "standard" .mkv matroska file to a AVCHD .m2ts file which plays perfectly fine on the Sony PS3 for example. This is possible by using the great software tsmuxer by SmartLabs.


Updates:
  • changed to the native linux version of tsmuxer
  • support for muliple audio lang

Requisites

tsMuxer: http://www.videohelp.com/tools/tsMuxeR
mkvtoolnix: http://www.videohelp.com/tools/MKVtoolnix
dcadec: http://www.videolan.org/developers/libdca.html
aften: http://aften.sourceforge.net/

Installation

1. Make sure the apps above are installed, mkvtoolnix should be available from your dist repo.. i.e. apt-get
2. Copy the script below for example to /usr/local/bin/mkvtom2ts.sh and make it executable.
3. Edit the preferred default language list
4. Test it! mkvtom2ts.sh movie.mkv


#!/bin/bash
#
# mkvtom2ts.sh - a simple wrapper around the tsmuxeR
# Creates a m2ts from a "standard" mkv (assuming video is MPEG4, and sound is AC3 or DTS)
#
# v0.1 initial version
# v0.2 added DTS support
# v0.3 changed to tsmuxer linux version + added multiple audio lang support
#
# Usage: mkvtom2ts filename.mkv
#

AUDIO_LANGS="eng und swe"


BASENAME=$(basename "$1" .mkv)
DEST_FILE=$BASENAME.m2ts

MPEG4_TRACK_NO=`mkvinfo "$1" | grep V_MPEG4/ISO/AVC -B10 | grep Track\ number\:\ | awk '{ print $5 }'`

for AUDIO_LANG in $AUDIO_LANGS
do
AC3_TRACK_NO=`mkvinfo "$1" | grep A_AC3 -B10 -C3 | grep Language\:\ $AUDIO_LANG -B13 | grep Track\ number\:\ | awk '{ print $5 }'`
DTS_TRACK_NO=`mkvinfo "$1" | grep A_DTS -B10 -C3 | grep Language\:\ $AUDIO_LANG -B13 | grep Track\ number\:\ | awk '{ print $5 }'`
if [ -n "$AC3_TRACK_NO" -o -n "$DTS_TRACK_NO" ]
then
break
fi
done

echo "Video(V_MPEG4/ISO/AVC) track no : $MPEG4_TRACK_NO"
echo "Audio(A_AC3) $AUDIO_LANG track no : $AC3_TRACK_NO"
echo "Audio(A_DTS) $AUDIO_LANG track no : $DTS_TRACK_NO"

#audio ac3->direct muxing
if [[ $AC3_TRACK_NO -gt "0" ]]
then
echo "Found ac3 track, muxing directly..."
rm -f mux.meta
echo "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr" >>mux.meta
echo "V_MPEG4/ISO/AVC, "$1", level=4.1, insertSEI, contSPS, track=$MPEG4_TRACK_NO, lang=eng" >>mux.meta
echo "A_AC3, "$1", track=$AC3_TRACK_NO, lang=eng" >>mux.meta
tsMuxeR mux.meta $DEST_FILE
rm -f mux.meta
else
if [[ $DTS_TRACK_NO -gt "0" ]]
then
echo "No ac3 but dts, converting to ac3.."
mkvextract tracks "$1" $DTS_TRACK_NO:"$BASENAME.dts" $MPEG4_TRACK_NO:"$BASENAME.mpeg4"
dcadec -r -o wavall "$BASENAME.dts" > "$BASENAME.wav"
aften "$BASENAME.wav" "$BASENAME.ac3"
echo "Muxing..."
rm -f mux.meta
echo "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr" >>mux.meta
echo "V_MPEG4/ISO/AVC, "$BASENAME.mpeg4", level=4.1, insertSEI, contSPS, track=1, lang=eng" >>mux.meta
echo "A_AC3, "$BASENAME.ac3", track=1, lang=eng" >>mux.meta
tsMuxeR mux.meta $DEST_FILE
rm -f mux.meta $BASENAME.dts $BASENAME.wav $BASENAME.ac3 $BASENAME.mpeg4
else
echo "No ac3 or dts, exiting..."
fi
fi


26 comments:

Unknown said...

Great work man.
I had a slight problem with the script though and thought I should report it.
It concerns the nifty language-selector thing. The file i wanted to convert had the language set to "und", so it was not recognized by the script. To correct this I modified the AUDIO_LANG variable to: AUDIO_LANG="eng\|\|und" so that it greps for one of several languages. Yes, it is kind of ugly, and I don't know if it creates trouble in other cases, but it works for me.

Once again: Thanks man
// Johan

Unknown said...

The script works great :) There is also a Linux version of tsmuxer available now as well, but the script is still very useful with it :)

-Aaron

. said...

Thanks!

I've now updated the script to use the native linux version + added support for multiple audio languages

Unknown said...

Excellent script... It was a pain getting tsMuxeR to work with CentOS 5.2. The script worked great!! Now I can call this script after a news group download and export it to my PS3.

Johannes said...

Any word on subtitles yet? :-)

Unknown said...

This works brilliantly! I've been playing around trying to get wine to work with tsmuxer but this is now no longer necessary!

Installed mkvtoolnix under Ubuntu and with your script it works great.

thank you thank you.

Unknown said...

The only thing that I did change was to include --split-size in MUXOPT like this:

echo "MUXOPT --split-size=1gb ....

now it works on FAT32 for files which would have been bigger than 4GB.

Awesome :)

Anonymous said...

Hi!
I have read on the tsMuxer site that the linux version is only 1.7.3(b).

But version 1.7.6(b) seems to have at least one important bug fixed:

- bug fixed: some H.264 streams in version 1.7.1/2/3 did not work in PS3. It is the same problem it was corrected in version 1.7.3. Fixed again.

So is version 1.7.3(b) still ok?

Thanks!

C

Anonymous said...

Hi I just tried your script with tsMuxer 1.7.3(b) Linux to make a m2ts file. I can play the file using mplayer no problems but when I try to stream it to PS3 using mediatomb it does not play. I am using Ubuntu 8.04.1.

I then used tsMuxeR 1.8.4(b) in Windows Vista and then copied the resulting m2ts file to my Ubuntu partition to stream with mediatomb. This file was able to play fine on the PS3 no problems at all.

Does anyone have any experience with the Linux version of tsMuxeR and mediatomb? I will retry when the newest version of tsMuxeR is released for Linux.

Unknown said...

Sanjay I have noticed similar strange problems when using the linux version of tsMuxer. I use the win32 version for now.

. said...

Hi friends!

Sorry for not updating frequently!

1. Subtitles are very tricky (impossible?) to fix until Sony allows them to be streamed. Currently subtitles is only working if you create a bluray image. This sucks big time, but if you're interested, there are guides out there that will show you how to achieve this by using tsmuxer.
Still this means that you have to copy or burn to be able to watch, no streaming yet :( .

2. Some of you reported problems with the linux version or tsmuxer. I will "revert" the script to make use of the windows version using wine. I had issues as well, I will update the script in a while.

Unknown said...

The script made tings alot easier for me,thanks. But i have a similar problem as reported above; when i use mediatomb to stream it, my PS3 says that the data is damaged. but when i download the movie to my PS3 it works great.
I read the post above; that it works with the windows version so I modified it to use that instead wit wine. but then the PS3 said that the data was not supported and when i used "file" on the movie there was no info but "data". but the output was similar to the linux version during muxing, no error messages at all.
any clues??
Do I need to modify mediatomb, I've already configured the mime types for m2ts to "video/avchd".

Unknown said...

Never mind, just figured it out by reading the mediatomb log. It turns out that the file permisions was wrong. it was only readable by the owner and not by root. and the mediatomb was of course running as a deamon, thus not as me.
Adding a simple "chmod a+r $DEST_FILE" at the end of a conversion solved my problem.

I don't want to start counting the hours I've spent on trying to solve this.

So thank you for the great script.

Gunstick said...

the script cannot handle big wav files. I corrected it like this:
dcadec -r -o wavall "$BASENAME.dts" |
aften - "$BASENAME.ac3"

also I have yet to notice problems with the linux version of tsMuxeR

Anonymous said...

I now have this script working for me in Linux using the linux version of tsMuxer and mediatomb. I can't believe the problem was as simple as changing the properties of the file after. Thanks to the person that mentioned that!!

doktor_a said...

Hey dirkadirka, I'm having a tough time getting tsMuxeR to work with CentOS 5.2 also. I keep getting an error indicating "/usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.9' not found". Is this the problem you were having, and if so, how did you fix it?

ZeRo said...

hi, i've see a desync between audio / video.
I've resolve adding fps=25 in
echo "V_MPEG4/ISO/AVC, "$1", fps=25, .....
and timeshift=1000ms in echo "A_AC3, "$1", timeshift=1000ms, ....
thank's

ZeRo said...
This comment has been removed by the author.
Alex said...

Hi dear,
I view the script truncated on AC3_TRACK_NO line.

Please can you attache a downloadble version.
Thankz
alex

Alex said...

Sorry only a visualization problem.

Gunstick said...

I came across a video with 2 alternate tracks both in AC3. That makes the script crash. I added an exit into the awk:

..... grep Track\ number\:\ | awk '{ print $5;exit }'`

jstobern said...

Excellent script, works on Ubuntu 10.04 LTS with aften 0.0.8, libdca 0.0.5, tsMuxer 1.10.6 and mkvtoolnix 3.0.0. With Gunstick's change to pipe the output of dcadec to aften the script works flawlessly on all the mkv files that I've every downloaded.

Once again, thanks for putting this together.

-Jens.

Unknown said...
This comment has been removed by the author.
Unknown said...

On Ubuntu 10.04 I got the following error:
Video(V_MPEG4/ISO/AVC) track no : 1
Audio(A_AC3) und track no : 2
Audio(A_DTS) und track no :
~/bin/mkvtom2ts.sh: 62: [[: not found
~/bin/mkvtom2ts.sh: 62: [[: not found
No ac3 or dts, exiting...

By removing the extra brackets (making them single) the script runs but has problems with filenames including spaces as tsMuxeR cannot find the file. Any ideas?

Ron said...

Great script. Thanks! I modified mine to 'prefer' DTS tracks when they have a lower track number than an AC-3 track. A lot of my files have DTS primary audio and AC-3 commentary, and I wanted the primary audio.

Unknown said...

Awesome script! I am running it right now and awaiting result :). One this I noticed was that if the audio track doesn't specify language, the script fails to parse the audio track number. I added the following lines right after the language track search loop.


if [ -z "$AC3_TRACK_NO" -a -z "$DTS_TRACK_NO" ] ; then
echo "No language specific track found. Going with the default one."
AUDIO_LANG=
AC3_TRACK_NO=`mkvinfo "$1" | grep A_AC3 -B10 -C3 | grep Track\ number\:\ | awk '{ print $5 }'`
DTS_TRACK_NO=`mkvinfo "$1" | grep A_DTS -B10 -C3 | grep Track\ number\:\ | awk '{ print $5 }'`
fi