Using QuickTime Streaming

This chapter describes from a programming perspective how to create, send, and receive streamed movies. Code samples for receiving and creating streaming movies are included.

Receiving Streaming Movies

An application receives streaming content by opening a movie and playing it.

Opening a Streaming Movie

In general, opening a streaming movie is like opening any QuickTime movie. You can open a streaming movie by opening

  • a movie file that contains streaming tracks

  • an SDP file

  • a URL

You can open a movie file that contains streaming tracks, or open an SDP file, by calling NewMovieFromFile in the usual way.

You open a movie from a URL by calling NewMovieFromDataRef with a URL data reference. The URL for a real-time streaming movie will use RTSP protocol. The following is a code sample for opening a movie from an RTSP URL:

char url[] = "rtsp://www.mycompany.com/mymovie.mov";
Handle urlDataRef;
 
urlDataRef = NewHandle(strlen(url) + 1);
if ( ( err = MemError()) != noErr) goto bail;
 
BlockMoveData(url, *urlDataRef, strlen(url) + 1);
 
err = NewMovieFromDataRef(&movieInfo->theMovie, newMovieActive,
    nil, urlDataRef, URLDataHandlerSubType);
DisposeHandle(urlDataRef);

It’s also possible to open a movie file from an HTTP or FTP URL, and it’s possible for that movie file to contain streaming tracks.

If you open a streaming movie from a URL or an SDP file, as shown in Figure 2-1, QuickTime will call the appropriate movie importer. If you open a movie file that contains streaming tracks, stream importers will be called.

Figure 2-1  Opening a streaming movie

Opening a streaming movie typically takes more time than opening a movie with purely local content. Each track in the movie on the server is transmitted as an RTP stream, so the client computer must establish a network connection with the server for each track, and often must establish a connection for RTSP control as well. This takes time, particularly if a dial-up connection must be established.

It also means that QuickTime can return connection status messages or networking errors in the process of opening a movie.

Playing A Streaming Movie

Applications that can already play QuickTime movies need to observe these cautions to play real-time streaming movies reliably:

  • Open movies with high-level Movie Toolbox calls or a movie importer.

  • Do not assume that the track structure of the movie you play reflects the track structure of the original movie; a streaming track can contain sound, video, text, MIDI, or all of these.

  • Use a movie controller to play the movie, or use the PrePrerollMovie function to set up any streams before playing the movie.

  • Display status messages returned by the movie controller.

  • Be prepared to deal with network errors when your application plays a movie (see Common Streaming Error Codes).

  • Be prepared for movie characteristics to change dynamically; the height, width, duration, and presence of audio or video can all change as the movie plays.

  • Do not assume that the movie will begin immediately.

The following sections describe some of these factors in more detail.

Track Structure

Unlike other QuickTime movies, streaming movies consist of two distinct movie files, one on the server and the other on the client machine, that often have different track structures. You sometimes need to distinguish between the server movie and the client movie. See Figure 2-2.

The media of each track in the server movie is transmitted as a separate RTP stream. On the client side, multiple RTP streams can be combined into a single streaming track.

If you open a movie from a URL, for example, the movie importer may create a client movie that contains only a streaming ('strm') track. Unlike most other QuickTime track types, a streaming track can contain multiple media streams of different types. A streaming track in a client movie may contain the URL of a server movie with audio, video, text, and/or MIDI tracks.

Figure 2-2  Server movie and client movie

The client movie file never contains audio or video media from the server movie; they are displayed and discarded. If a client movie is saved, the saved movie contains information such as the URL of the server movie and the currently-displayed movie time. The client movie can also contain local tracks and local media, but the media samples in the server movie remain on the server except when playing.

Pre-Prerolling

