Streaming to iPod touch or iPhone

From MythTV Official Wiki
Revision as of 09:27, 8 November 2007 by Juski (talk | contribs) (Transcoding: Added avisory about directly hacking the database)

Jump to: navigation, search

This page is a collection of what you can do to stream myth recordings to an iPod touch or iPhone via MythWeb. This makes the iPod a de facto front-end for myth with the exception of live TV. I actually bought an iPod just to see if I could do this, and I have to say, it is my favourite purchase in a LONG time

This guide is heavily based on Stream_mythtv_recordings_from_mythweb_using_flash_video setup which has had tremendous success. I appreciate all the work the authors have done for that, and I hope someone can make use of these modifications.


  • MythTV
  • MythWeb
  • ffmpeg with libfaac and libxvid


As with any new device there are formats it can handle, unfortunately most do not handle NUV. The iPhone and iPod Touch both handle a specific version of the MPEG-4 standard, as well as h264 video streams. These are documented on Apple's Developer Connection

The steps to making your iPod stream from your server involve:

  1. Encode the file to a friendly format
    1. Set up a script to generate iPod friendly format
    2. Set up a script to delete iPod friendly format files when the original is deleted
  2. Serve the file from your web-server
    1. Ensure your webserver has the correct set-up to see the new files
    2. Link it from the "recorded shows" page in MythWeb (HUGE thanks to Xris for all his work in MythWeb)

Transcoding and Scripts


