MediaTomb and PS3: The Lazy Man's solution

I've been using MediaTomb with my PlayStation 3 for a while now, and it's been working just peachy. However, it takes a lot of work keeping up with the different media formats in the library, and especially those media which don't play by default on the PS3: QPeL MPEG4, RealMedia, Flash, DVD ISOs ... After creating the umptieth transcoding profile fit for one specific filetype, I wondered if I could just create one single transcoding profile that fits everything I throw at it.

This article has been superseded by a new one, describing a way to combine transcoding and remuxing for HD content.

The thing that pushed me to try this was the ongoing suckification of the PS3's media center capabilities. I have no idea how or why, but the newer my firmware gets, the less stable the media player gets when it comes to supporting different media types. First there was the mp4 choppy playback issue that Sony refuses to acknowledge, and lately even plain divx/xvid starts to stutter now and then, seemingly randomly. Ironically, a transcoded mpeg2 stream of 10 times the bandwidth of the source divx plays just fine. Quality loss is - as far as I can tell, and my eyes aren't that bad yet - neglectable, so why not transcode everything and be done with it?

Such a profile would make the MediaTomb config a lot cleaner! Here's what mine looked like after cleaning it up to work with a single catch-all transcoding profile:

<?xml version="1.0" encoding="UTF-8"?>
<config version="2" xmlns="http://mediatomb.cc/config/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/2 http://mediatomb.cc/config/2.xsd">
  <server>
    <interface>eth0</interface>
    <port>50000</port>
    <ui enabled="yes" show-tooltips="yes">
      <accounts enabled="no" session-timeout="30">
        <account user="mediatomb" password="mediatomb"/>
      </accounts>
    </ui>
    <name>MediaTomb</name>
    <udn>uuid:05fb1733-b4bb-449f-9995-xxxx220dxxxx</udn>
    <home>/etc/mediatomb</home>
    <webroot>/usr/share/mediatomb/web</webroot>
    <storage caching="yes">
      <sqlite3 enabled="yes">
        <database-file>mediatomb.db</database-file>
      </sqlite3>
      <mysql enabled="no">
        <host>localhost</host>
        <username>mediatomb</username>
        <database>mediatomb</database>
      </mysql>
    </storage>
    <protocolInfo extend="yes"/>
    <extended-runtime-options>
      <ffmpegthumbnailer enabled="no">
      <thumbnail-size>128</thumbnail-size>
        <seek-percentage>5</seek-percentage>
        <filmstrip-overlay>yes</filmstrip-overlay>
        <workaround-bugs>no</workaround-bugs>
      </ffmpegthumbnailer>
      <mark-played-items enabled="no" suppress-cds-updates="yes">
        <string mode="prepend">*</string>
      </mark-played-items>
    </extended-runtime-options>
  </server>
  <import hidden-files="no">
    <filesystem-charset>UTF-8</filesystem-charset>
    <metadata-charset>ISO-8859-15</metadata-charset>
    <scripting script-charset="UTF-8">
      <common-script>/usr/share/mediatomb/js/common.js</common-script>
      <playlist-script>/usr/share/mediatomb/js/playlists.js</playlist-script>
      <virtual-layout type="js">
        <import-script>/usr/share/mediatomb/js/import.js</import-script>
        <dvd-script>/usr/share/mediatomb/js/import-dvd.js</dvd-script>
      </virtual-layout>
    </scripting>
    <mappings>
      <extension-mimetype ignore-unknown="no">
        <map from="mp3" to="audio/mpeg"/>
        <map from="wmv" to="video/transcode"/>
        <map from="flv" to="video/transcode"/>
        <map from="mkv" to="video/transcode"/>
        <map from="rm"  to="video/transcode"/>
        <map from="iso" to="video/transcode"/>
        <map from="ogm" to="video/transcode"/>
        <map from="mp4" to="video/transcode"/>
        <map from="avi" to="video/transcode"/>
      </extension-mimetype>
      <mimetype-upnpclass>
        <map from="audio/*" to="object.item.audioItem.musicTrack"/>
        <map from="video/*" to="object.item.videoItem"/>
        <map from="image/*" to="object.item.imageItem"/>
      </mimetype-upnpclass>
      <mimetype-contenttype>
        <treat mimetype="audio/mpeg" as="mp3"/>
        <treat mimetype="video/transcode" as="mpg"/>
      </mimetype-contenttype>
    </mappings>
    <online-content>
      <YouTube enabled="yes" format="mp4" hd="no" refresh="28800" update-at-start="yes" purge-after="604800" racy-content="exclude">
        <uploads user="MuppetsStudio"/>
        <favorites user="MyOwnYTUser"/>
      </YouTube>
    </online-content>
  </import>
  <transcoding enabled="yes">
    <mimetype-profile-mappings>
      <transcode mimetype="video/transcode" using="multifunctional"/>
    </mimetype-profile-mappings>
    <profiles>
      <profile name="multifunctional" enabled="yes" type="external">
        <mimetype>video/mpeg</mimetype>
        <first-resource>yes</first-resource>
        <agent command="/usr/local/bin/mediatomb-multifunctional.sh" arguments="%in %out"/>
        <buffer size="102400" chunk-size="51200" fill-size="20480"/>
      </profile>
    </profiles>
  </transcoding>
