MKV to MOV for big files

For most users, getting a matroska (MKV) file into Quicktime is as simple as installing the Perian codec. It makes things joyously simple. You can even do file->save as to rewrap your video as something else. Great!

It gets problematic when you have a really big (over 2gig) MKV file. QT will just crash! Oh no!

So, here’s my workaround. Not for the faint of heart.

Start by getting the current CVS version of MPEG4IP. You’ll need SDL and libtoolize to build it.

Also get mkvtoolnix and install that.

Extract the video and audio tracks from the mkv file using mkvextract:

mkvextract tracks <mkv filename> 1:part1.h264 2:part1.ac3

This will need to grind for a while, but eventually you’ll have your demuxed tracks.

Next, you need to use mp4creator to wrap the H.264 elementary stream in a proper mp4 box. You’ll probably get a warning about an invalid SEI message. Ignore that.

/usr/local/bin/mp4creator -create=part1.h264 -rate=29.97 “My Video.mp4”

Next, we need to add the audio. Unfortunately, mp4creator can’t handle ac3 audio. You’ll either need to convert the audio to AAC, and then use mp4creator to merge them, or use Quicktime Pro. I prefer the latter – open the ac3 file in QT, select all, copy, then open your mp4 and select add->add to movie.

Now, when you go to save, Quicktime will likely yell at you. You need to mark an in point a second into the video, and an outpoint a second from the end, and then select edit->trim. Then you can do “file->save as” and move on.

What a pain, hu?

iTunes as your only media management tool

I know, I know, I just posted saying that I’m somewhat disenchanted with the iTunes Store (and just wait till I post my rant about iPhone 1.1.1) … however, iTunes itself is still my digital media jukebox of choice.

With that in mind, and with the impending arrival of an appleTV, I’ve decided to commit to iTunes as my complete digital media manager. Not just audio – video too.

There are two routes to getting video into iTunes. If you want the video to work seamlessly on iPods, iPhones and AppleTVs, you need to use something like Quicktime Pro or Visual Hub to transcode the video. This is a slow, lossy process and I have no interest in that.

Option two is to wrap the video in a Quicktime wrapper. This doesn’t touch the video data at all, just makes it look like a Quicktime file. It’ll still have XVid or Windows Media (or whatever) data inside. To do this, open the file in Quicktime, and do file->save as. Make sure to create a new file, not a reference file. The resulting mov can be dropped directly into iTunes. If you add the Perian codec to your appleTV, the files will work with that device as well (I hope, I don’t have a TV yet to test this with).

That’s great if you just have a few files, but what if you’ve got hundreds of gigabytes of video? You need automation! Other folks have created Applescripts to do this, but Quicktime 7.2 broke them all. So, I’ve created one that works with 7.2. Make sure you’ve got interface scripting turned on in the “universal access” system preference panel. Then just drop a load of videos onto this droplet and let it go to work.

SaveAsMov.zip – SaveAsMov script

From there, you’ll need to properly organize all your videos. Check out Doug’s Applescripts for Itunes page for a load of scripts to make this easier. I particularly like “set video kind” and “track names with incremented number.”

Dig it.

Make XSan not suck

This is one of those posts that I’m doing just in case somebody stumbles upon it in the future while troubleshooting an issue. Since we started the Media Mill project, our XSan install has been relatively flakey. We haven’t had any data loss or anything, but it’s always taken forever to mount a volume after a boot, and the controllers often lost track of the clients.

It finally bothered me enough recently to dig down and solve the issue. It turns out the biggest problem (and this won’t surprise Xsan veterans) was DNS. Even though the machines don’t have DNS servers specified, they were still apparently waiting for DNS timeouts on every single Xsan transaction. OSX in general has obscenely long timeout periods of DNS, which was creating a cascade of problems within Xsan.

The solution was to create a hosts file. Just edit /etc/hosts (you’ll have to sudo to do this) and add all of the hosts that access xsan, as well as hostnames for them. “man hosts” for an explanation of the formatting.

The trick is to run “sudo lookupd -flushcache” afterwards, or you won’t get the benefits. Then, launch XSan Admin and marvel at how quickly it responds. Marvel too at how quickly hosts mount the SAN volume after boot.

There are a ton of other things you can do to make XSan behave better. Anyone thinking about installing should take a look at XSanity.com, the home of all things Xsan.

Dynamic Flash metadata injection with PHP

So, between the summer lull in industry news and my own globe hopping, the blog has been pretty sparse lately. I think things will now begin to normalize, and I figured I’d start it off with a bit of info about a project I’ve been working on.

First, some history. Streaming flash video normally requires an expensive Flash Media Server license. Otherwise, you’re limited to progressive download from http. Some very clever folks have, in the past, figured out how to do streaming over http using php. They accomplish this by adding a bunch of metadata in the flv file which cross references keyframe timestamps with byte offsets. So, if you have a keyframe 50 seconds into your video, they’d include where in the physical file data to find that. This allows you to seek in the video file without having to decode the whole flash video stream – you just need to read the metadata and do an fseek to an appropriate offset.

It gets slightly more complex, in that you need to also rebuild a proper flash header to that the file still has the right format, but for the most part that’s not too difficult either.

There are a number of projects out there to make this pretty easy. Start by taking a look at the phpstream project. These solutions all require you to do the metadata injection with a separate tool, either the closed-source and Windows-only flvmdi, or the open-source, ruby-based flvtool2. Neither of these is optimal if you’re looking to either do injection dynamically, or integrate injection into an existing automation workflow.