Before any movie is played, QuickTime needs to allocate buffers and open appropriate media handlers. This process is called prerolling the movie. Before a streaming movie can be played, additional steps need to be taken, such as establishing RTP streams between the client and the server. This setup process is called pre-prerolling. Pre-prerolling is performed automatically when a streaming movie is played using a movie controller. If your application uses movie controllers to play movies, you do not need to take any special steps to pre-preroll a streaming movie.

If you are playing movies using lower-level commands, you will need to use the PrePrerollMoviefunction to set up the network connections for a streaming movie before you can preroll or play the movie. The PrePrerollMovie function does nothing unless a movie contains streaming content, so it’s safe to call it for all movies. Here is a code sample:

    PrePrerollMovie(myMovie, 0, GetMoviePreferredRate(myMovie),
    NewMoviePrePrerollCompleteProc(MyMoviePrePrerollCompleteProc),
    (void *)0L);

PrePrerollMovie operates either synchronously or asynchronously, depending on whether you specify a completion procedure when you call it.

If called asynchronously, it returns almost immediately, even if the movie contains streaming content. This allows your application to perform other tasks while awaiting the completion of the pre-prerolling. You need to call MoviesTask periodically to grant time for the task of pre-prerolling when using it asynchronously.

When the pre-prerolling is finished, PrePrerollMovie calls the completion procedure whose address you pass in the NewMoviePrePrerollCompleteProc parameter. In the simplest case, the completion procedure will want to preroll and start the movie.

If no completion procedure is specified, PrePrerollMovie returns when the pre-preroll process is complete.

Reacting to Changes in Movie Characteristics

One feature of streamed movies is that their characteristics may change dynamically during playback. For example, when you open a movie from a URL you may not know the actual height and width of the movie, its duration, how many streams it contains, whether it has a sound track, or whether it is an audio-only movie.

QuickTime will assign default values to these characteristics if they are unknown. QuickTime can notify your application when the movie characteristics become known or are changed.

In most cases, your application will want to adjust the size of the window or pane that contains the movie to reflect such changes. You make these adjustments by implementing a movie controller action filter procedure.

To do this, you first need to indicate that you want to be informed of any changes. You do this by setting a movie playback hint:

SetMoviePlayHints(myMovie, hintsAllowDynamicResize,
        hintsAllowDynamicResize);

Changes in the movie size are announced to your filter procedure by the mcActionControllerSizeChanged selector. Changes in other movie characteristics are announced through the mcActionMovieEdited selector.

Size Changes

Whenever the size of the movie changes, the associated movie controller sends the mcActionControllerSizeChanged action to your movie controller action filter procedure. You can intercept that action and respond to it as follows:

pascal Boolean MyMCActionFilterProc (MovieController theMC, short theAction, void *theParams,
long theRefCon)
{
    Movie   myMovie = MCGetMovie(theMC);
        switch (theAction) {
            // handle window resizing
            case mcActionControllerSizeChanged:
                MyResizeWindow(myMovie);
                break;
            default:
                break;
        }
        return(false);
}

Duration Changes

The duration of a streaming movie or a streaming track may not be initially known. A track or movie whose duration is not known is assigned an indefinite duration: x7FFFFFF. If you do not treat this as a special case, a streaming movie will appear to your application as a very long movie indeed.

Once the pre-preroll process is complete, QuickTime should know the actual duration of the streams. If you set an action filter procedure and call SetMoviePlayHints, your application will be called with the mcActionMovieEdited selector when QuickTime determines the actual duration.

If the movie contains live content, it may not have a specific duration. In this case, the duration remains indefinite: x7FFFFFF. You might want to set a timeout in your code that detects the fact that QuickTime has not adjusted the duration from x7FFFFFF after a few seconds of movie play. QuickTimePlayer uses such a timeout and displays a “Live Transmission” message where the slider would be for a movie with a known duration.

Sound and Video Changes

Whether a streaming movie has sound ('ears') or is sound-only (no video) may not be initially known or may change dynamically. If you set an action filter procedure and call SetMoviePlayHints, your application will be called with the mcActionMovieEdited selector when the sound or video characteristics change.