</config>

As you can tell, I map everything that is not mp3 (because mp3 is the only audio that I have, and Just Works on the PS3) to video/transcode, and tell MediaTomb to transcode that using the /usr/local/bin/mediatomb-multifunctional.sh script. And here's that script then:

#!/bin/bash
#
# General all-covering MediaTomb transcoding script.
# This turns EVERYTHING in an mpeg2 stream for PS3 use.
#
# v0.1  2010/06/05
#
#############################################################################

# Change this to enable different subtitle languages.
SUBS="nl,en"

# Change this line to set the average bitrate.
# Use something like 8000 for wired connections; lower to 2000 for wireless.
AVBIT=8000

# Change this line to set the maximum bitrate.
# Use something like 12000 for wired connections; lower to 5000 for wireless.
MVBIT=12000

# Change this line to set the audio bitrate in kbps. 256 is nice.
AABIT=256

# Change this line to set your favourite subtitle font.
SFONT="/etc/mediatomb/DejaVuSans.ttf"

# Change this line to set the size of subtitles. 25 is okay.
SUBSIZE=20

# Enable downscaling of HD content to 720 pixels wide (DVD format)?
DOWNSCALE=1

# If downscaling is enabled, anything over this width will be downscaled.
MAXSIZE=900

# Enable logging to file?
LOGGING=1

# If logging is enabled, log to which file?
LOGFILE="/var/log/mediatomb-transcode.log"

#############################################################################
# Do not change anything below this line.
#############################################################################
# Variables
#############################################################################

FILE=$1

MENCODER=$(which mencoder)
MEDIAINFO=$(which mediainfo)
LSDVD=$(which lsdvd)

MENCOPTS="-oac lavc -ovc lavc -of mpeg -lavcopts \
abitrate=${AABIT}:vcodec=mpeg2video:keyint=1:vbitrate=${AVBIT}:\
vrc_maxrate=${MVBIT}:vrc_buf_size=1835 \
-mpegopts muxrate=12000 -af lavcresample=44100 "
SUBOPTS="-slang ${SUBS} "
SRTOPTS="-font ${SFONT} -subfont-autoscale 0 -subfont-text-scale ${SUBSIZE} -subpos 100 "
SIZEOPTS="-vf harddup,scale=720:-2 "
NOSIZEOPTS="-vf harddup "
S24FPS="23.976"
S24OPT="-ofps 24000/1001"
S30FPS="29.97"
S30OPT="-ofps 30000/1001"
MKVOPTS="-aid 0 -sid 0 "

WIDTH=""
SFPS=""
COMBINEDOPTS=""

#############################################################################
# Functions
#############################################################################

function log {
        if [ "${LOGGING}" == "1" ] ; then      
                echo -e "$(date +'%Y/%m/%d %H:%m:%S') \t $1" >> ${LOGFILE}
        fi
}

function mediainfo {
        MIOUT=$(mktemp /tmp/tmp.mediainfo.XXXXXX)
        log "Tempfile is ${MIOUT}"     
        ${MEDIAINFO} "${FILE}" > ${MIOUT}
        WIDTH=$(grep -e "^Width" ${MIOUT} | sed -e 's/[ ]*//g' -e 's/.*:\(.*\)pixels/\1/')
        SFPS=$(grep -e "^Frame" ${MIOUT} | sed -e 's/[ ]*//g' -e 's/.*:\(.*\)fps/\1/')
        log "Width of ${WIDTH} and FPS of ${SFPS} detected."
        rm -f "${MIOUT}"
}

