Ipod export

From MythTV Official Wiki
Jump to: navigation, search

Author Justin Hornsby
Description User job to transcode selected recordings to XviD and AAC for use in iPods and other devices with similar codec support.

iPod export script

Here is a script to export recordings in a format compatible with a video iPod. It can be used on the command line or as a user job script.

Command line usage

If using on the command line, the usage information is as follows:

ipodexport.pl exportdir=/foo/bar starttime=%STARTTIME% chanid=%CHANID% bitrate=x size=320x240 aspect=4:3 debug


%CHANID% = channel ID associated with the recording to export

%STARTTIME% = recording start time in either 'YYYY-MM-DD HH:MM:SS' or 'YYYYMMDDHHMMSS' format

exportdir = dir to export completed MP4 files to (note the user the script runs as must have write permission on that dir

size = frame size of output file. 320x240 is the default value

aspect = aspect ratio of output file. Valid values are 4:3 (default) and 16:9

bitrate = audio bitrate in output file in kbps. Default value is 96

debug = enable debugging information - outputs which commands would be run etc

Use as a User Job

Enter mythtv-setup and select the 'general' menu option. Keep hitting 'next' until the 'Job Queue (Job Commands)' screen appears.

Add a brief description of the script in the 'description' field then enter the path to the script (including any options) to the 'command' field.

In this case, put 'export recordings to iPod' in the description field and

ipodexport.pl exportdir=/foo/bar starttime=%STARTTIME% chanid=%CHANID% bitrate=128 size=320x240 aspect=4:3
in the 'command' field. You may want to change some of the parameters to suit your own needs.

Click all the way to 'finish' and if user jobs are permitted to run, the script will now be available to use.

The Code

Script.png ipodexport.pl

#!/usr/bin/perl -w
# ipodexport.pl v1.0
# By Justin Hornsby 27 July 2007
# A MythTV user job script for exporting MythTV recordings to iPod & other xvid/aac formats
# Usage info will be output if the script is run with no arguments (or insufficient arguments)
# Contains elements of mythtv.pl by Nigel Pearson
# Initial idea from nuvexport
# Requirements: ffmpeg with aac & xvid support enabled, perl and the DBI & DBD::mysql modules
#                Also requires MythTV perl bindings
use DBI;
use DBD::mysql;
use MythTV;

# Set default values
my $exportdir = '/home/mythtv/';
my $bitrate = '96';
my $aspect = '4:3';
my $size = '320x240';

$connect = undef;
$debug = 0;

#                                #
#    Main code starts here !!    #
#                                #

$usage = "\nHow to use ipodexport.pl : \n"
        ."ipodexport.pl exportdir=/foo/bar starttime=%STARTTIME% chanid=%CHANID bitrate=x size=320x240 aspect=4:3 debug\n"
        ."\n%CHANID% = channel ID associated with the recording to export\n"
        ."%STARTTIME% = recording start time in either 'YYYY-MM-DD HH:MM:SS' or 'YYYYMMDDHHMMSS' format\n"
        ."exportdir = dir to export completed MP4 files to (note the user the script runs as must have write permission on that dir\n"
        ."size = frame size of output file.  320x240 is the default value \n"
        ."aspect = aspect ratio of output file.  Valid values are 4:3 (default) and 16:9 \n"
        ."bitrate = audio bitrate in output file in kbps.  Default value is 96 \n"
        ."debug = enable debugging information - outputs which commands would be run etc\n"
        ."\nExample: ipodexport.pl exportdir=/home/juski starttime=20060803205900 chanid=1006 size=320x340 aspect=16:9 bitrate=192 debug \n";

# get this script's ARGS

$num = $#ARGV + 1;

# if user hasn't passed enough arguments, die and print the usage info

if ($num le "2") {
    die "$usage";

# Get all the arguments

foreach (@ARGV){

    if ($_ =~ m/debug/) {
        $debug = 1;
    elsif ($_ =~ m/size/) {
        $size = (split(/\=/,$_))[1];
    elsif ($_ =~ m/aspect/) {
        $aspect = (split(/\=/,$_))[1];
    elsif ($_ =~ m/bitrate/) {
        $bitrate = (split(/\=/,$_))[1];
    elsif ($_ =~ m/starttime/) {
        $starttime = (split(/\=/,$_))[1];
    elsif ($_ =~ m/chanid/) {
        $chanid = (split(/\=/,$_))[1];
    elsif ($_ =~ m/exportdir/) {
        $exportdir = (split(/\=/,$_))[1];

my $myth = new MythTV();
# connect to database
$connect = $myth->{'dbh'};

$query = "SELECT title, subtitle, basename FROM recorded WHERE chanid=$chanid AND starttime='$starttime'";

$query_handle = $connect->prepare($query);

$query_handle->execute() || die "Cannot connect to database \n";

$query_handle->bind_columns(undef, \$title, \$subtitle, \$basename);


my $schemaVer = $myth->backend_setting('DBSchemaVer');
# Storage Groups were added in DBSchemaVer 1171
my $dir = 'UNKNOWN';
if ($schemaVer < 1171)
    if ($debug) {
        print ("Using compatibility mode\n");
    $dir = $myth->backend_setting('RecordFilePrefix');
    if ($debug) {
        print ("Going into new mode\n");
    my $storagegroup = new MythTV::StorageGroup();
    $dir = $storagegroup->FindRecordingDir($basename);

$query = "SELECT name FROM channel WHERE chanid=$chanid";
$query_handle = $connect->prepare($query);
$query_handle->execute()  || die "Unable to query settings table";

my ($channame) = $query_handle->fetchrow_array;

# replace whitespace in channame with dashes
$channame =~ s/\s+/-/g;

# replace non-word characters in title with underscores
$title =~ s/\W+/_/g;
# replace non-word characters in subtitle with underscores
$subtitle =~ s/\W+/_/g;

# Remove non alphanumeric chars from $starttime & $endtime
$newstarttime = $starttime;
$newstarttime =~ s/[|^\W|\s|-|]//g;
$filename = $dir."/".$chanid."_".$newstarttime.".mpg";
$newfilename = $exportdir."/".$channame."_".$title."_".$subtitle."_".$newstarttime.".mp4";

if ($debug) {
    print "\n\n Source filename:$filename \nDestination filename:$newfilename\n \n";

# Now run ffmpeg to get iPod compatible video with a simple ffmpeg line

$command = "nice -n19 ffmpeg -i $filename -vcodec xvid -b 300 -qmin 3 -qmax 5 -bufsize 4096 -g 300 -acodec aac -ab $bitrate -s $size -aspect $aspect '$newfilename' 2>&1";

if ($debug) {
    print "\n\nUSING $command \n\n";

if (!$debug) { 
    system "$command";

Note on change in ffmpeg parameter

With a recent version of ffmpeg (SVN-r25059), the above script gives this error:

 encoder 'aac' is experimental and might produce bad results.
 Add '-strict experimental' if you want to use it.
 Or use the non experimental encoder 'libfaac'.

Change -acodec aac to -acodec libfaac in the $command line in the script to solve the issue.

Note On Conversion Of DVB Recording

If you live in the UK and you are using MythTV with Freeview, then you are probably pulling your hair out for 2 reasons:

  • It is impossible to get the audio and video in sync whatever you do.
  • Somehow ffmpeg always seems to pick the audio description soundtrack for the partially sighted rather than the normal one.

I have used the following script for some time, and it solves both the above problems by using ffprobe to determine which soundtrack to pick and then projectX to correct the lip-sync problems.

You can find details of how to install projectX here: Installing_MythArchive_Dependencies#ProjectX.


# Run this script with 2 arguments:
#     iphone.sh <src_file> <dest_file>

# We make a temporary directory to work in.
# NOTE: If you have problems with file access it is probably
# because you tested this script as one user and the mythtv is
# running as another.  Try chmoding this directory to 777.
mkdir /tmp/projectX

# Generate the filenames for the commands
TMP_FILE=`basename "$1" .mpg` 
TMP2_FILE=/tmp/`basename "$1" .mpg`.mov

# First up, we find the correct audio and video streams
# to transcode, if we didn't do this then 9 times out of 10
# you will end up with a video that has the audio descriptive
# track and not the real audio!
VIDEO_PID=`ffprobe "$1" 2>&1 | grep -i "video" | cut -c17-22 | sed -e 's/]//g' | sed -e 's/(//g'`
AUDIO_PID=`ffprobe "$1" 2>&1 | grep "2 channels" | cut -c17-22 | sed -e 's/]//g' | sed -e 's/(//g'`

# Now use projectX to split the audio and video in to separate files.  We
# do this to fix lip-sync problems when transcoding DVB-T transmission.
# Note that the important thing here is that projectX fixes up the problems
# not the separation in to separate files.
# If you don't do this then the audio and video will be out of sync by many
# seconds by then end of the programme.
# This is where we use the PIDs from the previous commands.
java -Djava.awt.headless=true -jar /usr/share/projectx/ProjectX.jar -demux "$1" -id $AUDIO_PID,$VIDEO_PID -out /tmp/projectX/

# Now we can actually transcode the video!  Insert your favourite ffmpeg
# command below.  Don't like it or it is too slow, well try changing the
# output size to 320x180 to speed up the transcode.
ffmpeg -i "/tmp/projectX/$TMP_FILE.m2v" -i "/tmp/projectX/$TMP_FILE.mp2" -async 1000 -dts_delta_threshold 100 -vcodec libx264 -b 768k -vpre medium -s 720x576 -acodec libfaac -ac 2 -ar 48k -ab 128k "$TMP2_FILE"

# We can now delete the intermediate files
rm /tmp/projectX/$TMP_FILE*

# ... and move the result in to the output directory
mv $TMP2_FILE $2

Multi Channel Audio

When a recording is in 5.1 surround sound, or any multi channel audio for that matter, I had to use the following option for ffmpeg to convert to 2 channel stereo. Otherwise the ipod would not output any audio.

-ac 2