Other Playback Considerations

Streaming movies only play back at a rate of 1. Other playback rates, such as playing backward, are not supported.

Common Streaming Error Codes

Here is a list of common streaming error codes. Applications that play streaming movies should deal gracefully with these errors.

// Streaming errors
-5400    // qtsBadSelectorErr
-5401    // qtsBadStateErr
-5402    // qtsBadDataErr
-5403    // qtsUnsupportedDataTypeErr
-5404    // qtsUnsupportedRateErr
-5405    // qtsUnsupportedFeatureErr
-5406    // qtsTooMuchDataErr
 
// Network errors
-5420    // connection failed (couldn't connect to the server)
 
// Open Transport errors, Macintosh only: -3150 to -3180, -3200 to -3285,
// plus the full range of OT error codes in file OpenTransport.h
 
-3150    // kOTBadAddressErr; a bad address was specified
-3170    // kOTBadNameErr; couldn't do name lookup
 
// Open Transport errors, Windows only
10061    // couldn't connect to server
 
// Streaming can return all QuickTime and Macintosh Toolbox errors.
// Common error codes returned include:
 
// QuickTime errors
-223    // siInvalidCompression; codec not installed
// Windows-specific errors when component is loading
-2092   // componentDllEntryNotFoundErr
 
// RTSP errors
// Most of these error codes are the same as for HTTP.
// These errors are usually generated from the server.
3xx    // redirect
400    // bad request
401    // unauthorized
402    // payment required
403    // forbidden
404    // not found (specified movie not found on server side)
405    // method not allowed
406    // not acceptable
407    // proxy authentication required
408    // request time-out
409    // conflict
410    // gone
411    // length required
412    // precondition failed
413    // request entity too large
414    // request URI too large
415    // unsupported media type
451    // parameter not understood
452    // conference not found
453    // not enough bandwidth
454    // session not founds
455    // method not valid in this state
456    // header field not valid for resource
457    // invalid range
458    // parameter is read only
459    // aggregate operation not allowed
460    // only aggregate operation allowed
461    // unsupported transport
462    // destination unreachable
500    // internal server error
501    // not implemented
502    // bad gateway
503    // service unavailable
504    // gateway timeout
505    // version not supported
551    // option not supported

Serving Streaming Movies

To serve QuickTime movies over RTP, your movie server must be equipped with RTP server software that understands the QuickTime file format, including the structure of hint tracks, which are described in the section Hint Track Structure. Your server also needs an RTSP controller application.

Your server does not need to have QuickTime software installed to serve streaming movies.

If your server is merely acting as a reflector for multicasts, no special software is required to reflect QuickTime movies. Forward the RTP streams on request in the usual way.

Your server uses the hint tracks in a streaming QuickTime movie to packetize the movie’s media into RTP streams. Hint tracks are added to QuickTime movies to prepare them for streaming over RTP. One hint track is added to the movie for each track whose media will be streamed, as illustrated in Figure 2-3.

Figure 2-3  Streaming a hinted movie

If your server is sending a unicast of a hinted movie, the QuickTime movie controller will provide the client with the ability to pause the movie and to skip backward and forward in movie time. This will be communicated to your server over RTSP.

The RTP server does not need to know about QuickTime media types or codecs. The hint tracks within the movie file provide the information needed to turn QuickTime media into RTP packets. Each hint track contains the data needed to build packet headers for a specific track’s media. The hint track also supplies a pointer to the media data that goes into each packet.

The RTP server needs to be able to parse a QuickTime movie file sufficiently to find each hint track, then to find the track and sample data that the hint track points to. The hint track contains any precalculated values that may be needed, making it easier for the server to create the RTP packets.

Hint tracks offload a great deal of computation from the RTP server. Consequently, you may find that an RTP server is able to send data more efficiently if it is contained in a QuickTime movie, even if the RTP server already understands the media type, codec, and RTP packing being used.

