June 93 - SOMEWHERE IN QUICKTIME
SOMEWHERE IN QUICKTIME
DERIVED MEDIA HANDLERS
JOHN WANG
In this column, I'll be telling you about derived media handlers in QuickTime 1.5 --
but first, some background.
QuickTime movies contain tracks that refer to media. In QuickTime 1.0, two media
types are supported: video and sound. A movie might therefore have one track that
refers to video media and one that refers to sound media. Each of these supported media
has a media handler, which is code that's responsible for interpreting the media's data.
Obviously, displaying video images requires different code than playing sound. The
media handler code is in the form of a component of type 'mhlr'. The video media
handler has the subtype 'vide', and the sound media handler has the subtype 'soun'.
QuickTime uses the concept of a media to separate media interpretation from the Movie
Toolbox and to place the responsibility into individual media handlers. This has the
added advantage that media handlers can be created to interpret new media types.
However, it wasn't possible to easily create a media handler in QuickTime 1.0.
DERIVED HANDLERS TO THE RESCUE
Derived media handler support was introduced in QuickTime 1.5 to allow developers to
define new custom media types. As an example of the capabilities of the derived media
handler, QuickTime 1.5 has a new 'text' media type that's implemented using a derived
media handler. Derived media handler components can easily be created because they
can use the services of a common base media handler supplied by Apple; hence the
namederived media handler. The base media handler manages most of the duties that
must be performed by all media handlers and reduces the intricacies of writing a
standalone media handler.
This column will discuss sample code (provided on this issue's CD) that implements a
complete QuickDraw derived media handler. This media handler will interpret
QuickDraw pictures stored in the media's data. Each media sample in the data is a
QuickDraw picture. For example, you could have a movie of a bouncing ball, but
instead of having compressed pixel images of the balls bouncing, as in a video media,
you would have a series of pictures of a ball drawn with PaintOval as it moves along its
path. The CD also contains a sample that creates interesting movies using our new
QuickDraw media type.
CREATING THE COMPONENT SHELL
The first step in creating our sample derived media handler is to create a component
shell to which we can add media handler-specific calls in a later step. The
MyComponent.c file contains the following routines: main (the dispatch routine for the
component), MyOpen, MyClose, MyCanDo, MyVersion, and MyRegister. MyOpen, the
initialization routine for our component, opens the base media handler and sends
atarget request to it. A target request is a Component Manager service that allows a
new component instance to establish itself as atarget component instance for another
(delegate) instance. In our case, the target is our QuickDraw derived media handler
and the delegate is the base media handler. The delegate will be called by the target
whenever the target wants to delegate calls to it. The delegate should call the target
whenever the delegate would normally call itself (for example, when it uses its own
services). This effectively makes our derived media handler sit on top of the base
media handler by handling all requests that it can handle and delegating requests that it
can't handle to the base media handler.
By calling the ComponentSetTarget routine after opening an instance of the base media
handler component, we inform the base media handler that our component is derived
from it. For example, the following code from our derived media handler component's
open routine, MyOpen, will open the base media handler and target it:
myComp = OpenDefaultComponent(MediaHandlerType, BaseMediaType);
ComponentSetTarget(myComp, self);
(**storage).delegate = myComp;
The above description of targeting a component is similar to another Component
Manager service, called capturing. Capturing is a service whereby the target
component completely and permanently overrides the delegate component by hiding it
from further use. This is feasible, for example, when updating a component or fixing
bugs in it; the target can implement only the new features while delegating the original
functionality to its delegate. Since the target wouldn't want the outdated delegate
component to be visible any longer, it would capture the delegate using the Component
Manager's CaptureComponent routine. You shouldn't call CaptureComponent on the base
media handler, because that would hide it and prevent other derived media handlers
from using it. Conceptually, you're not replacing the base media handler; you're just
using its services. Therefore, targeting it is sufficient.
When the media handler is no longer used by the Movie Toolbox, the QuickDraw derived
media handler's MyClose routine will be called. To close the connection to the base
media handler, MyClose must call CloseComponent to close the base media handler
component instance:
CloseComponent((**storage).delegate);
To prevent our derived media handler from registering if the base media handler isn't
available, the MyRegister routine returns true (to not register) if the initialization
done by MyOpen fails or false (to register) if it succeeds.
DEFINING THE MEDIA DATA FORMAT
The next step in creating a derived media handler is to define a media type identifier, a
sample description record that's stored along with the media samples, and the format
of the media data.
For our QuickDraw media, we'll use 'Qdrw' as the media type. (As with resource types,
Apple reserves all-lowercase types, so we use a media type that contains one
uppercase character.) Every movie that contains a track created by using
NewTrackMedia with mediaType 'Qdrw' will automatically refer to our custom media
handler. Our media handler will have the component type 'mhlr' and subtype 'Qdrw'.
All description records must contain size, type, resvd1, resvd2, and dataRefIndex
fields as a minimum. You should always fill in the size and type fields, but you can set
the other fields to 0. It's also recommended that a field for the media data version be
included in the sample description record so that it's always possible to identify the
version of the media data.
#define QDrawMediaType 'Qdrw'