Tween Media Handlers

A tween track is a special track in a movie that is used exclusively as a modifier track. The data it contains, known as tween data, is used to generate values that modify the playback of other tracks, usually by interpolating values. The tween media handler sends these values to other media handlers; it never presents data. For an introduction to modifier tracks, see QuickTime Movie Internals Guide.

Typical tween components can just interpolate numeric values or can perform complex tweening, such as finding intermediate data between one matrix or polygon and another. These processes are described in Tween Components and Native Tween Types.

Using the Tween Media Handler

This section describes how to create a tween track and how to connect a tween track to the input map of the track(s) it will modify. Detailed code examples are provided.

You can use the tween media handler to send tween values from a tween track to a receiving track, such as a video track or a sound track. To send tween values, you must create a tween track. The Movie Toolbox routes the data from the tween track to the receiving track based upon the receiving track’s input map.

Creating a Tween Track

To create a tween track, you must:

  1. Create a tween track and its media.

  2. Create one or more tween media samples.

  3. Add the media samples to the tween media.

  4. Add the tween media to the track.

  5. Create a link from the tween track to the track to which the tween media handler should send tween values.

  6. Bind the tween entry to the desired attributes in the receiving track.

The sample code shown in this section creates a tween sample that interpolates a short integer from 255 to 0. The tween media is attached to the sound track of a QuickTime movie to modify the sound track’s volume. Thus it creates a volume fadeout using the tween track. The data type for the tween component is kTweenTypeShort.

The sample code shown in Listing 6-1 creates a new track (t) to be used as the tween track and new tween media (type TweenMediaType).

Listing 6-1  Creating a tween track and tween media

Track t;
Media md;
SampleDescriptionHandle desc;
// ...
// set up the movie, m
// ...
// allocate a sample description handle
desc = (SampleDescriptionHandle)NewHandleClear (
    sizeof (SampleDescription));
// create the tween track, t
t = NewMovieTrack (m, 0, 0, kNoVolume);
// create the tween media, md
md = NewTrackMedia (t, TweenMediaType, 600, nil, 0);
(**desc).descSize = sizeof(SampleDescription);

Next, your application must create a tween media sample. The tween media sample is a QT atom container structure that contains one or more kTweenEntry atoms. Each kTweenEntry atom defines a separate tween operation. A single tween sample can describe several parallel tween operations.

The sample code shown in Listing 6-2 creates a new QT atom container and inserts a kTweenEntry atom into the container. Then, it creates two leaf atoms, both children of the kTweenEntry atom. The first leaf atom (atom type kTweenType) contains the type of the tween data, in this case kTweenTypeShort. The second leaf atom (atom type kTweenData) contains the two data values for the tween operation, 512 and 0.

Remember that all data in QT atoms must be big-endian. The sample code shown in this section contains the endian conversion routines required for cross-platform compatibility.

Listing 6-2  Creating a tween sample

QTAtomContainer container = nil;
short tweenDataShort[2];
QTAtomType tweenType;
tweenDataShort[0] = EndianS16_NtoB(255);
tweenDataShort[1] = EndianS16_NtoB(0);
// create a new atom container to hold the sample
QTNewAtomContainer (&container);
// create the parent tween entry atom
QTInsertChild (container, kParentAtomIsContainer, kTweenEntry, 1, 0, 0,
    nil, &tweenAtom);
// add two child atoms to the tween entry atom
// * the type atom, kTweenType
tweenType = EndianU32_NtoB(kTweenTypeShort);
QTInsertChild (container, tweenAtom, kTweenType, 1, 0,
    sizeof(tweenType), &tweenType, nil);
// * the data atom, kTweenData
QTInsertChild (container, tweenAtom, kTweenData, 1, 0, sizeof(short) * 2,
    tweenDataShort, nil);

You do not have to start the tween at the beginning of the sample, nor do you have to stop at the end of the sample. You can specify the start of the tween and its duration by adding additional child atoms to the tween entry.

You can add a kTweenStartOffset atom to start the tween operation at 500 units into the sample with the following lines of code:

TimeValue time = EndianU32_NtoB(500);
QTInsertChild (container, tweenAtom, kTweenStartOffset, 1, 0,
    sizeof(TimeValue), &time, nil);

