Technical: QuickTime
Advanced Search
Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

Compressed Movie Resources

Dispatch 12

QuickTime movies are made up of two distinct parts: the media data and the meta data. The media data can be compressed using a variety of video and sound compression algorithms. Starting with QuickTime 3.0, it is now also possible to compress the meta data, more commonly known as the movie resource. The movie resource cannot be compressed with a lossy compression algorithm as it contains critical information such as the video and audio compression types used, individual frame offsets, and timing information. Therefore, to compress the movie resource lossless data compression algorthms must be used. Compressing movie resources using data compression typically reduces the size of the movie resource by 50% or more. For QuickTime movies that are streamed over the internet, this can substantially reduce the start up latency of the movie.

Letting QuickTime Compress the Movie Resource

Most application developers don't need to know the details of how movie resources are compressed. The Movie Toolbox's FlattenMovie and FlattenMovieData functions will compress the movie resource, if requested to by the application. To do this, applications only need to set the flattenCompressMovieResource flag when calling either function. The QuickTime Movie Export component also provides users with the option of compressing the movie resource when exporting/creating a new movie through export.

QuickTime contains two different lossless data compressors, the Apple Data Compressor and the zlib Data Compressor. Both the flatten and export operations use the zlib Data Compressor when compressing movie resources. However, any available data compressor can be used to compress the movie resource if your application compresses the movie resource itself.

Structure of a Compressed Movie Resource

A compressed movie resource, like an uncompressed movie resource, is made up of a group of QuickTime atoms arranged in a hierarchy. Like a compressed movie resource, the outer most atom has a type of MovieAID. Within the Movie atom, there is a single CompressedMovieAID atom which contains all other required atoms. The compressed movie atom has two sub-atoms. The first is a DataCompressionAtomAID which contains a single 32-bit integer which identifies what lossless data compression algorithm was used to compress the movie resource. The second sub-atom is the CompressedMovieDataAID which contains the compressed movie resource itself. The first 32-bit integer in the compressed movie data atom indicates the uncompressed size of the movie resource, and then the compressed movie resource data follows.

The structure of the complete compressed movie is shown below. The constants that define the atom types are defined in MovieFormat.h. The four character codes for each atom type are also shown below.

MovieAID - 'moov'
  CompressedMovieAID - 'cmov'
    DataCompressionAtomAID - 'dcom'
      Compression Type (32 bit OSType) - 'zlib'
    CompressedMovieDataAID - 'cmvd'
      32 bit integer - uncompressed size
      (compressed movie resource data)

Compressing the Movie Resource In Your Application

If your application creates movie files without using the QuickTime Movie Exporter or FlattenMovie/FlattenMovieData, it must compress the movie resource itself, if it wants to provides users with the ability to create movies with compressed movie resources. The following code shows how to compress the movie resource.

First, it is necessary to get the uncompressed movie resource.

Handle movieResource = NewHandle(0);
long movieResourceSize;
   
PutMovieIntoHandle(theMovie, movieResource);
movieResourceSize = GetHandleSize(movieResource);

Next, we instantiate an instance of the lossless data compressor we'll use. In this case, we're using the zlib data compressor.

DataCodecComponent dataCompressor;
   
OpenADefaultComponent(DataCompressorComponentType,
    zlibDataCompressorSubType, &dataCompressor);

Now we need ask the data compressor how big a buffer to allocate to store the compressed data. The actual size of the compressed data will likely be smaller than the size we initially have to allocate, so after we compress the data, we'll shrink the compressed data handle down to the actual compressed data size. We also allocate an extra 10 32-bit integers of space that we'll use to store the compressed movie resource header information.

unsigned long compressedSize;
Handle compressedData;
   
DataCodecGetCompressBufferSize(dataCompressor, movieResourceSize, &compressedSize);
   
compressedData = NewHandle(compressedSize + (10 * sizeof(UInt32)));

Now we're ready to compress the movie resource. When we do this, the data compressor will return the actual size of the compressed data. It also returns a value that we'll ignore that indicates how much slop is required if the data is to be decompressed "in place." Notice that we don't put the compressed data at the start of the compressed data Handle. Instead, we put the compressed data after the space we've reserved to put the compressed movie resource header.

unsigned long actualCompressedSize;
unsigned long ignore;
   
HLock(compressedData);
HLock(movieResource);
   
DataCodecCompress(dataCompressor, *movieResource, movieResourceSize,
    *compressedData + (10 * sizeof(UInt32)), compressedSize,
    &actualCompressedSize, &ignore);
   
HUnlock(compressedData);
HUnlock(movieResource);

Now that we've compressed the movie resource, we need to fill in the compressed movie resource header. This is shown below. Because all fields in the QuickTime movie resource are in big endian format, we use the EndianU32_NtoB macro to ensure that the values written into the compressed movie resource header are written in big endian format.

UInt32 *header;
   
header = (UInt32 *)*compressedData;
*header++ = EndianU32_NtoB(actualCompressedSize + (10 * sizeof(UInt32)));
*header++ = EndianU32_NtoB(MovieResourceType);
*header++ = EndianU32_NtoB(actualCompressedSize + (8 * sizeof(UInt32)));
*header++ = EndianU32_NtoB(CompressedMovieAID);
*header++ = EndianU32_NtoB(12);
*header++ = EndianU32_NtoB(DataCompressionAtomAID);
*header++ = EndianU32_NtoB(zlibDataCompressorSubType);
*header++ = EndianU32_NtoB(actualCompressedSize + (3 * sizeof(UInt32)));
*header++ = EndianU32_NtoB(CompressedMovieDataAID);
*header++ = EndianU32_NtoB(movieResourceSize);

We now need to shrink the compressed movie resource Handle down to the actual size of the compressed movie resource data, not the worst case compressed size that we allocated prior to actually compressing the data.

SetHandleSize(compressedData, actualCompressedSize + (10 * sizeof(UInt32)));

Finally, we need to dispose of the uncompressed movie resource and the data compressor component we allocated in the process of compressing the movie resource.

CloseComponent(dataCompressor);
DisposeHandle(movieResource);

See Also

Inside Macintosh: QuickTime - Movie Toolbox chapter

Inside Macintosh: QuickTime - Quick Movie Format appendix

QuickTime 3 Reference - Movie Toolbox

Change History

4/25/98 - jph - First published
Topics
Previous | Next