Creating Video Output Components

This section describes the routines a hardware developer must implement when creating a video output component.

The examples in this section show how your video output component can use the services of the base video output component provided by Apple Computer. If your component uses these services, you do not have to implement the entire API for a video output component. You simply implement the functions described here, and the base video output component handles the rest. For most of the functions, you extend functions already included in the base video output component, which is much faster than providing complete implementations of these functions yourself. If the base video output component’s implementation of any of these functions returns an error, the function in your video output component must immediately return with the same error. If the base video output component’s implementation completes successfully, then your video output component’s function provides the remainder of the implementation.

Before reading this section, you should be familiar with how to create components.

Connecting to the Base Video Output Component

To use the services of the base video output component, your video output component must open a connection to the base video output component. It does this in its routine for processing open requests from the Component Manager. How to connect to the base video output component is shown in Listing 6-1.

Listing 6-1  Connecting to the base video output component

QTVideoOutputComponent baseVideoOutput;
OSErr err;
err = OpenADefaultComponent (kVideoOutputComponentType,
                             kVideoOutputComponentBaseSubType, 
                             &baseVideoOutput);
err = ComponentSetTarget (baseVideoOutput,
                         self);
globals->baseVideoOutput = baseVideoOutput;

Providing a Display Mode List

Your video output component must implement its own QTVideoOutputGetDisplayModeList function. This function is required for all video output components.

Starting Video Output

Listing 6-2 shows how your video output component can start video output.

Listing 6-2  Starting video output

pascal ComponentResult MyQTVideoOutputBegin (Globals storage)
{
    ComponentResult err;
    long mode;
    // call the default implementation
    err = QTVideoOutputBegin (storage->baseVideoOutput);
    if (err) goto bail;
    // get the selected mode
    err = QTVideoOutputGetDisplayMode (storage->self, &mode);
    if (err) goto bail;
    // switch the hardware to the selected mode
    // remember that we now own the hardware
    storage->ownHardware = true;
bail:
    if ((err != noErr) && (storage->ownHardware == true))
        QTVideoOutputEnd (storage-> baseVideoOutput);
    return err;
}

The default implementation of the QTVideoOutputBegin function ensures that the hardware is not currently in use by other software. It also ensures that a valid display mode has been set with either the QTVideoOutputSetDisplayMode function or the QTVideoRestoreSettings function.

Ending Video Output

Listing 6-3 shows how your video output component can stop video output. The implementation of this function is similar to the implementation of QTVideoOutputEnd, but here the default implementation must be called after the hardware has been released.

Listing 6-3  Ending video output

pascal ComponentResult MyQTVideoOutputEnd (Globals storage)
{
    ComponentResult err;
    // check that Begin has been called
    if (storage->ownHardware == false) {
        err = paramErr;
        goto bail;
    }
    // release the hardware
    // call default implementation
    QTVideoOutputEnd (storage->baseVideoOutput);
    // remember that we no longer own the hardware
    store->ownHardware = false;
bail:
    return err;
}

In the implementation of QTVideoOutputEnd, your component should also display a default image on the video output device to indicate that the device is no longer in use by other software.

Implementing the QTVideoOutputSaveState Function

If your video output component uses any custom settings, your component must implement its own QTVideoOutputSaveState function to save them. If your video output component has no custom settings, it can use the default QTVideoOutputSaveState implementation provided by the base video output component. Listing 6-4 shows an implementation of the QTVideoOutputSaveState function that saves custom settings. The function creates a QT atom container for storing the settings.

Listing 6-4  Extending the QTVideoOutputSaveState function

pascal ComponentResult MyQTVideoOutputSaveState (Globals storage,
                                        QTAtomContainer *settings) 
{
    OSErr err;
    // call default implementation
    err = QTVideoOutputSaveState (storage->baseVideoOutput, settings);
    if (err) goto bail;
 
    // add custom parameter(s)
    err = QTInsertChild (*settings,kParentAtomIsContainer,
                         'FOOB', 1, 0,
                         sizeof (storage->customSetting),
                         &storage->customSetting, nil);
    if (err) goto bail;
bail:
    return err;
}

Implementing the QTVideoOutputRestoreState Function

If your video output component saves custom settings with its own implementation of the QTVideoOutputSaveState function, it must also implement a QTVideoOutputRestoreState function to restore the settings. If your video output component has no custom settings, it can use the default QTVideoOutputRestoreState implementation provided by the base video output component. Listing 6-5 shows an implementation of the QTVideoOutputRestoreState function that restores custom settings from the QT atom container in which they are stored.

Listing 6-5  Restoring custom settings

pascal ComponentResult MyQTVideoOutputRestoreState (Globals storage,
                                        QTAtomContainer settings) 
{
    OSErr err;
    QTAtom atom;
    // call default implementation
    err = QTVideoOutputRestoreState (storage->baseVideoOutput, settings);
    if (err) goto bail;
    // get custom parameter(s)
    atom = QTFindChildByID (settings, kParentAtomIsContainer, 'FOOB',
                            1, nil);
    if (atom != 0) {
        long dataSize;
        Ptr dataptr;
        QTGetAtomDataPtr (settings, atom, &dataSize, &dataPtr);
        storage->customSetting = *(SettingsType *)dataPtr;
    }
    else {
        // reset custom settings to default values
    }
bail:
    return err;
}

Implementing the QTVideoOutputGetGWorldParameters Function

Your video output component must also implement the QTVideoOutputGetGWorldParameters. This function is not called by applications or other clients of your component; it is called by the base video output component as part of the implementation of the QTVideoOutputGetGWorld function.

pascal ComponentResult QTVideoOutputGetGWorldParameters (
    QTVideoOutputComponent vo,
    Ptr *baseAddr,
    long *rowBytes,
    CTabHandle *colorTable);

In the baseAddr parameter, your video output component must return the address at which to display pixels. If your component does not display pixels, return 0 for this parameter.

In the rowBytes parameter, your video output component must return the width of each scan line in bytes. If your component does not display pixels, return the width of the current display mode.

In the colorTable parameter, your video output component must return the color table to be used. If your component does not use a color table, return nil.

Controlling Other Hardware Features

If the video output device includes features that can be controlled by any of the following functions, the video output component must implement the functions for those features.

Delegating Other Component Calls

Your video output component’s dispatcher must delegate all component selectors it doesn’t handle itself to the base video output component. It can do this by calling the DelegateComponentCall function.

Closing the Connection to the Base Video Output Component

When your video output component closes, it must close its connection to the base video output component by calling the CloseComponent function.