function setopts {
        SUBLINK=$(mktemp /tmp/tmp.mmsublink.XXXXXX)
        if [ "${DOWNSCALE}" == "1" -a ${WIDTH} -gt ${MAXSIZE} ] ; then
                log "Rescaling to 720 pixels."
                COMBINEDOPTS="${COMBINEDOPTS} ${SIZEOPTS}"
        else
                log "Rescaling disabled or file within limits."
                COMBINEDOPTS="${COMBINEDOPTS} ${NOSIZEOPTS}"
        fi     
        if [ "${SFPS}" == "${S24FPS}" ] ; then
                log "Framerate adjusted for mencoder."
                COMBINEDOPTS="${COMBINEDOPTS} ${S24OPT}"
        else if [ "${SFPS}" == "${S30FPS}" ] ; then
                COMBINEDOPTS="${COMBINEDOPTS} ${S30OPT}"
        else
                log "Framerate acceptable for mencoder."
        fi
        fi
        if [ -e "$(echo $FILE | sed 's/...$/sub/')" ] ; then
                SUB=$(echo $FILE | sed 's/...$/sub/')
                rm $SUBLINK && ln -s "${SUB}" "${SUBLINK}"
                log "Subtitle found: ${SUB}"
                COMBINEDOPTS="-sub ${TEMPSUB} ${COMBINEDOPTS}"
        else if [ -e "$(echo $FILE | sed 's/...$/srt/')" ] ; then
                SUB=$(echo $FILE | sed 's/...$/srt/')
                rm $SUBLINK && ln -s "${SUB}" "${SUBLINK}"
                log "Subtitle found: ${SUB}"
                COMBINEDOPTS="-sub ${SUBLINK} ${COMBINEDOPTS}"
        else
                log "No external subtitles."
        fi
        fi
}

#############################################################################
# Actual code
#############################################################################

log "Starting MediaTomb Multifunctional Transcoder."
find /tmp/tmp.mmsublink.* -mtime +1 -exec rm {} \;

FEXT=$(echo $FILE | sed 's/.*\.//')

if [ "$(echo $FILE | grep 'http://')" != "" ] ; then
        FEXT="URL"
fi

case $FEXT in
        "iso")
                log "ISO file specified: \"${FILE}\""
                CHAPTER=$(${LSDVD} "${FILE}" | grep Longest | sed 's/.* //')
                log "Chapter ${CHAPTER} selected..."
                COMBINEDOPTS="${MENCOPTS} ${SUBOPTS} ${SIZEOPTS}"
                log "Starting mencoder:"
                log "${MENCODER} -dvd-device \"${FILE}\" dvd://${CHAPTER} ${COMBINEDOPTS} -o \"$2\""
                exec ${MENCODER} -dvd-device "${FILE}" dvd://${CHAPTER} ${COMBINEDOPTS} -o "$2" &>/dev/null &
                ;;
        "ogm" | "mkv")
                log "OGM/MKV file specified: \"${FILE}\""
                mediainfo
                COMBINEDOPTS="${MKVOPTS} ${MENCOPTS} ${SRTOPTS}"
                setopts
                log "Starting mencoder:"
                log "${MENCODER} \"${FILE}\" ${COMBINEDOPTS} -o \"$2\""
                exec ${MENCODER} "${FILE}" ${COMBINEDOPTS} -o "$2" &>/dev/null &
                ;;
        "URL")
                log "URL specified: \"${FILE}\""
                log "Starting mencoder:"
                log "ffmpeg -i \"${FILE}\" -acodec mp2 -vcodec mpeg2video -f mpegts -b ${AVBIT}000 -ab ${AABIT}k -y \"$2\""
                exec ffmpeg -i "${FILE}" -acodec mp2 -vcodec mpeg2video -f mpegts -b ${AVBIT}000 -ab ${AABIT}k -y "$2" &>/dev/null &
                ;;
        *)
                log "Regular file specified: \"${FILE}\""
                mediainfo
                COMBINEDOPTS="${MENCOPTS} ${SRTOPTS}"
                setopts
                log "Starting mencoder:"
                log "${MENCODER} \"${FILE}\" ${COMBINEDOPTS} -o \"$2\""
                exec ${MENCODER} "${FILE}" ${COMBINEDOPTS} -o "$2" &>/dev/null &
                ;;
esac   
log "Script ended."

