nav-left cat-right RSS
cat-right

Converting TiVo MPEG2 Videos to H.264

Something I’ve been working on a lot lately (and haven’t been posting until I had things the way I wanted them) was to convert my tivo mpeg2 files that I’ve been copying over from my S3 Tivo to something a little smaller, like h.264.  I have a script to do this, which I’ll provide, but I’d like to go through the process, which consists of:

  1. Getting the dimensions of the video
  2. Cropping letterbox and overscan
  3. Encoding the video

I had a *lot* of issues with AV Sync as well as dropped frames using HandBrake (that no one seemed to know why) so I went with mencoder.  I also left the audio as-is instead of transcoding into AAC.  It’s not a “proper” h.264 file with AC-3, but it works for my purposes.

First off, we need to figure out the dimensions of the video.  The reason is, we want to crop off the timecode/overscan line on the top of the video so that 1. it looks better, and 2. we can actually use cropdetect to figure out where the black bars are.   Here’s how to get video dimensions:

mplayer -nojoystick -nolirc -vo null -ao null -identify -frames 0 $input

The options I’m using:

  • -nojoystick – prevents mplayer spewing out warnings about joysticks
  • -nolirc – same thing here – we’re not using LIRC, so don’t warn us
  • -vo null – No video output device
  • -ao null – No audio output device
  • -identify – Spit out the info
  • -frames 0 – We don’t need to actually look at any frames, so we set to 0
  • $input – The input file

This will output quite a few interesting lines — the ones we care about are ID_VIDEO_WIDTH and ID_VIDEO_HEIGHT. These tell us the dimensions of the video.

For the next step, we’re going to want to strip off the overscan line — to do this, we subtract 6 pixels from the height, (I’ll use a variable called $OVERSCAN) and then send that to mplayer again, this time to detect the crop area that we want:

$height -= $OVERSCAN;
mplayer -nojoystick -nolirc -vo null -ao null -vf crop=$width:$height:0:$OVERSCAN,cropdetect -ss 600 -endpos 180 $input

The new options here are:

  • -vf crop – specify the crop area like this width:height:x:y – x and y are the starting position from the left/top – since we want to pre-crop off the overscan, we have to remove from height as well as start from that position.
  • cropdetect – This tells mplayer to spit out a line for every frame saying where it thinks you’ll want to crop the video
  • -ss 600 – This tells it to start 600 seconds into the video – I wanted to get the middle somewhere, just because the file could start with the end of the previous program, etc.
  • -endpos 180 – This says to stop 180 seconds after it starts (bad name in my opinion) – I want to grab 3 minutes worth of video, in case we happen to be in the middle of a commercial break

This will spit out a ton of lines with crop info, and we want to grab the most common crop sizes.  To do this, I use some perl:

foreach $line (@cropdetect)
{
    if ($line =~ /-vf crop=([\d:]+)/)
    {
        $croptest{$1}++;
    }
}

# Get the crop value with the most hits
my @croplist = sort { $croptest{$b} <=> $croptest{$a} } keys (%croptest);
my $crop = $croplist[0];

This will grab the crop value that’s the most popular.  (The sort line brings it to the first element in the array)

Now that we know where we want to crop, we can begin encoding.  I use a 2-pass encoding method, which is the accepted standard for great quality encoding.  You can go with 1-pass or more than 2, but I think 2 is the sweet spot.  A lot of these options I’m not actually sure what they do, but will explain the ones that I do know about.

mencoder -ovc x264 -x264encopts pass=1:turbo:bitrate=$VBITRATE:bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300 -vf pp=ci,crop=$crop,scale=-1:-10,harddup -oac copy -ofps 30000/1001 $input -o /dev/null

Options:

  • -ovc x264 – Use x264 for the Output Video Codec
  • -x264encopts – Specify options to pass to x264
  • pass=1 – 1st pass
  • bitrate=$VBITRATE – I set $VBITRATE to 1500 – which is 1500 kbits, you can go less for smaller files/lower quality
  • pp=ci – Deinterlacing – tivo files are interlaced, so I wanted to get rid of that
  • crop=$crop – use the crop value that we determined earlier
  • scale=-1:-10 – This will downscale the video so that it uses sizes divisible by 16 – there’s encoding and even playback issues if you don’t do this.  You can upscale by using -10:-1, but I didn’t really see the point in upscaling.
  • harddup – This means that you want to duplicate frame by frame (hard duplicate) – if you don’t, you’ll run into A/V sync issues
  • -oac copy – Audio is passthrough – don’t touch it
  • -ofps 30000/1001 – Hard sets the FPS to 29.97 – I didn’t want the frame rate to jump back and forth like it does, so I wanted to hard set this – haven’t found a good reason not to
  • -o /dev/null – The first pass will just log to a logfile, it won’t write to the output file

After the first pass is done, we do another pass, which has almost the same parameters:

mencoder -ovc x264 -x264encopts pass=2:turbo:bitrate=$VBITRATE:bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300 -vf pp=ci,crop=$crop,scale=-1:-10:,harddup -oac copy -ofps 30000/1001 $input -o $output

New options:

  • pass=2 – 2nd pass
  • -o $output – this time output to our output file

When this is completed, you should have a video file with h.264 for the video, and AC3 for the audio.  This resulted in file sizes at about 60% of the originals, which is good enough for me.  I hope someone found this useful.  I’ll be putting up a script soon that will do all of this work for you (and even work from a queue), but till then, I wanted to get the details out there.

Update: I have created another guide that includes the script that I use here.

blog comments powered by Disqus