Timecode Media Handler Functions

QuickTime includes support for timecode tracks. Timecode tracks allow you to store external timecode information, such as SMPTE timecodes, in your QuickTime movies. QuickTime provides a timecode media handler that interprets the data in these tracks. This chapter discusses the functions and structures that allow you to use the timecode media handler.

About Timecodes

The timecode media handler allows QuickTime movies to store timing information that is derived from the movie’s original source material. Every QuickTime movie contains QuickTime-specific timing information, such as frame duration. This information affects how QuickTime interprets and plays the movie.

The timecode media handler allows QuickTime movies to store additional timing information that is not created by or for QuickTime. This additional timing information would typically be derived from the original source material; for example, as a SMPTE timecode. In essence, you can think of the timecode media handler as providing a link between the digital QuickTime-specific timing information and the original analog timing information from the source material.

A movie’s timecode is stored in a timecode track. Timecode tracks contain

Apple Computer has defined the information that is stored in the track in a manner that is independent of any specific timecode standard. The format of this information is sufficiently flexible to accommodate all known timecode standards, including SMPTE timecoding. The timecode format information provides QuickTime the parameters for understanding the timecode and converting QuickTime time values into timecode time values (and vice versa).

One key timecode attribute relates to the technique used to synchronize timecode values with video frames. Most video source material is recorded at whole-number frame rates. For example, both PAL and SECAM video contain exactly 25 frames per second. However, some video source material is not recorded at whole-number frame rates. In particular, NTSC color video contains 29.97 frames per second (though it is typically referred to as 30 frames-per-second video). However, NTSC timecode values correspond to the full 30 frames-per-second rate; this is a holdover from NTSC black-and-white video. For such video sources, you need a mechanism that corrects the error that will develop over time between timecode values and actual video frames.

A common method for maintaining synchronization between timecode values and video data is called dropframe. Contrary to its name, the dropframe technique actually skips timecode values at a predetermined rate in order to keep the timecode and video data synchronized. It does not actually drop video frames. In NTSC color video, which uses the dropframe technique, the timecode values skip two frame values every minute, except for minute values that are evenly divisible by ten. So NTSC timecode values, which are expressed as HH:MM:SS:FF (hours, minutes, seconds, frames) skip from 00:00:59:29 to 00:01:00:02 (skipping 00:01:00:00 and 00:01:00:01). There is a flag in the timecode definition structure that indicates whether the timecode uses the dropframe technique.

You can make the toolbox display the timecode when a movie is played. Use the TCSetTimeCodeFlags function to turn the timecode display on and off. Note that the timecode track must be enabled for this display to work.

You store the timecode’s source identification information in a user data item. Create a user data item with a type value of TCSourceRefNameType. Store the source information as a text string. This information might contain the name of the videotape from which the movie was created, for example.

The timecode media handler provides functions that allow you to manipulate the source identification information. The following sample code demonstrates one way to set the source tape name in a timecode media’s sample description.

void setTimeCodeSourceName (Media timeCodeMedia,
                                TimeCodeDescriptionHandle tcdH,
                                Str255 tapeName, ScriptCode tapeNameScript)
{
    UserData srcRef;
    if (NewUserData(&srcRef) == noErr) {
        Handle nameHandle;
        if (PtrToHand(&tapeName[1], &nameHandle, tapeName[0]) == noErr) {
            if (AddUserDataText (srcRef, nameHandle,'name', 1,
                                        tapeNameScript) == noErr) {
                TCSetSourceRef (GetMediaHandler (timeCodeMedia),
                                        tcdH,
                                        srcRef);
            }
            DisposeHandle(nameHandle);
        }
        DisposeUserData(srcRef);
    }
}

Creating a Timecode Track

You can create a timecode track and media in the same manner that you create any other track. Call the NewMovieTrack function to create the timecode track, and use the NewTrackMedia function to create the track’s media. Be sure to specify a media type value of TimeCodeMediaType when you call the NewTrackMedia function.

You can define the relationship between a timecode track and one or more movie tracks using the toolbox’s new track reference functions. You then proceed to add samples to the track, as appropriate.

Each sample in the timecode track provides timecode information for a span of movie time. The sample includes duration information. As a result, you typically add each timecode sample after you have created the corresponding content track or tracks.

The timecode media sample description contains the control information that allows QuickTime to interpret the samples. This includes the timecode format information. The actual sample data contains a frame number that identifies one or more content frames that use this timecode. Stored as a long, this value identifies the first frame in the group of frames that use this timecode. In the case of a movie made from source material that contains no edits, you would only need one sample. When the source material contains edits, you typically need one sample for each edit, so that QuickTime can resynchronize the timecode information with the movie. Those samples contain the frame numbers of the frames that begin each new group of frames.

The timecode description structure defines the format and content of a timecode media sample description, as follows:

typedef struct TimeCodeDescription {
    long                descSize;           /* size of the structure */
    long                dataFormat;         /* sample type */
    long                resvd1;             /* reserved; set to 0 */
    short               resvd2;             /* reserved; set to 0 */
    short               dataRefIndex;       /* data reference index */
    long                flags;              /* reserved; set to 0 */
    TimeCodeDef         timeCodeDef;        /* timecode format information */
    long                srcRef[1];          /* source information */
} TimeCodeDescription, *TimeCodeDescriptionPtr, **TimeCodeDescriptionHandle;

Term

Definition

descSize

Specifies the size of the sample description, in bytes.

dataFormat

Indicates the sample description type (TimeCodeMediaTypeMovie Data Types).

resvd1

Reserved for use by Apple. Set this field to 0.

resvd2

Reserved for use by Apple. Set this field to 0.

dataRefIndex

Contains an index value indicating which of the media's data references contains the sample data for this sample description.

flags

Reserved for use by Apple. Set this field to 0.

timeCodeDef

Contains a timecode definition structure that defines timecode format information.

srcRef

Contains the timecode's source information. This is formatted as a user data item that is stored in the sample description. The media handler provides functions that allow you to get and set this data.

The timecode definition structure contains the timecode format information. This structure is defined as follows:

typedef struct TimeCodeDef {
    long            flags;              /* timecode control flags */
    TimeScale       fTimeScale;         /* timecode's time scale */
    TimeValue       frameDuration;      /* how long each frame lasts */
    unsigned char   numFrames;          /* number of frames per second */
} TimeCodeDef;

Parameter

Definition

flags

Contains flags that provide some timecode format information. The following flags are defined:

Flag

Definition

tcDropFrame

Indicates that the timecode drops frames occasionally in order to stay in synchronization. Some timecodes run at other than a whole number of frames per second. For example, NTSC video runs at 29.97 frames per second. In order to resynchronize between the timecode rate and a 30 frames-per-second playback rate, the timecode drops a frame at a predictable time (in much the same way that leap years keep the calendar synchronized). Set this flag to 1 if the timecode uses the dropframe technique.

tc24HourMax

Indicates that the timecode values wrap at 24 hours. Set this flag to 1 if the timecode hour value wraps (that is, returns to 0) at 24 hours.

tcNegTimesOK

Indicates that the timecode supports negative time values. Set this flag to 1 if the timecode allows negative values.

tcCounter

Indicates that the timecode should be interpreted as a simple counter, rather than as a time value. This allows the timecode to contain either time information or counter (such as a tape counter) information. Set this flag to 1 if the timecode contains counter information.

fTimeScale

Contains the time scale for interpreting the frameDuration field. This field indicates the number of time units per second.

frameDuration

Specifies how long each frame lasts, in the units defined by the fTimeScale field.

numFrames

Indicates the number of frames stored per second. In the case of timecodes that are interpreted as counters, this field indicates the number of frames stored per timer tick.

The best way to understand how to format and interpret the timecode definition structure is to consider an example. If you were creating a movie from an NTSC video source recorded at 29.97 frames per second, using SMPTE timecodes, you would format the timecode definition structure as follows:

    TimeCodeDef.flags = tcDropFrame | tc24HourMax;
    TimeCodeDef.fTimeScale = 2997;          /* units */
    TimeCodeDef.frameDuration = 100;        /* relates units to frames */
    TimeCodeDef.numFrames = 30;             /* whole frames per second */

The movie’s natural frame rate of 29.97 frames per second is obtained by dividing the fTimeScale value by the frameDuration (2997 / 100). Note that the flags field indicates that the timecode uses the dropframe technique to resync the movie’s natural frame rate of 29.97 frames per second with its playback rate of 30 frames per second.

Given a timecode definition, you can freely convert from frame numbers to time values and from time values to frame numbers. For a time value of 00:00:12:15 (HH:MM:SS:FF), you would obtain a frame number of 375 ((12*30) + 15). The timecode media handler provides a number of functions that allow you to perform these conversions.

When you use the timecode media handler to work with time values, the media handler uses timecode records to store the time values. The timecode record allows you to interpret the time information as either a time value (HH:MM:SS:FF) or a counter value. The timecode record is defined as follows:

typedef union TimeCodeRecord {
    TimeCodeTime        t;          /* value interpreted as time */
    TimeCodeCounter     c;          /* value interpreted as counter */
} TimeCodeRecord;
 
typedef struct TimeCodeTime {
    unsigned char       hours;      /* time: hours */
    unsigned char       minutes;    /* time: minutes */
    unsigned char       seconds;    /* time: seconds */
    unsigned char       frames;     /* time: frames */
} TimeCodeTime;
 
typedef struct TimeCodeCounter {
    long                counter;    /* counter value */
} TimeCodeCounter;

When you are working with timecodes that allow negative time values, the minutes field of the TimeCodeTime structure (TimeCodeRecord.t.minutesMovie Data Types) indicates whether the time value is positive or negative. If the tctNegFlag bit of the minutes field is set to 1, the time value is negative.