danielgtaylor/qtfaststart — pull request #15 by reinecke (2014-01-14 00:12:12+00:00)
Title: Compressed header handling

We've discovered that using the library on Quicktime movies with compressed headers (identifiable by the "cmov" atom under the "moov" atom) would often cause corruption of the mov file. I'm relatively certain this will resolve #13 from mgoblue80.

I identified this is being caused by the library's deletion of free atoms and it's inability to update "stco" or "co64" atoms within a compressed header.

This diff adds features to:
1. disable deletion of "free" atoms
2. detect compressed moov atoms and raise an exception

While in the code, I also made some more specific exceptions for certain cases. These new exception types are subclassed from FastStartException, so the updates should be backward compatible with existing code. I've also updated the code to include a useful explanation while raising exceptions in the event that logging is turned off.

This patch is a stop-gap to prevent corruption of movies with compressed "moov" resources. To explain what I understand the cause of the corruption to be, lets assume a Quicktime file with uncompressed headers and the following atom structure:
ftyp
moov
wide
mdat

With "moov" resources, the contents of the "moov" atom are compressed using zlib. Among those contents can be byte offset values pointing to locations in the "mdat" atom relative to the beginning of the file (offsets are in the compressed "stco" and "co64" atoms within the "moov"). Unfortunately the size of the compressed "moov" atom is unknown until after compressing that atom. If you were to write the "wide" and "mdat" resources out directly after the "moov" resource, it would be impossible to correctly know what values to place in the "stco" or "co64" atom because the unpredictable size of the "moov" atom would affect the byte offset of the "mdat" atom.
To account for this, the offsets in the "stco" and "co64" atoms are generated assuming the "moov" atom will be some safely larger size than it's approximate compressed size. A "free" atom is then written after the compressed "moov" atom to calibrate the file file offsets to the correct position. So with compressed "moov" resources, the top-level atom structure comes out being:
ftyp
moov
free
wide
mdat

This code can't play nice with compressed "moov" resources without the ability to:
1. decompress the "moov" resource
2. apply the "stco" or "co64" offsets
3. re-compress the adjusted "moov" resource
4. add a "free" atom to ensure correct "mdat" position
I currently have a pretty good idea how to write that support in, but I don't have time to tackle it just now. I thought it would be best if I shared what I'd figured out in case it's not general knowledge.

The "Compressed Movie Resources" section of the following doc was useful in untangling this:
https://developer.apple.com/library/mac/documentation/QuickTime/qtff/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-BBCDACCD

I've been unable to find documentation on using the "free" atom to re-calibrate file offsets, the explanation I gave is conjecture on my part.

Thank you!
-Eric Reinecke