For example, the H.263+ video codec is an IETF-standard RTP format which your server may already understand, but creating an H.263+ stream from video data requires complex calculations to properly determine packet boundaries. This information is precalculated and stored in the hint track when H.263+ video is contained in a QuickTime movie, allowing your server to packetize the data quickly and efficiently.

If you are writing QuickTime extensions to an RTP server application, you will need to read the QuickTime File Format documentation, as well as Hint Tracks in this document.

Hint Tracks

You prepare a QuickTime movie for RTP streaming by adding hint tracks. Hint tracks allow an RTP server to stream QuickTime movies without requiring the RTP server to understand QuickTime media types, codecs, or packing. The RTP server needs to understand the QuickTime file format sufficiently to find tracks and media samples in a QuickTime movie, however.

Each track in a QuickTime movie is sent as a separate RTP stream, and the recipe for packetizing each stream is contained in a corresponding hint track. Each sample in a hint track tells the RTP server how to packetize a specific amount of media data. The hint track sample contains any data needed to build a packet header of the correct type, and also contains a pointer to the block of media data that belongs in the packet.

There is at least one hint track for each media track to be streamed. It is possible to create multiple hint tracks for a given track’s media, optimized for streaming the same media over networks with different packet sizes, for example. The hinter included in QuickTime creates one hint track for each track to be streamed.

Hint tracks are structured in the same way as other QuickTime movie tracks. Standard QuickTime data structures, such as track references, are used to point to data. In order to serve a QuickTime movie, your RTP server must locate the hint tracks contained in the movie and parse them to find the packet data they point to. You should review the QuickTime File Format documentation before you read the remainder of this hint track information. You will also find it helpful to refer to the QuickTime File Format periodically in the course of reading this document.

Hint Track Structure

Hint tracks are atoms of type 'trak'. A hint track atom contains a track header atom ('tkhd'), an edits atom ('edts'), a track reference atom ('tref'), a media atom ('mdia'), and usually a track user data atom ('udta'). The atoms are normally present in the order described, but this is not a requirement. Most of these atoms have child atoms. An expanded diagram of a typical hint track atom is shown in Figure 2-4.

Figure 2-4  A typical hint track atom

A detailed description of each atom’s contents follows. This document focuses on atom contents that are specific to hint tracks. Refer to the QuickTime File Format documentation for generic information about the structure and contents of the atom types found in track atoms.

Track Header Atom

The flags field of the track header atom must be 0x000000, indicating the track is inactive, and not part of the movie, preview, or poster. Hint tracks must be marked as inactive for the movie to play locally.

The creation time, modification time, and track ID fields are set as they would be for any track.

The duration field is also the duration of the media track being hinted, expressed in movie time scale.

The layer field is not used.

The alternate group field can be used to distinguish alternate language or alternate data rate tracks in streaming movies. It is not required that all servers support this feature. It is not recommended that applications attempt to make use of this feature at this time. This field is normally set to 1.

The remaining track header fields are not used for hint tracks.

Unused fields should be set to 0 when creating hint tracks and ignored when using them.

Edits Atom

The edits atom contains an edits list atom ('elst'). Edit lists can be used for hint tracks as they can for any other track type.

The fields of the edits list atom ('elst') are used as follows:

The flags field is not used, and should be set to 0.

The numEntries field is the number of list entries. Unless the hint track has been edited, it will have either 1 or 2 entries.

Each list entry consists of a duration, a media time, and a rate.

If the track should begin playing after the movie begins, there is an “empty edit” whose duration is the amount of time that passes until the track begins playing, whose media time is -1, and whose media rate is 1. No data should be sent for this track until the number of movie time units specified by the duration field has passed.

Whether or not there is an empty edit, there will typically be one entry whose duration is the media duration in movie timescale units, whose media time is 0, and whose rate is 1.

