Low level Quicktime library

Author: Adam Williams    broadcast@earthling.net
Homepage: heroine.tampa.fl.us/quicktime
------------------------------------------------------------------------

***** 

This is a low level implementation of the Quicktime file format for
UNIX in a freely redistributable, statically linkable library.  You can
statically link it in a program and charge money for the program.  The
only condition is that if you use it in a program, you must put the
author's name and email somewhere.  If you redistribute the code, you
must also redistribute the author information and documentation. 

*****


The Quicktime file format is first and foremost a very complicated,
tedious, wrapper for 3rd party compression schemes.  This library hides
the nightmare of accessing a Quicktime bitstream and presents a set of
raw audio and video streams.  The audio tracks are sequential streams
of PCM audio data and video tracks are a sequential streams of raw
frame data.

Before you drop your classes and write up your dream program on this be
aware of some limitations.  The raw stream level is the lowest level of
abstraction possible.  This library doesn't give you a Quicktime API
even remotely.  It uses it's own ANSI C API.  This library doesn't
include any compression algorithms nor does it include support for
keyframes, which most of the commercial codecs require but the free
codecs don't.  Also you may encounter Quicktime files containing
compressed headers.  This library only reads uncompressed headers.

What you can do is create and read any Quicktime movie that uses JPEG,
RAW, or YUV2 compression and all PCM sound formats.  Integrating
libjpeg, RAW and YUV2 encoding into it is simple enough for even an
unemployed programmer.

Mandatory usage:
------------------------------------------------------------------------

For any operation, the first step is to #include <quicktime.h> and then
create a pointer of type quicktime_t.

	quicktime_t *file;

Open the movie with the quicktime_open function.  Argument 1 is the
path to a file.  Argument 2 is a flag for read access.  Argument 3 is a
flag for write access.  You can specify read, read/write or write
access by setting these flags.  Don't specify read/write mode for files
that already exist.  Read/write mode should only be used for new files.

	file = quicktime_open("test.mov", 1, 1));

This returns a NULL if the file couldn't be opened or the format
couldn't be recognized.  Now you can do all sorts of operations on the
file.

Reading a file:
---------------

A good place to start is before opening the file, make sure it is
Quicktime with quicktime_check_sig().

	quicktime_check_sig("filename");

This returns 1 if it looks like a Quicktime file or 0 if it doesn't. 
Then you can open the file as above.

Next get the number of tracks for each media type in the file:

	int quicktime_video_tracks(quicktime_t *file);
	int quicktime_audio_tracks(quicktime_t *file);

While Quicktime can store multiple video tracks, the audio track count
is a bit more complicated.  In addition to the track count, Quicktime
can store multiple audio channels for each audio track so you have to
count those too, for each track.

	int quicktime_track_channels(quicktime_t *file, int track);

Tracks are numbered from 0 to the total number of audio tracks - 1. 
The library doesn't handle any extraction of channels from each track. 
It just reads raw track data.  For each audio track, other routines you
might find useful for getting information are:

	int quicktime_audio_bits(quicktime_t *file, int track);
	long quicktime_sample_rate(quicktime_t *file, int track);
	long quicktime_audio_length(quicktime_t *file, int track);
	char* quicktime_audio_compressor(quicktime_t *file, int track);

quicktime_audio_compressor returns a 4 byte array that matches one of
Quicktime's audio data format types.   The only formats you can
currently use with this library are RAW and twos because of the
positioning information.  Look in Apple's documentation to figure out
what those are.

quicktime_audio_length gives you the total number of samples in a given
track regardless of the channels or bitrate.

The available video information for each video track is:

	long quicktime_video_length(quicktime_t *file, int track);
	int quicktime_video_width(quicktime_t *file, int track);
	int quicktime_video_height(quicktime_t *file, int track);
	float quicktime_frame_rate(quicktime_t *file, int track);
	char* quicktime_video_compressor(quicktime_t *file, int track);

Video tracks are numbered 0 to the total number of video tracks - 1. 
The video length is in frames.  The width and height are in pixels. 
The frame rate is in frames per second.  The video compressor is a four
byte array containing one of Quicktime's video data format types.  The
only video formats this library can handle are like RAW, yuv2, and
jpeg, which don't use keyframes.

Unless you get a really nihilistic file for reading, you can safely
assume the encoding scheme for track 0 of audio or video is the same
for all tracks of that media type.  That's what the library does.

Once you have that information, you can begin reading data.

	int quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track);
	int quicktime_read_audio(quicktime_t *file, char *audio_buffer, long samples, int track);

quicktime_read_frame reads one frame worth of raw data from your
current position on the specified video track and returns the number of
bytes in the frame.  You have to make sure the buffer is big enough for
the frame.   A return value of 0 means error.

	long quicktime_frame_size(quicktime_t *file, long frame, int track);

