Using Data Handler Components

This section describes how applications use data handler components. You should read this section if you are writing your own media handler or your own data handler.

Selecting a Data Handler

To help developers choose the best data handler for a specific situation while still making it easy for an application to find a usable data handler, Apple has defined two separate and complementary mechanisms for selecting data handler components. You can use the Component Manager’s selection mechanisms to find a data handler that meets your needs, or you can interrogate a data handler to determine if it supports a specific data reference. Both mechanisms rely on characteristics of the current data reference in order to make the selection.

Before you can use a data handler component, your application must open a connection to that component. The easiest way to open a connection to a data handler component is to call the Movie Toolbox’s GetDataHandler function. You supply a data reference and the Movie Toolbox selects an appropriate data handler component for you. This function is preferred for opening a data handler as it reliably chooses the best data handler.

Alternatively, you may use the Component Manager to open your connection. Call the Component Manager’s OpenDefaultComponent or OpenComponent function to do so, but be aware that these functions are often unable to make the best choice when there are several different data handlers available for a file.

Selecting by Component Type Value

At the most basic level, your application can use the Component Manager’s built-in selection mechanisms to find a data handler component for a data reference. You may use the Component Manager’s FindNextComponent function in order to retrieve a list of all data handler components that meet your needs. You specify your request by supplying the component’s characteristics in a component description record: in particular, in the componentType, componentSubtype, componentManufacturer, and componentFlags fields.

All data handler components have a component type value of 'dhlr', which is defined by the dataHandlerType constant. Data handler components use the value of the component subtype field to indicate the type of data reference they support. As a result of this convention, note that all data handlers that share a component subtype value must be able to recognize and work with data references of the same type. For example, file system data handlers always carry a component subtype value of 'alis', which indicates that their data references are file system aliases (note that this is true for QuickTime on Macintosh and under Windows, even though there is not, properly, a file system alias under Windows). Apple’s memory-based data handler for Macintosh has a component subtype value of 'hndl'.

Apple has not defined any special manufacturer field values or component flags values for data handler components. You may use the manufacturer field to select data handlers supplied by a specific vendor. To do so, you need to know the correct manufacturer field value for that vendor.

Interrogating a Data Handler's Capabilities

While you can use the Component Manager’s selection mechanisms to find a data handler component that can recognize data references of a specific type, your application must interact with the data handler in order to determine whether it can support a specific data reference. Apple has defined two functions, DataHCanUseDataRef and DataHGetVolumeList, that allow you to query a data handler component in order to find out whether it can work with a data reference. By using these two functions, your application can choose a data handler that is best-suited to its specific needs.

Using the DataHCanUseDataRef function, you supply a data reference to the data handler component. The component then reports what it can do with that data reference. The returned value indicates the level and, to some extent, the quality of service the data handler can provide (for example, whether the component can read data from or write data to the data reference and whether the component uses any special support when working with that data reference).

Because calling the DataHCanUseDataRef function in several data handlers can be time consuming, Apple has also defined a function that helps narrow the search. By using the DataHGetVolumeList function, your application can obtain a list of all the file system volumes that a data handler can support. In response to your request, the data handler returns the list and flags indicating the level and quality of service the data handler can provide for containers on that volume.

For more information on these functions, see Determining Data Handler Capabilities.

Managing Data References

Once you have selected a data handler component, you must provide a data reference to the data handler. Use the DataHSetDataRef function to supply a data reference to a data handler. Once you have assigned a data reference to the data handler, your application may start reading or writing movie data from that data reference. The DataHGetDataRef function allows your application to obtain a data handler’s current data reference.

Data handlers also provide a function that allows your application to determine whether two data references are equivalent (that is, refer to the same movie container). Your application provides a data reference to the DataHCompareDataRef function. The data handler returns a Boolean value indicating whether that data reference matches the data handler’s current data reference.

For more information on these functions, see Working With Data References.

Working With Data References

