home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: AddEffectSegment.c
- //
- // Contains: Sample code for adding a visual effect to a segment of a movie.
- //
- // Written by: Tim Monroe
- //
- // Copyright: © 1999 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <2> 05/06/99 rtm tested on Mac and Windows; works fine
- // <1> 05/05/99 rtm first file; some functions based on some existing code
- // in QTShowEffect
- //
- // This file contains some sample code that adds a QuickTime effect to a part of a movie;
- // we assume that the movie already exists and that it contains one or more video tracks.
- // Our job here is to add a specified effect at a specified time. For one- or two-source
- // effects, the principal value in this code consists in illustrating how to duplicate the
- // portion(s) of the existing video track(s) for use as the effects source track(s).
- //
- //////////
-
- #include "AddEffectSegment.h"
-
-
- //////////
- //
- // QTEffSeg_AddEffectToMovieSegment
- // Add the specified effect to occur at the specified time and duration.
- //
- //////////
-
- OSErr QTEffSeg_AddEffectToMovieSegment (Movie theMovie, OSType theEffectType, long theNumSources, TimeValue theStartTime, TimeValue theDuration)
- {
- Track myVidTrack1 = NULL;
- Track myVidTrack2 = NULL;
- Track mySrcTrack1 = NULL;
- Track mySrcTrack2 = NULL;
- Media mySrcMedia1 = NULL;
- Media mySrcMedia2 = NULL;
- Track myEffectTrack = NULL;
- Media myEffectMedia = NULL;
- Fixed myWidth, myHeight;
- TimeScale myTimeScale;
- TimeValue mySampleTime;
- Rect myRect;
- QTAtomContainer myInputMap = NULL;
- QTAtomContainer myEffectDesc = NULL;
- ImageDescriptionHandle mySampleDesc = NULL;
- OSType myEffectName1 = kSourceNoneName;
- OSType myEffectName2 = kSourceNoneName;
- short myLayer;
- OSErr myErr = noErr;
-
- //////////
- //
- // get some information about the movie
- //
- //////////
-
- // make sure we were passed a valid movie
- if (theMovie == NULL)
- return(paramErr);
-
- myTimeScale = GetMovieTimeScale(theMovie);
- GetMovieBox(theMovie, &myRect);
- myLayer = QTEffSeg_GetFrontmostTrackLayer(theMovie, VideoMediaType);
-
- myWidth = (myRect.right - myRect.left) << 16;
- myHeight = (myRect.bottom - myRect.top) << 16;
-
- //////////
- //
- // retrieve the original video track(s), create the effect's source track(s) and media,
- // then set the new source track(s) to reference the data in the original video track(s)
- //
- //////////
-
- switch (theNumSources) {
- case 2:
- myVidTrack2 = GetMovieIndTrackType(theMovie, 2, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
- if (myVidTrack2 == NULL)
- return(paramErr);
-
- mySrcTrack2 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
- if (mySrcTrack2 == NULL)
- return(paramErr);
-
- mySrcMedia2 = NewTrackMedia(mySrcTrack2, VideoMediaType, myTimeScale, NULL, 0);
- if (mySrcMedia2 == NULL)
- return(paramErr);
-
- #if COPY_MOVIE_MEDIA
- myErr = BeginMediaEdits(mySrcMedia2);
- if (myErr != noErr)
- return(myErr);
- #endif
- myErr = CopyTrackSettings(myVidTrack2, mySrcTrack2);
- myErr = InsertTrackSegment(myVidTrack2, mySrcTrack2, theStartTime, theDuration, theStartTime);
- if (myErr != noErr)
- return(myErr);
-
- #if COPY_MOVIE_MEDIA
- EndMediaEdits(mySrcMedia2);
- #endif
- myEffectName2 = kSourceTwoName;
-
- // note that we fall through here!
-
- case 1:
- myVidTrack1 = GetMovieIndTrackType(theMovie, 1, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
- if (myVidTrack1 == NULL)
- return(paramErr);
-
- mySrcTrack1 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
- if (mySrcTrack1 == NULL)
- return(paramErr);
-
- mySrcMedia1 = NewTrackMedia(mySrcTrack1, VideoMediaType, myTimeScale, NULL, 0);
- if (mySrcMedia1 == NULL)
- return(paramErr);
-
- #if COPY_MOVIE_MEDIA
- myErr = BeginMediaEdits(mySrcMedia1);
- if (myErr != noErr)
- return(myErr);
- #endif
- myErr = CopyTrackSettings(myVidTrack1, mySrcTrack1);
- myErr = InsertTrackSegment(myVidTrack1, mySrcTrack1, theStartTime, theDuration, theStartTime);
- if (myErr != noErr)
- return(myErr);
-
- #if COPY_MOVIE_MEDIA
- EndMediaEdits(mySrcMedia1);
- #endif
- myEffectName1 = kSourceOneName;
-
- break;
-
- case 0:
- // for 0-source effects, we don't need to create any new source track
- break;
-
- default:
- return(paramErr);
- }
-
- //////////
- //
- // create the effects track and media
- //
- //////////
-
- myEffectTrack = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
- if (myEffectTrack == NULL)
- return(GetMoviesError());
-
- myEffectMedia = NewTrackMedia(myEffectTrack, VideoMediaType, myTimeScale, NULL, 0);
- if (myEffectMedia == NULL)
- return(GetMoviesError());
-
- // create an effect sample description
- mySampleDesc = QTEffSeg_MakeSampleDescription(theEffectType, myWidth >> 16, myHeight >> 16);
- if (mySampleDesc == NULL)
- goto bail;
-
- // create an effect description
- myEffectDesc = QTEffSeg_CreateEffectDescription(theEffectType, myEffectName1, myEffectName2);
-
- // add the effect description as a sample to the effect track media
- BeginMediaEdits(myEffectMedia);
-
- myErr = AddMediaSample(myEffectMedia, (Handle)myEffectDesc, 0, GetHandleSize((Handle)myEffectDesc), theDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime);
- if (myErr != noErr)
- goto bail;
-
- EndMediaEdits(myEffectMedia);
-
- // add the media sample to the effects track
- myErr = InsertMediaIntoTrack(myEffectTrack, theStartTime, mySampleTime, theDuration, fixed1);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // create the input map and add references for the source track(s)
- //
- //////////
-
- myErr = QTNewAtomContainer(&myInputMap);
- if (myErr != noErr)
- goto bail;
-
- if (mySrcTrack1 != NULL) {
- myErr = QTEffSeg_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack1, kSourceOneName);
- if (myErr != noErr)
- goto bail;
- }
-
- if (mySrcTrack2 != NULL) {
- myErr = QTEffSeg_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack2, kSourceTwoName);
- if (myErr != noErr)
- goto bail;
- }
-
- // add the input map to the effects track
- myErr = SetMediaInputMap(myEffectMedia, myInputMap);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // do any required positioning and graphics mode manipulation
- //
- //////////
-
- SetTrackLayer(myEffectTrack, myLayer - 1); // in front of any existing video track
-
- switch (theNumSources) {
- case 2:
- break;
-
- case 1:
- break;
-
- case 0: {
- RGBColor myColor;
-
- myColor.red = 0; // (good for fire, not so good for clouds)
- myColor.green = 0;
- myColor.blue = 0;
-
- MediaSetGraphicsMode(GetMediaHandler(myEffectMedia), transparent, &myColor);
- break;
- }
- }
-
- bail:
- if (mySampleDesc != NULL)
- DisposeHandle((Handle)mySampleDesc);
-
- if (myInputMap != NULL)
- QTDisposeAtomContainer(myInputMap);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTEffSeg_CreateEffectDescription
- // Create an effect description for zero, one, or two sources.
- //
- // The effect description specifies which video effect is desired and the parameters for that effect.
- // It also describes the source(s) for the effect. An effect description is simply an atom container
- // that holds atoms with the appropriate information.
- //
- // Note that because we are creating an atom container, we must pass big-endian data (hence the calls
- // to EndianU32_NtoB).
- //
- // The caller is responsible for disposing of the returned atom container, by calling QTDisposeAtomContainer.
- //
- //////////
-
- QTAtomContainer QTEffSeg_CreateEffectDescription (OSType theEffectName, OSType theSourceName1, OSType theSourceName2)
- {
- QTAtomContainer myEffectDesc = NULL;
- OSType myType;
- OSErr myErr = noErr;
-
- // create a new, empty effect description
- myErr = QTNewAtomContainer(&myEffectDesc);
- if (myErr != noErr)
- goto bail;
-
- // create the effect ID atom: the atom type is kParameterWhatName, and the atom ID is kParameterWhatID
- myType = EndianU32_NtoB(theEffectName);
- myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, 0, sizeof(myType), &myType, NULL);
- if (myErr != noErr)
- goto bail;
-
- // add the first source, if it's not kSourceNoneName
- if (theSourceName1 != kSourceNoneName) {
- myType = EndianU32_NtoB(theSourceName1);
- myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myType), &myType, NULL);
- if (myErr != noErr)
- goto bail;
- }
-
- // add the second source, if it's not kSourceNoneName
- if (theSourceName2 != kSourceNoneName) {
- myType = EndianU32_NtoB(theSourceName2);
- myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myType), &myType, NULL);
- }
-
- bail:
- return(myEffectDesc);
- }
-
-
- //////////
- //
- // QTEffSeg_AddTrackReferenceToInputMap
- // Add a track reference to the specified input map.
- //
- //////////
-
- OSErr QTEffSeg_AddTrackReferenceToInputMap (QTAtomContainer theInputMap, Track theTrack, Track theSrcTrack, OSType theSrcName)
- {
- OSErr myErr = noErr;
- QTAtom myInputAtom;
- long myRefIndex;
- OSType myType;
-
- myErr = AddTrackReference(theTrack, theSrcTrack, kTrackModifierReference, &myRefIndex);
- if (myErr != noErr)
- goto bail;
-
- // add a reference atom to the input map
- myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex, 0, 0, NULL, &myInputAtom);
- if (myErr != noErr)
- goto bail;
-
- // add two child atoms to the parent reference atom
- myType = EndianU32_NtoB(kTrackModifierTypeImage);
- myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myType), &myType, NULL);
- if (myErr != noErr)
- goto bail;
-
- myType = EndianU32_NtoB(theSrcName);
- myErr = QTInsertChild(theInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myType), &myType, NULL);
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // QTEffSeg_MakeSampleDescription
- // Return a new image description with default and specified values.
- //
- //////////
-
- ImageDescriptionHandle QTEffSeg_MakeSampleDescription (OSType theEffectType, short theWidth, short theHeight)
- {
- ImageDescriptionHandle mySampleDesc = NULL;
-
- #if USES_MAKE_IMAGE_DESC_FOR_EFFECT
- OSErr myErr = noErr;
-
- // create a new sample description
- myErr = MakeImageDescriptionForEffect(theEffectType, &mySampleDesc);
- if (myErr != noErr)
- return(NULL);
- #else
- // create a new sample description
- mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
- if (mySampleDesc == NULL)
- return(NULL);
-
- // fill in the fields of the sample description
- (**mySampleDesc).cType = theEffectType;
- (**mySampleDesc).idSize = sizeof(ImageDescription);
- (**mySampleDesc).hRes = 72L << 16;
- (**mySampleDesc).vRes = 72L << 16;
- (**mySampleDesc).frameCount = 1;
- (**mySampleDesc).depth = 0;
- (**mySampleDesc).clutID = -1;
- #endif
-
- (**mySampleDesc).vendor = kAppleManufacturer;
- (**mySampleDesc).temporalQuality = codecNormalQuality;
- (**mySampleDesc).spatialQuality = codecNormalQuality;
- (**mySampleDesc).width = theWidth;
- (**mySampleDesc).height = theHeight;
-
- return(mySampleDesc);
- }
-
-
- //////////
- //
- // QTEffSeg_GetFrontmostTrackLayer
- // Return the layer number of the frontmost track of the specified kind in a movie.
- //
- //////////
-
- short QTEffSeg_GetFrontmostTrackLayer (Movie theMovie, OSType theTrackType)
- {
- short myLayer = 0;
- short myIndex = 1;
- Track myTrack = NULL;
-
- // get the layer number of the first track of the specified kind;
- // if no track of that kind exists in the movie, return 0
- myTrack = GetMovieIndTrackType(theMovie, 1, theTrackType, movieTrackMediaType | movieTrackEnabledOnly);
- if (myTrack == NULL)
- return(myLayer);
-
- myLayer = GetTrackLayer(myTrack);
-
- // see if any of the remaining tracks have lower layer numbers
- while (myTrack != NULL) {
- if (myLayer > GetTrackLayer(myTrack))
- myLayer = GetTrackLayer(myTrack);
- myIndex++;
- myTrack = GetMovieIndTrackType(theMovie, myIndex, theTrackType, movieTrackMediaType | movieTrackEnabledOnly);
- }
-
- return(myLayer);
- }
-
-
-