Track Reference Atom

Each hint track refers to a media track. The hint track contains a track reference atom ('tref') that contains exactly one child atom of type 'hint'. This child atom holds the track ID of the media track. The whole track reference atom has this structure:

Atom Type

Field

Bytes

Description

Track Reference

Contains a 'hint' atom

  

Size

4

Size of track reference atom (including 'hint' atom); 32-bit integer.

  

Type

4

'tref'

Track Hint

Contains the track ID of the media track being hinted

  

Size

4

Size of this child atom; 32-bit integer.

  

Type

4

'hint'

  

TrackID

4

Track ID of the media track being hinted; 32-bit integer.

The Track ID field of the 'hint' atom contains the track ID of the media track being hinted. The target track ID can be found in the media track’s track header atom ('tkhd'). All media sample data should be taken from the specified media track.

There could theoretically be a list of track IDs for a hint track that hinted multiple media tracks, but the current hinter only references one media track per hint track.

Creating Streaming Movies

Streaming movies come in two forms: server movies and client movies.

You create a server movie that can be streamed over RTP by adding hint tracks. Hint tracks tell the server how to packetize the movie. You add hint tracks by exporting a movie as a hinted movie using QuickTime’s standard movie export mechanism.

You create a client movie that includes streaming content by adding one or more streaming tracks. A streaming track tells the client where to get the streaming media. In its simplest form, a client movie consists of just a streaming track containing the URL of a movie on a server. A client movie can contain multiple streaming tracks.

A client movie can contain non-streaming tracks with local media content as well as streaming tracks. Streaming tracks can be composited with local tracks. For example, a streaming track could be used as the source for an effect track that is local to the client movie.

Server Movies

You create a streaming movie for an RTP server by adding hint tracks to an existing movie. You do this by calling ConvertMovieToFile, which invokes a movie exporter component. This displays a standard dialog box that lets the user specify “Export Movie to Hinted Movie,” set the parameters for hinting the movie, select compressors, and specify a file name and directory for the hinted movie (see Figure 2-5).

The hinting is performed by media packetizer components. QuickTime selects an appropriate media packetizer for each track and routes each packetizer’s output through an Apple-provided packet builder to create a hint track. One hint track is created for each streamable track in the movie.

Figure 2-5  Exporting a hinted movie

Hint tracks are quite small compared with audio or video tracks. A movie that contains hint tracks can be played from a local disk or streamed over HTTP, like any other QuickTime movie. The hint tracks are only used when streaming the movie over RTP.

As long as your application supports movie exporter components, it should be able to create hinted movies. If you want to bypass the standard dialog for user input, selecting “Export Movie to Hinted Movie” programmatically, you will need to modify your code by adding the appropriate selectors.

A hinted movie does not need to be self-contained (flattened). It can reference sample media contained in other files. But observe these cautions:

  • Use file names that are transportable between the system that the movies are created on and the RTP server.

  • The relative path from the movie file to the data files must not change after the movie is saved.

  • The simplest way to ensure both of these is to use only lowercase letters in file names, without spaces, and to keep the media data files and the movie file in the same folder or directory.

  • Hint tracks should be created as the last step in making a streaming movie. Any editing of the movie that adds or deletes sample data, including the flattening of a movie with edit lists, invalidates the hint track. If your application edits a hinted movie in a way that invalidates the hint tracks, delete the hint tracks and re-export the movie.

Hint tracks are marked as inactive so they do not interfere with local playback. If you call FlattenMovie with the flattenActiveTracksOnly flag, the hint tracks are deleted from the flattened movie.

This release of QuickTime supports RTP streaming of video, audio, text (including HREF Tracks), and MIDI. If your movie contains other media types, or features that rely on track references, you cannot currently export the entire movie to a hinted movie. You can either stream such movies over HTTP, or you can put some of the tracks into a client movie and stream the rest, as described in the section Compositing Streaming and Non-Streaming Tracks.