All data handler components use data references to identify and locate a movie’s container. Different types of containers may require different types of data references. For example, a reference to a memory-based movie may be a handle, while a reference to a file-based movie may be an alias.

Client programs can correlate data references with data handlers by matching the component’s subtype value with the data reference type; the subtype value indicates the type of data reference the component supports. All data handlers with the same subtype value must support the same data reference type. To continue the previous example, Apple’s memory-based data handler for Macintosh uses handles (and has a subtype value of 'hndl'), while the HFS data handler uses Alias Manager aliases (its subtype value is 'alis').

The DataHSetDataRef and DataHGetDataRef functions allow applications to assign your data handler’s current data reference. The DataHCompareDataRef function asks your component to compare a data reference against the current data reference and indicate whether the references are equivalent (that is, refer to the same container). The DataHResolveDataRef permits your component to locate a data reference’s container.

The DataHSetOSFileRef and DataHGetOSFileRef functions provide an alternative, system-specific mechanism for assigning your data handler’s current data reference.

For more information on data references, see Managing Data References.

Retrieving Movie Data

Before your application can read data using a data handler component, you must open a read path to the current data reference. Use the DataHOpenForRead function to request read access to the current data reference. Once you have gained read access to the data reference, data handlers provide both high- and low-level read functions.

The high-level function, DataHGetData, provides an easy-to-use, synchronous read interface. Being a synchronous function, DataHGetData does not return control to your application until the data handler has read and delivered the data you request.

If you need more control over the read operation, you can use the low-level function, DataHScheduleData, to issue asynchronous read requests. When you call this function, you provide detailed information specifying when you need the data from the request. The data handler returns control to your application immediately, and then processes the request when appropriate. When the data handler completes the request, it calls your data-handler completion function to report that the request has been satisfied, see Completion Function for more information on the data-handler completion function.

Besides simply scheduling read requests that must be satisfied during a movie’s playback, another use of the DataHScheduleData function is to prepare a movie for playback (commonly referred to as prerolling the movie). The DataHScheduleData function uses several special values to indicate a preroll operation. Your application calls the DataHScheduleData function one or more times to schedule the preroll read requests, and then uses the DataHFinishData function to tell the data handler to start delivering the requested data.

For more information on these functions and about preroll operations, see Reading Movie Data.

Completion Function

When client programs schedule asynchronous read or write operations (by calling your component’s DataHScheduleData or DataHWrite functions), they furnish your component a data-handler completion function. Your component must call this function when it completes the read or write operation, whether the operation was a success or a failure.

Reading Movie Data

Data handler components provide two basic read facilities. The DataHGetData function is a fully synchronous read operation, while the DataHScheduleData function is asynchronous. Applications provide scheduling information when they call your component’s DataHScheduleData function. When your component processes the queued request, it calls the application’s data-handler completion function. By calling your component’s DataHFinishData function, applications can force your component to process queued read requests. Applications may call your component’s DataHGetScheduleAheadTime function in order to determine how far in advance your component prefers to get read requests.

Before any application can read data from a data reference, it must open read access to that reference by calling your component’s DataHOpenForRead function. The DataHCloseForRead function closes that read access path.

For more information on reading movie data, see Retrieving Movie Data.

Storing Movie Data

Before your application can write data using a data handler component, you must open a write path to the current data reference. Use the DataHOpenForWrite function to request write access to the current data reference. Once you have gained write access to the data reference, data handler components provide both high- and low-level write functions.

The high-level function, DataHPutData, allows you to easily append data to the end of the container identified by a data reference. Except when capturing movie data using the sequence grabber component, the Movie Toolbox uses this call when writing data to movie files. However, this function does not allow your application to write to any location other than the end of the container. In addition, this is a synchronous operation, so control is not returned to your program until the write is complete. As a result, this function is not well-suited to high-performance write operations, such as would be required to capture a movie.