gives up the number of bytes in the specified frame in the specified
track even if you haven't read the frame yet.  Frame numbers start on
0.

Now some of you are going to want to read frames directly from a file
descriptor using another library like libjpeg or something.  To read a
frame directly start by calling quicktime_read_frame_init to initialize
the output.

	int quicktime_read_frame_init(quicktime_t *file, int track);

Then read your raw, compressed data from the file descriptor given by
quicktime_get_fd.

	FILE* quicktime_get_fd(quicktime_t *file);

End the frame by calling quicktime_read_frame_end.

	int quicktime_read_frame_end(quicktime_t *file, int track);

You can get the file descriptor any time the file is opened, not just
when reading or writing, but you must call the init and end routines to
read a frame.

For reading audio, quicktime_read_audio converts the samples argument
into a byte count.  Then it reads that number of bytes on the specified
track and returns the equivalent number of bytes read or 0 if error. 
The data read is PCM audio data of interleaved channels depending on
the format of the track.

The current position of each track is independant of each other track
and advances automatically when you read from it.  Speaking of
positions, you can also set each track's position arbitrarily with

	int quicktime_seek_end(quicktime_t *file);
	int quicktime_seek_start(quicktime_t *file);
	int quicktime_set_audio_position(quicktime_t *file, long sample, int track);
	int quicktime_set_video_position(quicktime_t *file, long frame, int track);

The seek_end and seek_start seek all tracks to their ends or starts. 
The set_position commands seek one track to the desired position.

When you're done reading, call quicktime_close(quicktime_t *file);

Writing a file:
-------------
The following commands are good for writing to a file.

Immediately after opening the file, set up the tracks with these
commands:

	quicktime_set_audio(quicktime_t *file, int channels, long sample_rate, int bits, char *compressor);
	quicktime_set_video(quicktime_t *file, int tracks, int frame_w, int frame_h, float frame_rate, char *compressor);

The compressor string can be one of the compressor #defines in
quicktime.h or your own 4 byte type and applies to all audio or video
tracks, for simplicity reasons.  Choose an audio compressor for the
audio command and a video compressor for the video command.  The
library doesn't check for conflicting media types or whether a
compressor you make up is legitimate.

The current compressor #defines are:

	QUICKTIME_RAW
	QUICKTIME_TWOS
	QUICKTIME_JPEG
	QUICKTIME_YUV2

Since you're supplying the compressor for these formats, you can get
their descriptions in the Quicktime file format documentation.

Notice the channels argument for audio channels per track but there is
no argument for total audio tracks. For sanity reasons, the library
only supports creating one audio track of any number of channels.

Now you'll want to seek to any point in the file.  Seeking works
exactly as in reading, using the same commands, except if you seek to
the middle of a file and write out data, you're going to cause a glitch
in the playback data.  Since most video compressors don't store video
linearly, it's impossible to line up new frame boundaries with old
frames.

With that, you can now write data.  You need to supply a buffer of data
exactly as you intend quicktime_read_... to see it, with the encoding
done, then call one of these functions to write it.  For video, specify
the number of bytes in the frame buffer and the track this frame
belongs to.  Video can only be written one frame at a time.

	int quicktime_write_frame(quicktime_t *file, unsigned char *video_buffer, long bytes, int track);

Writing audio involves writing the raw audio data exactly the way
quicktime_read_audio is going to see it, with channels interleaved and
whatever else.

	int quicktime_write_audio(quicktime_t *file, char *audio_buffer, long samples, int track);

The library automatically converts the sample count to the number of
bytes of data in the buffer, based on values you passed to
quicktime_set_audio.

Now some of you are going to want to write frames directly to a file
descriptor using another library like libjpeg or something.  For every
frame start by calling quicktime_write_frame_init to initialize the
output.

	int quicktime_write_frame_init(quicktime_t *file, int track);

Then write your raw, compressed data to the file descriptor given by
quicktime_get_fd.

	FILE* quicktime_get_fd(quicktime_t *file);

End the frame by calling quicktime_write_frame_end.

	int quicktime_write_frame_end(quicktime_t *file, int track);

When you're done, call quicktime_close to close the file.

	int quicktime_close(file);


Repeat starting at quicktime_write_frame_init for every frame.

Other functions:
----------------

You can get some utilities by running make util in the source code
directory.  The dump program merely reads the salient features of a
header from a quicktime file and dumps it in english to the screen.  As
you can see, there is a lot more information in Quicktime files than
video and sound.  Eventually this library may allow you to access the
extra information.

Web authors might find a use for make_streamable.

Bugs:
-------

No key frame support.  Haven't tested most conditions.

References:
-------------
Apple's quicktime file format information:

http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/refQTFileFormat.htm