Luckily, there is another project, someone neglected, called flv4php. It implements many of the necessary FLV-parsing routines in php, allowing you to build your metadata array directly within php and write it back to the FLV file, or store it separately. You can even do this at runtime, if you’re so inclined. I’d recommend against that particular approach if you’re dealing with long flash videos, as there is a significant amount of processing overhead involved.

If you browse around the source, you’ll find a php4 and php5 version of flv4php. The php4 version has many more features, but the php5 version has sample code for implementing metadata injection. Take a look at the test2.php code to get started. However, for long files, replace the line that says

$ts = number_format($tag->timestamp/1000, 3);

with:

$ts = $tag->timestamp/1000;

To prevent php from adding commas to your timestamps and thus breaking flash.

The test2.php code writes out a .meta file, containing the metadata for your video. That leaves the issue of how to read that data back in and inject it appropriately. That code is below.

To actually view streaming FLVs, you can use JeroenWijering’s free flv player. Take a look at the source if you’re curious how it all works on the client side.

Anyways, here’s how to playback a .meta file in conjuction with an FLV file. $streamPos is the offset within the video that we’re seeking to (it comes from Flash as a byte offset already). A bunch of this was stolen from the php4 tree of flv4php.

$fp = fopen( $targetFile, ‘r’ );

header(‘Content-type: flv-application/octet-streamn’);

header(‘Content-Disposition: attachment; filename=”‘ . $fakeName . ‘”‘);

header(“Pragma: public”);

header(“Cache-Control: must-revalidate, post-check=0, pre-check=0”);

fseek($fp, 0);

$FLV_HEADER_SIZE = 9;

$hdr = fread( $fp, $FLV_HEADER_SIZE );

fseek($fp, 0);

$bodyOfs = (ord($hdr[5]) << 24) + (ord($hdr[6]) << 16) + (ord($hdr[7]) << 8) + (ord($hdr[8]));

echo fread($fp, $bodyOfs + 4);

$metadataFile = $targetFile . “.meta”;

$metad= file_get_contents($metadataFile);

echo $metad;

$chunkSize = 4096;

$skippedOrigMeta = empty($origMetaSize);

if($streamPos == 0) {

}

else {

fseek($fp, $streamPos);

}

while (! feof($fp))

{

// if the original metadata is present and not yet skipped…

if (! $skippedOrigMeta)

{

$pos = ftell($fp);

// check if we are going to output it in this loop step

if ( $pos <= $origMetaOfs && $pos + $chunkSize > $origMetaOfs )

{

// output the bytes just before the original metadata tag

if ($origMetaOfs – $pos > 0)

echo fread($fp, $origMetaOfs – $pos);

// position the file pointer just after the metadata tag

fseek($fp, $origMetaOfs + $origMetaSize);

$skippedOrigMeta = true;

continue;

}

}

echo fread($fp, $chunkSize);

}

fclose($fp);

Deinterlacing for Fun and Profit

Deinterlacing is one of those things that often gets overlooked in video production. When you’re delivering video on the web, it’s really important to deinterlace it, or you’ll see all kinds of interlacing ugliness when your video is displaying on an (inherently progressive scan) computer monitor.

There are a load of ways to deinterlace an image, ranging from the most basic – just throwing away every other field – to crazy complex – optical flow analysis with motion adaptive interpolation. As you might guess, these range in processing-costs from essentially free to very expensive.

Seeing as my email is down at the moment, and seeing as it’s spring break, I decided to spend some time playing with the various deinterlacing options available within Compressor. I mention Compressor specifically because all of the Media Mill presets make use of the basic “deinterlace – blur” filter to force all video to progressive. When the “100% frame size” bug is fixed, I’ll be adding some straight progressive presets, without any deinterlacing.

Deinterlacing is most important when you’re not doing any rescaling of the frame – when you’re shrinking a 1080i frame down to 320×180, it tends to all get blurred away anyways.

Here’s a 1080i60 frame, after being run through an H264 encode with no deinterlacing.

Greenscreen Tutorial-Original

It looks pretty nice, but notice the interlacing blur in Mike’s hand. This is the sort of thing that can get really ugly on a panning shot. It’s a bit harder to see in the web jpeg because the images get shrunk slightly. Here’s a 100% crop:

Mikehand-2

Next, the same frame but with a “Deinterlace – Blur” applied. I’m using blur because it’s the nicest of the “cheap” deinterlace filters available within Compressor.

Blur

Well, his hand looks better, but look at the tripod legs and Rebecca’s dress. They’re terrible! This is really bad artifacting, and it really bothers me because it looks so unnatural.

What happens when we throw just a little bit more (20%) cpu time at the problem? Here’s a frame that has the “Frame Control” deinterlace applied, with the “fastest” option selected, line averaging.

Lineaveraging

Wow, much better! The diagonal elements look good, and his hand has a proper motion blur, like it should.

One tip – when you’re using the frame control deinterlace within Compressor, be sure to also set the “output fields” dropdown to “progressive,” or the deinterlace won’t have any effect at all.

If we throw even more CPU time at the problem, you get another ~10% improvement in vertical resolution, but it’s really not worth the effort.

So, the verdict? I’ve been doing it all wrong. Starting today, the highest quality Media Mill presets will use frame controls for interlacing. This means the 1080p, 720p (just added!) and “Very Large” 480p presets. This only effects the Quicktime presets for now, as I need to do more testing with WMV.

Fun!