MythTV Transcoding (3): Transcoding for iPad Playback

I'm doing a series of posts here on automated transcoding of recordings in MythTV. The idea is to explain the basics, then evolve the design to end up with recordings suitable for playback on the iPad, which is a little more advanced.

  • The complete series of articles is available at this page

Last time I showed where you go in MythTV to edit the default job settings, and what happens when you hit the Transcode button in MythWeb or let MythTV transcode automatically after recording.

Today I’m going to continue the series by leaving MythTV to one side, and showing how to create a transcoded recording suitable for playback on an iPad (or other Apple device – iPod, iPhone, Mac OS X, etc). Next time we’ll incorporate this into MythWeb for the final result.

Before that, let’s look at the different ways that playback on Apple platforms might be achieved (more suggestions are welcome, in the comments):

  • Install the MythFrontend application natively onto an OS X device.
  • Install the VLC Media Player onto an OS X device (as it can handle the ASX Stream link in MythWeb) – in fact this is what I do on my own desktop Mac.
  • Install MythPodcaster, a Transcoder and RSS publisher, and subscribe to transcoded recordings in iTunes (leads to syncing them to the iPad).
  • Create a MythTV Job to transcode into H.264 format (compatible with all Apple platforms), and add links to the generated files in MythWeb.

It’s the last of these which I’m going to cover in this article. However an honourable mention must be made of MythPodcaster. First, most of the work here is taken from looking at what that excellent tool does. Second, if you don’t want to mess about editing MythWeb, then MythPodcaster has its own web interface for not only managing transcode schedules and profiles, but also browsing and playback. It really is an excellent tool I recommend you check out.

Each MythTV user job is configured as a command which can be executed at the shell command-line. That means the first thing to do is get transcoding working at the command-line for ourselves. The tool for this is ffmpeg, but we must compile a special version which can output H.264. The following instructions are for an Ubuntu system and based on the MythPodcaster InstallationOnMythBuntu page.

I’m going to build a custom version of ffmeg, separate to that installed with my Ubuntu system. The instructions below aren’t intended to be the cleanest solution, but get the job done.

sudo apt-get install build-essential git-core yasm checkinstall zlib1g-dev pkg-config

And we’ll do this work as the mythtv user in a new directory:

sudo mkdir -p /usr/local/lib/ffmpeg-264
sudo chown mythtv:mythtv /usr/local/lib/ffmpeg-264
sudo su - mythtv
cd /usr/local/lib/ffmpeg-264

Build the faac library:

cd /usr/local/lib/ffmpeg-264
wget http://downloads.sourceforge.net/project/faac/faac-src/faac-1.28/faac-1.28.tar.gz
tar -zxvf faac-1.28.tar.gz
cd faac-1.28
./configure --prefix=/usr/local/lib/ffmpeg-264 --enable-static --disable-shared
# some kind of gcc-compatibility bug which needs fixing
sed -i -e "s|^char \*strcasestr.*|//\0|" common/mp4v2/mpeg4ip.h
make && make install

Build the x264 library:

cd /usr/local/lib/ffmpeg-264
git clone git://git.videolan.org/x264.git
cd x264
./configure --prefix=/usr/local/lib/ffmpeg-264 --enable-static --disable-shared
make && make install

Build the libmp3lame library:

cd /usr/local/lib/ffmpeg-264
wget http://downloads.sourceforge.net/project/lame/lame/3.98.4/lame-3.98.4.tar.gz
tar -zxvf lame-3.98.4.tar.gz
cd lame-3.98.4
./configure --prefix=/usr/local/lib/ffmpeg-264 --enable-static --disable-shared
make && make install

Build ffmpeg:

cd /usr/local/lib/ffmpeg-264
wget http://www.ffmpeg.org/releases/ffmpeg-0.8.3.tar.gz
tar -zxvf ffmpeg-0.8.3.tar.gz
cd ffmpeg-0.8.3
./configure --prefix=/usr/local/lib/ffmpeg-264 --extra-version=static --disable-debug --enable-static --extra-cflags=--static --disable-ffplay --disable-ffserver --disable-doc --enable-gpl --enable-pthreads --enable-postproc --enable-gray --enable-runtime-cpudetect --enable-libfaac --enable-libmp3lame --enable-libx264 --enable-nonfree --enable-version3 --disable-devices --extra-ldflags=-L/usr/local/lib/ffmpeg-264/lib --extra-cflags=-I/usr/local/lib/ffmpeg-264/include
make && make install

To make life a little easier, I link to this new binary from a more memorable location:

exit # if you are still the "mythtv" user
sudo ln -s /usr/local/lib/ffmpeg-264/bin/ffmpeg /usr/local/bin/ffmpeg-264

Now we need a magic incantation for ffmpeg-264 which will result in an H.264 file suitable for iPad playback. A good source of possible command line options is the MythPodcaster trancoding profiles XML file. In this file, the various iPad profiles, as their names suggest, will ask for various formats and qualities of output (see each encoderArguments key).

These command line options in turn refer to ffmpeg presets (via -vpre) which should be shipped with ffmpeg in the ffpresets directory. Some of these might work, but I’m pretty happy with two presets from an older version of ffmpeg:

mkdir ~mythtv/.ffmpeg
cd ~mythtv/.ffmpeg
wget https://raw.github.com/FFmpeg/FFmpeg/release/0.6/ffpresets/libx264-main.ffpreset
wget https://raw.github.com/FFmpeg/FFmpeg/release/0.6/ffpresets/libx264-medium.ffpreset

