Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
QTSndTween.c
// |
// File: QTSndTween.c |
// |
// Contains: Sound tweening support for QuickTime movies. |
// |
// Written by: Tim Monroe |
// based largely on the tween sample code in the QuickTime 2.5 Developers Guide |
// and the sample code QT3DTween.c. |
// |
// Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <3> 03/21/00 rtm made changes for running under CarbonLib |
// <2> 05/26/98 rtm set the time scale of the sound track media to that of the movie, |
// using revised code from Peter Hoddie |
// <1> 04/10/98 rtm first file; revised to personal coding style |
// |
// |
// This sample shows how to modify an existing QuickTime movie so that the volume of its sound track |
// is gradually increased (or decreased) as the movie plays. We do this by adding a tween track to |
// the movie and linking the tween track to the existing sound track. |
// |
// NOTES: |
// |
// *** (1) *** |
// For complete information on creating tween media tracks, see the chapter "Tween Media Handler Components" |
// in the QuickTime 2.5 or 3.0 Developers Guide. |
// |
// |
#include <FixMath.h> |
#include <Sound.h> |
#include "QTSndTween.h" |
// global variables |
// this variable determines what kind of tween data we add to the movie |
Boolean gTweenLoToHigh = true; // do we start at no volume and end at full volume? |
////////// |
// |
// QTSndTween_AddTweenTrackToMovie |
// Add a tween track to a QuickTIme movie. |
// |
////////// |
OSErr QTSndTween_AddTweenTrackToMovie (Movie theMovie) |
{ |
Track mySndTrack = NULL; |
Track myTrack; |
Media myMedia; |
StandardFileReply myReply; |
SampleDescriptionHandle mySampleDesc = NULL; |
QTAtomContainer mySample = NULL; |
QTAtomContainer myInputMap = NULL; |
QTAtom myAtom = 0; |
QTAtom myInputAtom = 0; |
short myTweenData[2]; |
long myRefIndex; |
TimeRecord myTimeRec; |
OSErr myErr = noErr; |
if (theMovie == NULL) |
goto bail; |
////////// |
// |
// get the (first) sound track from the movie |
// |
////////// |
mySndTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly); |
if (mySndTrack == NULL) |
goto bail; |
////////// |
// |
// create the tween track and media, and a sample to contain the tween data |
// |
////////// |
// create the tween track and media |
myTrack = NewMovieTrack(theMovie, 0, 0, kNoVolume); |
myMedia = NewTrackMedia(myTrack, TweenMediaType, kTweenTimeScale, NULL, 0); |
// create a new sample; this sample will hold the tween data |
myErr = QTNewAtomContainer(&mySample); |
if (myErr != noErr) |
goto bail; |
myTweenData[0] = gTweenLoToHigh ? EndianU16_NtoB(0) : EndianU16_NtoB(512); |
myTweenData[1] = gTweenLoToHigh ? EndianU16_NtoB(512) : EndianU16_NtoB(0); |
// make a tween entry for that data; |
// a tween entry is a parent atom that contains leaf atoms describing the tweening operation |
myErr = QTSndTween_AddTweenEntryToSample(mySample, kSoundTweenID, kTweenTypeShort, &myTweenData, sizeof(myTweenData)); |
if (myErr != noErr) |
goto bail; |
// create the sample description |
mySampleDesc = (SampleDescriptionHandle)NewHandleClear(sizeof(SampleDescription)); |
if (mySampleDesc == NULL) |
goto bail; |
(**mySampleDesc).descSize = sizeof(SampleDescription); |
// add the tween sample to the media |
BeginMediaEdits(myMedia); |
// set the time scale of the media to that of the movie |
myTimeRec.value.lo = GetTrackDuration(mySndTrack); |
myTimeRec.value.hi = 0; |
myTimeRec.scale = GetMovieTimeScale(theMovie); |
ConvertTimeScale(&myTimeRec, GetMediaTimeScale(myMedia)); |
myErr = AddMediaSample(myMedia, mySample, 0, GetHandleSize(mySample), myTimeRec.value.lo, (SampleDescriptionHandle)mySampleDesc, 1, 0, NULL); |
if (myErr != noErr) |
goto bail; |
EndMediaEdits(myMedia); |
// add the media to the track |
InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1); |
// dispose of some things we no longer need |
QTDisposeAtomContainer(mySample); |
DisposeHandle((Handle)mySampleDesc); |
////////// |
// |
// create a link between the sound track and the tween track, and update the sound track's input map |
// |
////////// |
// first, create a new atom container |
myErr = QTNewAtomContainer(&myInputMap); |
if (myErr != noErr) |
goto bail; |
// for *each* tween entry in the tween media sample, |
// create a link between the sound track and the tween track, and add an entry to the input map |
myErr = AddTrackReference(mySndTrack, myTrack, kTrackModifierReference, &myRefIndex); |
if (myErr != noErr) |
goto bail; |
myErr = QTSndTween_AddTweenEntryToInputMap(myInputMap, myRefIndex, kSoundTweenID, kTrackModifierTypeVolume, NULL); |
if (myErr != noErr) |
goto bail; |
// attach the input map to the sound media |
myErr = SetMediaInputMap(GetTrackMedia(mySndTrack), myInputMap); |
if (myErr != noErr) |
goto bail; |
// dispose of the input map |
QTDisposeAtomContainer(myInputMap); |
////////// |
// |
// finish up |
// |
////////// |
// save the new movie file; if you are running under CarbonLib, change this to use Navigation Services |
StandardPutFile("\pSave Movie as:", "\pNewMovie.mov", &myReply); |
if (myReply.sfGood) { |
FlattenMovieData(theMovie, flattenAddMovieToDataFork, &myReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile); |
myErr = GetMoviesError(); |
} |
bail: |
return(myErr); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Tween utilities. |
// |
// Use these functions add tween entries to samples or to add attributes to tween entries. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// QTSndTween_AddTweenEntryToSample |
// Add a tween entry to the specified sample. |
// |
// A tween entry defines a set of values for a single tweening operation. A tween entry is a parent atom |
// whose children define the tween data type, the tween data, and additional attributes of the operation. |
// |
// The data specified in the theData parameter is assumed to be in big-endian format. |
// |
////////// |
OSErr QTSndTween_AddTweenEntryToSample (QTAtomContainer theSample, QTAtomID theID, QTAtomType theType, void *theData, long theDataSize) |
{ |
OSErr myErr = noErr; |
QTAtom myAtom; |
// create an entry for this tween in the sample |
myErr = QTInsertChild(theSample, kParentAtomIsContainer, kTweenEntry, theID, 0, 0, NULL, &myAtom); |
if (myErr != noErr) |
goto bail; |
// set the type of this tween entry |
theType = EndianU32_NtoB(theType); |
myErr = QTInsertChild(theSample, myAtom, kTweenType, 1, 0, sizeof(theType), &theType, NULL); |
if (myErr != noErr) |
goto bail; |
// set the data for this tween entry |
myErr = QTInsertChild(theSample, myAtom, kTweenData, 1, 0, theDataSize, theData, NULL); |
bail: |
return(myErr); |
} |
////////// |
// |
// QTSndTween_AddTweenEntryToInputMap |
// Add a tween entry to the specified input map. |
// |
////////// |
OSErr QTSndTween_AddTweenEntryToInputMap (QTAtomContainer theInputMap, long theRefIndex, long theID, OSType theType, char *theName) |
{ |
QTAtom myInputAtom; |
OSErr myErr = noErr; |
// add an entry to the input map |
myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, theRefIndex, 0, 0, NULL, &myInputAtom); |
if (myErr != noErr) |
goto bail; |
// add two child atoms to the parent atom; |
// these atoms define the type of the modifier input and the ID of the tween entry atom |
theType = EndianU32_NtoB(theType); |
myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(OSType), &theType, NULL); |
if (myErr != noErr) |
goto bail; |
theID = EndianU32_NtoB(theID); |
myErr = QTInsertChild(theInputMap, myInputAtom, kInputMapSubInputID, 1, 0, sizeof(long), &theID, NULL); |
if (myErr != noErr) |
goto bail; |
// set the name of the input atom |
if (theName != NULL) { |
long myLength = 1; |
Ptr myPtr = theName; |
UInt16 *myShort; |
// determine the length of the name string |
while (*myPtr++) |
myLength++; |
// convert the name string to the proper endian format |
myPtr = theName; |
while (*myPtr) { |
myShort = (UInt16 *)myPtr; |
*myPtr = EndianU16_NtoB(*myShort); |
myPtr = myPtr + 2; // point to next word |
} |
myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierInputName, 1, 0, myLength, theName, NULL); |
} |
bail: |
return(myErr); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14