Client Movies

You incorporate streaming content in a client movie by adding at least one streaming track. The simplest form of client movie has only one track: a streaming track with the URL of a movie on a server.

A streaming track has a media type of kQTSStreamMediaType ('strm') and contains a single media sample: typically either an RTSP URL of a streaming movie or the SDP text describing a multicast.

The code example in Listing 2-1 shows how to create a streaming track, insert a sample description, and add a URL media sample.

Listing 2-1  Creating a streaming track with an RTSP URL

Handle dataRef;
long dataLength;
char url[] = "rtsp://myserver.bigcompany.com/mystreaming.mov";
dataRef = NewHandle(strlen(url) + 1);
BlockMoveData(url, *urlDataRef, strlen(url) + 1);
dataLength = GetHandleSize(dataRef);
newMedia = NewTrackMedia(newTrack, kQTSStreamMediaType,
        kQTSMediaTimeScale, handleDataRef, HandleDataHandlerSubType);
err = BeginMediaEdits(newMedia);
qtsDesc =
(QTSSampleDescriptionHandle)NewHandleClear(sizeof(QTSSampleDescription));
(**qtsDesc).descSize = sizeof(QTSSampleDescription);
(**qtsDesc).dataFormat = 'rtsp';
(**qtsDesc).dataRefIndex = 1;
(**qtsDesc).version = kQTSSampleDescriptionVersion;
duration = kQTSInfiniteDuration;
err = AddMediaSample(newMedia, dataRef, 0, dataLength, duration,
        (SampleDescriptionHandle)qtsDesc, 1, 0, nil);
err = EndMediaEdits(newMedia);
err = InsertMediaIntoTrack(newTrack, 0, 0, GetMediaDuration(newMedia),
        kQTSNormalForwardRate);

A streaming track in a client movie can point to a server movie containing audio, video, text, and MIDI tracks. Any or all of the tracks in the server movie can appear as a single streaming track in the client movie.

To sum up:

  • A client-side streaming movie contains at least one streaming 'strm' track.

  • A streaming track contains a single media sample, typically an RTSP URL that points to streaming content. It can also contain SDP information for a multicast.

  • The streaming content can be a live stream or a stored movie on a streaming server.

  • The movie on the server can contain any number of tracks; multiple tracks in the server movie may be represented in the client movie as a single streaming track.

Compositing Streaming and Non-Streaming Tracks

A client movie can contain non-streaming tracks with locally-stored media, in addition to one or more streaming tracks. Use this technique to add a live stream to a locally-stored movie, or to distribute a movie on CD-ROM that references the latest version of some media stored on a server.

You can composite a streaming track with local tracks. A streaming track can be positioned in time and space like any other track. Bear in mind that the streaming track may contain more than one video, audio, text, or other streams, however.

If your application creates movies, you will want to provide options for creating a server movie and a client movie from the same data, as well as providing options for putting some tracks in the server movie and some in the client movie.

Ordinarily, you create a streaming movie by exporting a movie as a hinted movie, putting that hinted movie on an RTP server, and creating a client movie that contains the URL of the movie on the server.

Sometimes, however, you will want to export part of an existing movie to a hinted server movie while incorporating other parts in the client movie. You might do this to stream the audio and video parts of a movie over RTP, while streaming wired sprites or chapter lists over HTTP.

For example, to create a streaming movie with a chapter list, extract the text track containing the chapter list from the movie and export the remainder as a hinted movie. Create a client movie with just a streaming track containing the URL of the hinted movie. Add the extracted text track to the client movie and make it a chapter list by adding a track reference to the streaming track. The client movie now contains:

The server movie contains the original movie, minus the chapter list, plus hint tracks.

You would use a similar technique to stream a movie with QuickTime video effects, storing the effects tracks in the client movie and applying the track references to the streaming tracks that act as sources to the effects.