One problem you might have with ffmpeg options is selection of an audio track in recordings with multiple soundtracks (for example normal, and audio-descriptive). There’s no easy way to know which you want (and in my settings I force the choice). Here’s what I settled on, which seems to work OK for SD content, and if you have others please add a comment, below:

-i <infile> -y -map 0:0 -map 0:1 -er 4 -f ipod -acodec libfaac -ac 2 -ab 128k \
    -ar 44100 -deinterlace -vcodec libx264 -vpre medium -vpre main -b 1200k \
    -bt 1200k -maxrate 1200k -bufsize 1200k -level 30 -r 30 -g 90 -async 2 \
    -threads 0 -v 0 <outfile>

These parameters are wrapped up in a script, making things easier for MythTV configuration. This file, called h264xcode is also placed in /usr/local/bin (and obviously, season this to taste, for your system’s recording directories):

#!/bin/bash

CHANID=$1
STARTTIME=$2

INDIR="/mnt/mythtv-video/Videos/MythTV"
OUTDIR="/mnt/mythtv-video/Videos/iPad"

PROG="time nice -n 19 /usr/local/bin/ffmpeg-264"
PARAMS="-y -map 0:0 -map 0:1 -er 4 -f ipod -acodec libfaac -ac 2 -ab 128k -ar 44100 -deinterlace -vcodec libx264 -vpre medium -vpre main -b 1200k -bt 1200k -maxrate 1200k -bufsize 1200k -level 30 -r 30 -g 90 -async 2 -threads 0 -v 0"

LOG="/var/log/mythtv/h264xcode.log"
OUTFILE="${OUTDIR}/${CHANID}_${STARTTIME}"

COMMAND="${PROG} -i ${INDIR}/${CHANID}_${STARTTIME}.mpg ${PARAMS} ${OUTFILE}.m4v.tmp"

echo "h264xcode: ${COMMAND}" >> $LOG
$COMMAND >> $LOG 2>&1
mv -f ${OUTFILE}.m4v.tmp ${OUTFILE}.m4v >> $LOG 2>&1
rm -f ${OUTFILE}.m4v.tmp >> $LOG 2>&1

Let’s work through what’s going on, here. The script takes two arguments – the channel ID and the start time of the recording (we’ll see how MythTV passes these, later). From them it’s possible to locate the original recording file on disk, using the $INDIR variable.

Next a simple log is set up, and the proposed ffmpeg-264 command echoed to that file. Finally the command itself is run, with a low system priority (nice -n 19), and the output directed to the log file. The H.264 file is saved in $OUTDIR.

So far so good. All that remains is to let MythTV know about this new user job command, which we’ll cover in the next article in this series.

Many thanks to Murray Cox, Seb Jacob, and Colin Morey for providing valuable feedback on this post!
This entry was posted in mythtv, transcoding. Bookmark the permalink.

5 Responses to MythTV Transcoding (3): Transcoding for iPad Playback

  1. Brad says:

    First, thanks! This is really great!

    Second, you need to (as root) touch /var/log/mythtv/h264xcode.log and chmod it to mythtv:mythtv. Otherwise the jobs stay in the ‘queued’ state because mythtv doesn’t know about the errors (see below).

    Third, you should probably handle errors from ffmpeg so that mythtv knows the status of the job, and so that you’re not moving unfinished videos to your ipad directory.

    Last, thanks again!

    • Hi Brad,

      Two excellent comments, many thanks. I’ll make a note to update the example script to handle the ffmpeg return code and pass it to mythtv.

      regards,
      oliver.

  2. David Tranter says:

    I have this all setup but am seeing the job queued as per the first comment from Brad how do I carry out the below suggestions?

    you need to (as root) touch /var/log/mythtv/h264xcode.log and chmod it to mythtv:mythtv. Otherwise the jobs stay in the ‘queued' state because mythtv doesn't know about the errors (see below).

  3. I’ve followed this guide and enjoyed the results, thanks for your efforts in documenting this.
    To make it work on Mythbuntu 12.04LTS I had to compile Yasm from source. I guess this issue will disappear with the next LTS.

    Additionally to use this with mythexport, I added the following to a file called /usr/share/mythexport/configs/TabTrans.pm


    #!/usr/bin/perl

    # Update this with a package name relivant to your new config, make sure it matches with the file name (without the extension).
    package TabTrans;

    use ExportBase;

    our @ISA = qw(ExportBase);

    #Example strings, replace with something relivant to your new config.
    my $description = "h264xcode default settings.";
    my $devices = "Tablet and superphone";
    my $notes = "Requires custom ffmpeg build, see http://blog.gorwits.me.uk/2011/09/04/mythtv-transcoding-3-transcoding-for-ipad-playback/";
    my $version = "1.0";

    #Inherit our base class.
    sub new{
    my $class = shift;
    my $self = $class->SUPER::new(shift, shift, $description, $devices, $notes, $version);
    bless $self, $class;
    return $self;
    }

    sub export{
    my( $self ) = @_;

    # Any command can go here, below is an example of ffmpeg, but you can use anything you would like.
    # Available variables are inputFile, outputFile, and extension
    # system("ffmpeg -i \'$self->{_inputFile}\' -y -pass 1 -an -vcodec libx264 -vpre slowfirstpass -vpre ipod640 -b 1500kb -bt 1000kb -threads 0 -s 800x480 -aspect 16:9 -f$
    system("time nice -n 19 /usr/local/bin/ffmpeg-264 -i \'$self->{_inputFile}\' -y -map 0:0 -map 0:1 -er 4 -f ipod -acodec libfaac -ac 2 -ab 128k -ar 44100 -deinterlace -vc$

    }

    #Feel free to use or extend anything from the base class.

    1;