You can specify a duration for the tween operation independent of the sample’s duration by adding a kTweenDuration atom to the tween entry, as follows:

TimeValue duration = EndianU32_NtoB(1000);
QTInsertChild (container, tweenAtom, kTweenDuration, 1, 0,
    sizeof(TimeValue), &duration, nil);

Once the tween samples have been created, you can add them to the tween media and then add the tween media to the track, as shown in Listing 6-3.

Listing 6-3  Adding the tween sample to the media and the media to the track

// add the sample to the tween media
BeginMediaEdits (md);
AddMediaSample (md, container, 0,
    GetHandleSize(container), kSampleDuration, desc, 1, 0, nil);
EndMediaEdits(md);
// dispose of the sample description handle and the atom container
DisposeHandle ((Handle)desc);
QTDisposeAtomContainer(container);
// add the media to the track
InsertMediaIntoTrack(t, 0, 0, kSampleDuration, kFix1);

Once you have added the tween media to its track, you need to call the AddTrackReference function to create a link between the tween track to the receiving track. AddTrackReference returns the index of the reference it creates.

The sample code shown in Listing 6-4 retrieves the sound track from a movie and calls AddTrackReference to create a link between the tween track (t) and the sound track. The reference index is returned in the parameter referenceIndex.

Listing 6-4  Creating a link between the tween track and the sound track

Track soundTrack;
long referenceIndex;
// retrieve the sound track from the movie
soundTrack = GetMovieIndTrackType (theMovie, 1,
    AudioMediaCharacteristic,
    movieTrackCharacteristic | movieTrackEnabledOnly);
// create a link between the tween track and the sound track --
// on return, referenceIndex contains the index of the link
err = AddTrackReference (soundTrack, t, kTrackModifierReference,
                            &referenceIndex);

Once you have linked the tween track to its receiving track, you must update the input map of the receiving track’s media to indicate how the receiving track should interpret the data it receives from the tween track.

To do this, you create a QT atom container and insert an atom of type kTrackModifierInput whose ID is the index returned by the AddTrackReference function. Then, you insert two atoms as children of the kTrackModifierInput atom:

Once you have created the appropriate atoms in the input map, you call SetMediaInputMap to assign the input map to the receiving track’s media.

The code shown in Listing 6-5 creates an input map for the sound track of a movie. In this code, the tween media is linked to a sound track; the interpolated tween values are used to modify the sound track’s volume.

Listing 6-5  Binding a tween entry to its receiving track

QTAtomContainer inputMap = nil;
// create an atom container to hold the input map
if (QTNewAtomContainer (&inputMap) == noErr)
{
    QTAtom inputAtom;
    OSType inputType;
    long tweenID = 1;
    // create a kTrackModifierInput atom
    // whose ID is referenceIndex
    QTInsertChild(inputMap, kParentAtomIsContainer,
        kTrackModifierInput, referenceIndex, 0, 0, nil,
        &inputAtom);
    // add a child atom of type kTrackModifierTypeVolume
    inputType = EndianU32_NtoB(kTrackModifierTypeVolume);
    QTInsertChild (inputMap, inputAtom, kTrackModifierType, 1, 0,
      sizeof(inputType), &inputType, nil);
    // add a child atom for the ID of the tween to
    // modify the volume
    QTInsertChild (inputMap, inputAtom, kInputMapSubInputID, 1,
        0, sizeof(tweenID), &tweenID, nil);
    // assign the input map to the sound media
    SetMediaInputMap(GetTrackMedia(soundTrack), inputMap);
    // dispose of the input map
    QTDisposeAtomContainer(inputMap);
}

Tween Media Handler Constants

This section defines a QT atom type used for mapping a tween to the receiving track of a movie.

The following input type is defined for tween-related atoms:

enum {
    kInputMapSubInputID         = 'subi',
};

The kInputMapSubInputID type is the QT atom type for mapping a tween to a receiving track in a movie:

Term

Definition

kInputMapSubInputID

A leaf atom that contains the ID of a tween entry. You create a kInputMapSubInputID atom in a receiving track's input map to define the relationship between the tween entry and the receiving track.You create a kInputMapSubInputID atom as a child of a kTrackModifierInput atom.