As you can tell, you need mencoder, ffmpeg, mediainfo and lsdvd. Why ffmpeg? Because mencoder on my AMD64 system didn't like the codec in YouTube's mp4s. According to the MediaTomb docs, ffmpeg doesn't like writing to FIFO; this is true, since ffmpeg temporarily opens its output file read-only before starting to write to it. If the output file is a (new) FIFO, nothing is in it yet, so the call blocks on this. This is fixed by using the "-y" switch, which basically tells ffmpeg to write to the given target, regardless of whether it already exists or not, skipping the read-check.

This script checks for various things. First of all, mediainfo is used to determine video dimensions and framerate. Mencoder doesn't like floating point framerates, so 24000/1001 and 30000/1001 are being used for 23.976 and 29.97 respectively. Since my CPU (AMD 5050E, dualcore 2.5) isn't powerful enough to transcode HD content on the fly, I added an option to allow downscaling of content to 720 pixels wide (basically DVD format). It also checks for the presence of subtitles, and embeds them in the stream if found, using the specific options (font, size) you can set in the first part of the script.

My config has YouTube enabled (yes! I made the step to mediatomb 0.12+!); add your own YT user in the config to get to see your own favourites. And really, check out the MuppetsStudio content - it's hilarious :-)

Those of you who have read through the script will have noticed I do a very dirty thing to get subtitles working: subtitles are symlinked to a tempfile, and this is being passed to mencoder. The reason for this is that I still haven't figured out how I can pass subtitle filenames with spaces and/or special characters in it, inside the COMBINEDOPTS parameter without bash treating every word as a separate argument. As far as I know bash, this isn't possible. I'm open for suggestions on how to clean this up - I've cracked my head at it for several hours and haven't found a solution.

I've only tested this for a few days now so there might still be bugs or tweaks needed in the script, but so far anything I've thrown at it works: realmedia, divx with and without qpel, dvd isos and ogm. I'll do some more testing later on; check back for revisions of the script now and then - or tweak it yourself, and let me know what you did to improve it.

Enjoy!

Tags:
Nice job!

Your posts on Mediatomb tweaks are always nice! Good job.

I'm having a problem with a couple of avi movies streaming to my PS3 where I get no sound output even though its a mp3 track. I tried running your script to transcode it, but for some reason it didn't work on my PS3 (corrupted data error). In these cases, is it possibçe/viable to just work on the audio track of the video or it's just easier to re-code the file "offline"?

I also tried running it with a MKV blu-ray rip but my processor (Intel Dual Core e3300) couldn't take the load and the video was crippled and freezing every 3 seconds or so. Do you think that could be solved by tweaking the buffer config on mencoder?

Thanks once again :)

Submitted by Wagner Melo (not verified) on Sat, 07/08/2010 - 00:37.
Remux

Hello there,

The script should handle all AVIs just fine - if the PS3 reports the data being corrupted, I'd try running the mencoder command manually to check if there's a problem there. Perhaps there's something about the file that mencoder doesn't like either.

As for the mkvs: I know this is a problem, and I'm working on a script that can remux the files instead of transcoding them! That means maximum quality at neglectable processing power. I still need to tweak it a bit before it's ready to be released, but that shouldn't be too long. Check back in a week or so :-)

Submitted by Lennert on Sat, 07/08/2010 - 11:44.
Version 2 ?

I also am using Ubuntu 10.04 (UbuntuStudio).
But the config.xml as version 2 specified which is not found on the mediatomb web site.
So when starting the daemon, it fails with a version "2" not found...

Changed version 2 to 1 (and other changes mentioned above), daemon starts fine but the transcode script never got executed (even if it's located in good directory and execute bit is set for all on the script).

Also changed home directory to /var/lib/mediatomb according to ubuntu's config.xml in package.

mediatomb installed is maintained by ubuntu community which is version 0.12.0.

Submitted by TiPaul (not verified) on Mon, 19/07/2010 - 17:37.
slight error

There is an error in config.xml
Line
/usr/share/mediatomb/import.js
should be
/usr/share/mediatomb/js/import.js
rodrigo

Submitted by Rodrigo (not verified) on Thu, 15/07/2010 - 09:30.
Whoops

Correct - changed it. I use a custom script, so not the one in /usr/share - I replaced it with this one because people would get errors because my custom script wasn't present on their machine. Guess I should have looked better when typing. Thanks :-)

Submitted by Lennert on Thu, 15/07/2010 - 10:26.
Possible to Pause/Forward

Hey,

i recently tried your script - and it works amazingly. Thanks for the effort you put in it.
Put, i cant pause any video file that plays on my ps3 - i think its because of the on-the-fly transcoding, or is there a chance that i maybe did something wrong?

mfg
OliA

Submitted by OliA (not verified) on Wed, 30/06/2010 - 00:55.
Workaround

Correct - the PS3 cannot forward/rewind transcoded streams. You can pause them however via a silly workaround: press the PS-button on your controller to pause/unpause :-)