First we have a script to convert the show to an iPod friendly format (if you're good with mencoder or ffmpeg your help in making this a bit better would be greatly appreciated)

In order to use this you will also need to ensure your webuser is in the myth users group, or in some other manner has permission to write to the myth video store.

Script.png /usr/local/bin/


#MythIPod v.1                                                 
#Copyright 2007 Chris Lorenzo et al                  
#This software is licensed under the CC-GNU LGPL <> 
#Additionally modified 2007 Doug Johnson

if [ ! $# == 2 ]; then
  echo "Usage: $0 directory file"


#Get the video information
video_info=`mplayer -vo null -ao null -frames 10 -identify "${directory}/${file}" 2>/dev/null`

#Command line grep sucks, but we make due...
aspect=`echo $video_info | egrep -oe "Movie-Aspect is [0-9:.]+" | egrep -o "[0-9:.]+"`
framerate=`echo $video_info | egrep -oe "[0-9.]+ fps" | egrep -o "[0-9.]+"`

# set resolution by aspect ratio

if [ "$aspect" == "1.78:1" ]


# Create the MP4

ffmpeg -i "${directory}/${file}" -acodec libfaac -ab ${abitrate} -s ${width}x${height} -vcodec mpeg4 -b ${vbitrate} -flags +aic+mv4+trell -mbd 2 -cmp 2 -subcmp 2 -g 250 -maxrate 512k -bufsize 2M -title "${file}" "${directory}/${file}.mp4" 

This can be set up as a user-job with the following SQL instructions in mythconverg

% mysql mythconverg
UPDATE settings SET data='/usr/local/bin/ %DIR%/%FILE%' WHERE value='UserJob1';
UPDATE settings SET data='Convert to iPod' WHERE value='UserJobDesc1';
UPDATE settings SET data='1' WHERE value='JobAllowUserJob1';
The proper, safe way to do this instead would be to add a user job in mythtv-setup. i.e. add the line
/usr/local/bin/ %DIR%/%FILE%
to a spare user job slot. That way, if you already have a user job in slot 1 it won't be overwritten. It's not generally considered a great idea to send users headlong into the database.

Expire transcoded recordings

Deleting old files

From the Flash Streaming page we get this (very slightly modified) perl script which can autoexpire mp4 recordings. When ran it will check your myth recordings for mp4 files without a corresponding .mpg file and delete any it finds. The code is below, save it as /usr/local/bin/ and chmod it to 755. If you are also using mythflash then please just add another if block that looks exactly the same within the foreach loop, and change the extension to mp4 Also make sure you change the $directory variable to where your recordings are stored.

Script.png /usr/local/bin/

#Checks the myth recording directory for .mp4 files that don't have a corresponding .mpg. If found, it deletes them.

#Change below to your myth recordings directory
$directory = "/mnt/store";

foreach $f (<$directory/*>) {
        if ( $f =~ /\.mp4$/ )
                $f =~ s/\.mp4$//;
                if (!( -e $f )) { `rm -f $f.mp4`; };

There are a number of ways to have this run automatically, I run this command to have cron automatically execute it once a day

ln -s /usr/local/bin/ /etc/cron.daily/

Streaming from your Webserver

First of all you must make sure your webserver gives the correct mime-types when serving an mp4 file. For my install that involved updating /etc/

Getting to the files

Make sure you can see the files. You'll need to have a link to the recordings directory from your mythweb data directory. (Substitute your own mythweb data, and myth TV recordings directories for these values)

# It might look like this:
# ln -s /srv/www/htdocs/mythweb/data/recordings /mnt/videos/mythtv/
ln -s ${mythweb}/data/recordings/ ${myMythVideosDirectory}

Updating recording.php

If you want a link in recording.php you will need something like the following:

Permission to run the script as the webuser

chmod 755 /usr/local/bin/

An updated recorded.php You should find a row in your recorded.php that has the following line:

<tr id="statusrow_<?php echo $row ?>" class="recorded">
    <td nowrap colspan="<?php echo 6 + ($_SESSION['recorded_descunder'] ? 0 : 1) + $recgroup_cols ?>" align="center">

Add the following afterwards. In this example I include a link to encode in case the file doesn't exist. If you don't want to be able to encode as webuser, then your else statement could be changed to "echo 'Not Available';"

Script.png %mythweb%/modules/tv/tmpl/default/recorded.php

<tr id="statusrow_<?php echo $row ?>" class="recorded">
    <td nowrap colspan="<?php echo 6 + ($_SESSION['recorded_descunder'] ? 0 : 1) + $recgroup_cols ?>" align="center">
			echo '<span style="padding-right: 25px; word-spacing: 0.5em;">ipod stream: <b>';
			$file = basename($show->filename);
			if(file_exists($show->filename . '.mp4')){
				echo '<a href="/mythweb/data/recordings/' . $file . '.mp4" target="_blank">Watch</a> ';
				echo "</b>";
			} else {
				echo '<a href="/mythweb/data/ipodencoder.php?file=recordings/' . basename($show->filename) . '&convert=true" target="_blank">Encode?</a> ';
			echo '</b></span>';

Transcoding remotely

An "ipod encoding" page to perform the encoding (I'm sure there's a better way to do this, I did this because it matches what was done in mythflash and worked well for me)

Script.png %mythweb%/data/ipodencoder.php


MythIPod v.2 
Original from MythFlash v.1 Copyright 2007 Chris Lorenzo                    
This software is licensed under the CC-GNU LGPL <> 
Modified 2007 Doug Johnson - changing to encode for iPod. Changes to the recorded.php also don't
reference the player here, so I've simply left that out

if(!isset($_GET['file']) && (!file_exists($_GET['file'])) ){
        print "<br /><br /><center><strong>No File!</strong></center>";

$file = $_GET['file'];

//Convert the file to mp4 using /usr/local/bin/
if(isset($_GET['convert'])) {
   //recording directory must be writable by owner of apache process eg. www-data or apache
   //runs the command in the background   
   $dir = getcwd() ."/recordings";
   if(!is_writable($dir)) {
   	  $apache_owner = `whoami`;
   	  print "<div style='padding: 15px; font-size: larger;'>Recording directory, $dir, is not writable by ${apache_owner}. <br>
	  Please add ${apache_owner} to mythtv group in /etc/group and make sure that the store directory <br>
	  is writable by ${apache_owner} - ie chmod 775 MYTHTV_STORE .</div>";
   } else {
	   print "<div style='padding: 15px; font-size: larger;'>Converting file, should be done in about the length of the show ...";
	   print "<br> <a href=\"javascript:window.close();\" \">close window</a></div>";
	   system("nohup nice -n 15 /usr/local/bin/ ". $dir ." ". basename($file) ." > /dev/null 2>&1 &");


	<title>iPod Touch Streamer</title>

<script type="text/javascript" language="javascript" src="ufo.js"></script>
<link type="text/css" href="streamer.css" rel="stylesheet">


You shouldn't be here.