If you need a more flexible write facility, or one with higher performance characteristics, you can use the DataHWrite function. This function is intended to support high-speed writes, suitable for movie capture operations. For example, Apple’s sequence grabber component uses this data handler function to capture movies.

When you call this function, you provide detailed information specifying the location in the container that is to receive the data. The data handler returns control to your application immediately, and then processes the request asynchronously. When the data handler completes the request, it calls your data-handler completion function to report that the request has been satisfied, see Completion Function for more information on the data-handler completion function.

In addition to the DataHWrite function, data handler components provide several other “helper” functions that allow you to create new movie containers and prepare them for a movie capture operation.

For more information on all of these functions, see Writing Movie Data.

Writing Movie Data

As with reading movie data, data handlers provide two distinct write facilities. The DataHPutData function is a simple synchronous interface that allows applications to append data to the end of a container.

The DataHWrite function is a more capable, asynchronous write function that is suitable for movie capture operations. As is the case with the DataHScheduleData function, your component calls the application’s data-handler completion function when you are done with the write request.

There are several other helper functions that allow applications to prepare your data handler for a movie capture operation. The DataHCreateFile function asks your component to create a new container. The DataHSetFileSize and DataHGetFileSize functions work with a container’s size, in bytes. The DataHGetFreeSpace function allows applications to determine when to make a container larger. The DataHPreextend function asks your component to make a container larger. Applications may call your component’s DataHGetPreferredBlockSize function in order to determine how best to interact with your data handler.

Before writing data to a data reference, applications must call your component’s DataHOpenForWrite function to open a write path to the container. The DataHCloseForWrite function closes that write path.

Note that some data handlers may not support write operations. For example, some shared devices, such as a CD-ROM “jukebox,” may be read-only devices. As a result, it is very important that your data handler correctly report its write capabilities to client programs. See Determining Data Handler Capabilities for information about the functions that client programs use to interrogate your data handler. For more information on writing movie data, see Storing Movie Data.

Managing the Data Handler

Data handler components provide a number of functions that your application can use to manage its connection to the handler. The most important among these is DataHTask, which provides processor time to the handler. Your application should call this function often so that the handler has enough time to do its work.

Other functions in this category provide playback hints to the data handler and allow your application to influence how the component handles its cached data.

For more information on these functions, see Managing Data Handler Behavior.

Managing Data Handler Behavior

Applications may call your handler’s DataHPlaybackHints function in order to provide you with some guidelines about how those applications play to use the current data reference.

The DataHFlushData and DataHFlushCache functions allow applications to influence how your component manages its stored data.

Determining Data Handler Capabilities

In order for client programs to choose the best data handler component for a data reference, Apple has defined some functions that allow applications to interrogate a data handler’s capabilities.

The DataHGetVolumeList function allows an application to obtain a list of the volumes your data handler can support. The DataHCanUseDataRef function allows your data handler to examine a specific data reference and indicate its ability to work with the associated container. The DataHGetDeviceIndex function allows applications to determine whether different data references identify containers that reside on the same device.

By way of illustration, the Movie Toolbox uses the DataHGetVolumeList and DataHCanUseDataRef functions as follows. During startup, and whenever a new volume is mounted, the Movie Toolbox calls each data handler’s DataHGetVolumeList function in order to obtain information about each handler’s general capabilities. Specifically, the Movie Toolbox calls each component’s GetDataHandler, DataHGetVolumeList, and CloseComponent functions.

Whenever an application opens a movie, the Movie Toolbox selects the best data handler for the movie’s container. This may involve calling each appropriate data handler’s DataHCanUseDataRef function (in some cases, a data handler may indicate that it does not need to examine a data reference before accessing it; see the description of the DataHGetVolumeList function for more information). For each data handler that can support the data reference (that is, has the correct component subtype value) and needs to be interrogated, the Movie Toolbox calls the component’s GetDataHandler, DataHCanUseDataRef, and CloseComponent functions. Based on the resulting information, the Movie Toolbox selects the best data handler for the application.