Submitted by Lennert on Wed, 30/06/2010 - 10:27.
Mediatomb Config File

Thanks for writing this up! Transcoding everything is a fantastic way to make using mediatomb easier. I am still in the process of testing it but when I was reading over your mediatomb configuration file I noticed that the mappings section is repeated an additional time so it actually appears twice. It actually might make things easier, for some people, if you posted the configuration file as a diff.

Submitted by Brian Murray (not verified) on Sat, 19/06/2010 - 17:15.
Yikes

Good catch. There's no reason for this - probably a copy/paste fail. Fixed it. Thanks for the comment!

Submitted by Lennert on Sat, 19/06/2010 - 19:17.
Great Config

Thanks for the config. It helped, I'll admit I'm too lazy and didn't really want to read the Mediatomb help pages to try and figure out the transcoding bit. Unfortunately, I found that some of my hi quality videos (with 5.1 channel audio) are being transcoded to a lower quality 2.1 channel video. I still use the config though, only for mp4s, mkvs and iso's. Thanks again!

Submitted by Ravi (not verified) on Wed, 16/06/2010 - 12:09.
Error with js support

I am using version 0.12.0 on Ubuntu Lucid Lynx x86 and I get the following:
2010-06-14 22:34:50 INFO: Checking configuration...
2010-06-14 22:34:50 INFO: Setting filesystem import charset to UTF-8
2010-06-14 22:34:50 INFO: Setting metadata import charset to ISO-8859-15
2010-06-14 22:34:50 INFO: Setting playlist charset to UTF-8
2010-06-14 22:34:50 ERROR: MediaTomb was compiled without js support, however you specified "js" to be used for the virtual-layout.

Do you know why?

Also if you know anything related to Samsung 7 series DLNA support would be great thanks.

Submitted by Someone (not verified) on Mon, 14/06/2010 - 21:37.
Builtin

Try using <virtual-layout type="builtin">. Silly though, that the Ubuntu maintainer disables such a feature.

Submitted by Lennert on Tue, 15/06/2010 - 07:48.
I think things got even worse :(

Now I get this:
2010-06-21 19:05:55 ERROR: Failed to get XML content from YouTube service

And not even files that play with the normal config.xml, like the avis, are playing now.

Sorry to disturb you but would be very cool if you know how to fix it.

Submitted by Someone (not verified) on Mon, 21/06/2010 - 18:07.
YouTube

Check your mediatomb and config file. Was it compiled with YouTube support? If no, remove that section from the config. If yes... you did change the "MyOwnYTUser", right? If you don't have a YouTube user account, just remove that line as well. After all, MuppetsStudio is all one needs. ;-)

Submitted by Lennert on Tue, 22/06/2010 - 08:40.
lazy man's solution

I'm running mediatomb from a ubuntu headless server, I tried your lazy man's solution config and got some errors that I was unable to fix. Namely 2010-06-12 11:37:56 ERROR: /etc/mediatomb/import-custom-0.12.js : 20 x No such file or directory. I am wondering if this file can be found somewhere on the mediatomb site, or whether I am expected to know how to make this file myself or if mediatomb should have generated the file. Please let me know what I am supposed to do about import-custom-0.12.js and possibly make it available for download someplace! I look forward to using this solution for my ps3, thank you!

Submitted by bluefox83 (not verified) on Sat, 12/06/2010 - 17:49.
Whoops

I forgot to change that in the article. Don't worry about that custom file - it's something I hacked up, starting from the default import.js, to match my specific filesystem layout.

I edited the config.xml to clean up the custom paths I use. My mediatomb is in /opt - I built my own .deb and prefer not to meddle in /usr - which is uncommon. All paths should be 'default' now. Sorry for the confusion.

Submitted by Lennert on Sat, 12/06/2010 - 21:57.

User login

Who's online

There is currently 1 user and 1 guest online.

Online users

  • Lennert