home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / goodies / qtaddeffectseg / addeffectsegment.c next >
Encoding:
Text File  |  2000-06-23  |  11.7 KB  |  417 lines

  1. //////////
  2. //
  3. //    File:        AddEffectSegment.c
  4. //
  5. //    Contains:    Sample code for adding a visual effect to a segment of a movie.
  6. //
  7. //    Written by:    Tim Monroe
  8. //
  9. //    Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  10. //
  11. //    Change History (most recent first):
  12. //
  13. //       <2>         05/06/99    rtm        tested on Mac and Windows; works fine
  14. //       <1>         05/05/99    rtm        first file; some functions based on some existing code
  15. //                                    in QTShowEffect
  16. //       
  17. //    This file contains some sample code that adds a QuickTime effect to a part of a movie;
  18. //    we assume that the movie already exists and that it contains one or more video tracks.
  19. //    Our job here is to add a specified effect at a specified time. For one- or two-source
  20. //    effects, the principal value in this code consists in illustrating how to duplicate the
  21. //    portion(s) of the existing video track(s) for use as the effects source track(s).
  22. //
  23. //////////
  24.  
  25. #include "AddEffectSegment.h"
  26.  
  27.  
  28. //////////
  29. //
  30. // QTEffSeg_AddEffectToMovieSegment
  31. // Add the specified effect to occur at the specified time and duration.
  32. //
  33. //////////
  34.  
  35. OSErr QTEffSeg_AddEffectToMovieSegment (Movie theMovie, OSType theEffectType, long theNumSources, TimeValue theStartTime, TimeValue theDuration)
  36. {
  37.     Track                    myVidTrack1 = NULL;
  38.     Track                    myVidTrack2 = NULL;
  39.     Track                    mySrcTrack1 = NULL;
  40.     Track                    mySrcTrack2 = NULL;
  41.     Media                    mySrcMedia1 = NULL;
  42.     Media                    mySrcMedia2 = NULL;
  43.     Track                    myEffectTrack = NULL;
  44.     Media                    myEffectMedia = NULL;
  45.     Fixed                    myWidth, myHeight;
  46.     TimeScale                myTimeScale;
  47.     TimeValue                mySampleTime;
  48.     Rect                    myRect;
  49.     QTAtomContainer            myInputMap = NULL;
  50.     QTAtomContainer            myEffectDesc = NULL;
  51.     ImageDescriptionHandle    mySampleDesc = NULL;
  52.     OSType                    myEffectName1 = kSourceNoneName;
  53.     OSType                    myEffectName2 = kSourceNoneName;
  54.     short                    myLayer;
  55.     OSErr                    myErr = noErr;
  56.     
  57.     //////////
  58.     //
  59.     // get some information about the movie
  60.     //
  61.     //////////
  62.     
  63.     // make sure we were passed a valid movie
  64.     if (theMovie == NULL)
  65.         return(paramErr);
  66.         
  67.     myTimeScale = GetMovieTimeScale(theMovie);
  68.     GetMovieBox(theMovie, &myRect);
  69.     myLayer = QTEffSeg_GetFrontmostTrackLayer(theMovie, VideoMediaType);
  70.     
  71.     myWidth = (myRect.right - myRect.left) << 16;
  72.     myHeight = (myRect.bottom - myRect.top) << 16;
  73.  
  74.     //////////
  75.     //
  76.     // retrieve the original video track(s), create the effect's source track(s) and media,
  77.     // then set the new source track(s) to reference the data in the original video track(s)
  78.     //
  79.     //////////
  80.     
  81.     switch (theNumSources) {
  82.         case 2:
  83.             myVidTrack2 = GetMovieIndTrackType(theMovie, 2, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
  84.             if (myVidTrack2 == NULL)
  85.                 return(paramErr);
  86.             
  87.             mySrcTrack2 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
  88.             if (mySrcTrack2 == NULL)
  89.                 return(paramErr);
  90.                 
  91.             mySrcMedia2 = NewTrackMedia(mySrcTrack2, VideoMediaType, myTimeScale, NULL, 0);
  92.             if (mySrcMedia2 == NULL)
  93.                 return(paramErr);
  94.  
  95. #if COPY_MOVIE_MEDIA
  96.             myErr = BeginMediaEdits(mySrcMedia2);
  97.             if (myErr != noErr)
  98.                 return(myErr);
  99. #endif            
  100.             myErr = CopyTrackSettings(myVidTrack2, mySrcTrack2);
  101.             myErr = InsertTrackSegment(myVidTrack2, mySrcTrack2, theStartTime, theDuration, theStartTime);
  102.             if (myErr != noErr)
  103.                 return(myErr);
  104.  
  105. #if COPY_MOVIE_MEDIA
  106.             EndMediaEdits(mySrcMedia2);
  107. #endif            
  108.             myEffectName2 = kSourceTwoName;
  109.             
  110.             // note that we fall through here!
  111.                 
  112.         case 1:
  113.             myVidTrack1 = GetMovieIndTrackType(theMovie, 1, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
  114.             if (myVidTrack1 == NULL)
  115.                 return(paramErr);
  116.                 
  117.             mySrcTrack1 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
  118.             if (mySrcTrack1 == NULL)
  119.                 return(paramErr);
  120.                 
  121.             mySrcMedia1 = NewTrackMedia(mySrcTrack1, VideoMediaType, myTimeScale, NULL, 0);
  122.             if (mySrcMedia1 == NULL)
  123.                 return(paramErr);
  124.  
  125. #if COPY_MOVIE_MEDIA
  126.             myErr = BeginMediaEdits(mySrcMedia1);
  127.             if (myErr != noErr)
  128.                 return(myErr);
  129. #endif            
  130.             myErr = CopyTrackSettings(myVidTrack1, mySrcTrack1);
  131.             myErr = InsertTrackSegment(myVidTrack1, mySrcTrack1, theStartTime, theDuration, theStartTime);
  132.             if (myErr != noErr)
  133.                 return(myErr);
  134.             
  135. #if COPY_MOVIE_MEDIA
  136.             EndMediaEdits(mySrcMedia1);
  137. #endif            
  138.             myEffectName1 = kSourceOneName;
  139.             
  140.             break;
  141.             
  142.         case 0:
  143.             // for 0-source effects, we don't need to create any new source track
  144.             break;
  145.     
  146.         default:
  147.             return(paramErr);
  148.     }
  149.     
  150.     //////////
  151.     //
  152.     // create the effects track and media
  153.     //
  154.     //////////
  155.  
  156.     myEffectTrack = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
  157.     if (myEffectTrack == NULL)
  158.         return(GetMoviesError());
  159.         
  160.     myEffectMedia = NewTrackMedia(myEffectTrack, VideoMediaType, myTimeScale, NULL, 0);
  161.     if (myEffectMedia == NULL)
  162.         return(GetMoviesError());
  163.     
  164.     // create an effect sample description
  165.     mySampleDesc = QTEffSeg_MakeSampleDescription(theEffectType, myWidth >> 16, myHeight >> 16);
  166.     if (mySampleDesc == NULL)
  167.         goto bail;
  168.  
  169.     // create an effect description
  170.     myEffectDesc = QTEffSeg_CreateEffectDescription(theEffectType, myEffectName1, myEffectName2);
  171.  
  172.     // add the effect description as a sample to the effect track media
  173.     BeginMediaEdits(myEffectMedia);
  174.  
  175.     myErr = AddMediaSample(myEffectMedia, (Handle)myEffectDesc, 0, GetHandleSize((Handle)myEffectDesc), theDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime);
  176.     if (myErr != noErr)
  177.         goto bail;
  178.  
  179.     EndMediaEdits(myEffectMedia);
  180.     
  181.     // add the media sample to the effects track
  182.     myErr = InsertMediaIntoTrack(myEffectTrack, theStartTime, mySampleTime, theDuration, fixed1);
  183.     if (myErr != noErr)
  184.         goto bail;
  185.  
  186.     //////////
  187.     //
  188.     // create the input map and add references for the source track(s)
  189.     //
  190.     //////////
  191.  
  192.     myErr = QTNewAtomContainer(&myInputMap);
  193.     if (myErr != noErr)
  194.         goto bail;
  195.     
  196.     if (mySrcTrack1 != NULL) {    
  197.         myErr = QTEffSeg_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack1, kSourceOneName);
  198.         if (myErr != noErr)
  199.             goto bail;
  200.     }
  201.         
  202.     if (mySrcTrack2 != NULL) {    
  203.         myErr = QTEffSeg_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack2, kSourceTwoName);
  204.         if (myErr != noErr)
  205.             goto bail;
  206.     }
  207.         
  208.     // add the input map to the effects track
  209.     myErr = SetMediaInputMap(myEffectMedia, myInputMap);
  210.     if (myErr != noErr)
  211.         goto bail;
  212.  
  213.     //////////
  214.     //
  215.     // do any required positioning and graphics mode manipulation
  216.     //
  217.     //////////
  218.  
  219.     SetTrackLayer(myEffectTrack, myLayer - 1);    // in front of any existing video track
  220.     
  221.     switch (theNumSources) {
  222.         case 2:
  223.             break;
  224.             
  225.         case 1:
  226.             break;
  227.             
  228.         case 0: {
  229.             RGBColor    myColor;
  230.             
  231.             myColor.red = 0;        // (good for fire, not so good for clouds)
  232.             myColor.green = 0;
  233.             myColor.blue = 0;
  234.             
  235.             MediaSetGraphicsMode(GetMediaHandler(myEffectMedia), transparent, &myColor);
  236.             break;
  237.         }
  238.     }
  239.     
  240. bail:
  241.     if (mySampleDesc != NULL)
  242.         DisposeHandle((Handle)mySampleDesc);
  243.     
  244.     if (myInputMap != NULL)
  245.         QTDisposeAtomContainer(myInputMap);
  246.     
  247.     return(myErr);
  248. }
  249.  
  250.  
  251. //////////
  252. //
  253. // QTEffSeg_CreateEffectDescription
  254. // Create an effect description for zero, one, or two sources.
  255. // 
  256. // The effect description specifies which video effect is desired and the parameters for that effect.
  257. // It also describes the source(s) for the effect. An effect description is simply an atom container
  258. // that holds atoms with the appropriate information.
  259. //
  260. // Note that because we are creating an atom container, we must pass big-endian data (hence the calls
  261. // to EndianU32_NtoB).
  262. //
  263. // The caller is responsible for disposing of the returned atom container, by calling QTDisposeAtomContainer.
  264. //
  265. //////////
  266.  
  267. QTAtomContainer QTEffSeg_CreateEffectDescription (OSType theEffectName, OSType theSourceName1, OSType theSourceName2)
  268. {
  269.     QTAtomContainer        myEffectDesc = NULL;
  270.     OSType                myType;
  271.     OSErr                myErr = noErr;
  272.  
  273.     // create a new, empty effect description
  274.     myErr = QTNewAtomContainer(&myEffectDesc);
  275.     if (myErr != noErr)
  276.         goto bail;
  277.  
  278.     // create the effect ID atom: the atom type is kParameterWhatName, and the atom ID is kParameterWhatID
  279.     myType = EndianU32_NtoB(theEffectName);
  280.     myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, 0, sizeof(myType), &myType, NULL);
  281.     if (myErr != noErr)
  282.         goto bail;
  283.         
  284.     // add the first source, if it's not kSourceNoneName
  285.     if (theSourceName1 != kSourceNoneName) {
  286.         myType = EndianU32_NtoB(theSourceName1);
  287.         myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myType), &myType, NULL);
  288.         if (myErr != noErr)
  289.             goto bail;
  290.     }
  291.                             
  292.     // add the second source, if it's not kSourceNoneName
  293.     if (theSourceName2 != kSourceNoneName) {
  294.         myType = EndianU32_NtoB(theSourceName2);
  295.         myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myType), &myType, NULL);
  296.     }
  297.  
  298. bail:
  299.     return(myEffectDesc);
  300. }
  301.  
  302.  
  303. //////////
  304. //
  305. // QTEffSeg_AddTrackReferenceToInputMap
  306. // Add a track reference to the specified input map.
  307. // 
  308. //////////
  309.  
  310. OSErr QTEffSeg_AddTrackReferenceToInputMap (QTAtomContainer theInputMap, Track theTrack, Track theSrcTrack, OSType theSrcName)
  311. {
  312.     OSErr                myErr = noErr;
  313.     QTAtom                myInputAtom;
  314.     long                myRefIndex;
  315.     OSType                myType;
  316.  
  317.     myErr = AddTrackReference(theTrack, theSrcTrack, kTrackModifierReference, &myRefIndex);
  318.     if (myErr != noErr)
  319.         goto bail;
  320.             
  321.     // add a reference atom to the input map
  322.     myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex, 0, 0, NULL, &myInputAtom);
  323.     if (myErr != noErr)
  324.         goto bail;
  325.     
  326.     // add two child atoms to the parent reference atom
  327.     myType = EndianU32_NtoB(kTrackModifierTypeImage);
  328.     myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myType), &myType, NULL);
  329.     if (myErr != noErr)
  330.         goto bail;
  331.     
  332.     myType = EndianU32_NtoB(theSrcName);
  333.     myErr = QTInsertChild(theInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myType), &myType, NULL);
  334.         
  335. bail:
  336.     return(myErr);
  337. }
  338.  
  339.  
  340. //////////
  341. //
  342. // QTEffSeg_MakeSampleDescription
  343. // Return a new image description with default and specified values.
  344. // 
  345. //////////
  346.  
  347. ImageDescriptionHandle QTEffSeg_MakeSampleDescription (OSType theEffectType, short theWidth, short theHeight)
  348. {
  349.     ImageDescriptionHandle        mySampleDesc = NULL;
  350.  
  351. #if USES_MAKE_IMAGE_DESC_FOR_EFFECT
  352.     OSErr                        myErr = noErr;
  353.     
  354.     // create a new sample description
  355.     myErr = MakeImageDescriptionForEffect(theEffectType, &mySampleDesc);
  356.     if (myErr != noErr)
  357.         return(NULL);
  358. #else
  359.     // create a new sample description
  360.     mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  361.     if (mySampleDesc == NULL)
  362.         return(NULL);
  363.         
  364.     // fill in the fields of the sample description
  365.     (**mySampleDesc).cType = theEffectType;
  366.     (**mySampleDesc).idSize = sizeof(ImageDescription);
  367.     (**mySampleDesc).hRes = 72L << 16;
  368.     (**mySampleDesc).vRes = 72L << 16;
  369.     (**mySampleDesc).frameCount = 1;
  370.     (**mySampleDesc).depth = 0;
  371.     (**mySampleDesc).clutID = -1;
  372. #endif
  373.     
  374.     (**mySampleDesc).vendor = kAppleManufacturer;
  375.     (**mySampleDesc).temporalQuality = codecNormalQuality;
  376.     (**mySampleDesc).spatialQuality = codecNormalQuality;
  377.     (**mySampleDesc).width = theWidth;
  378.     (**mySampleDesc).height = theHeight;
  379.     
  380.     return(mySampleDesc);
  381. }
  382.  
  383.  
  384. //////////
  385. //
  386. // QTEffSeg_GetFrontmostTrackLayer
  387. // Return the layer number of the frontmost track of the specified kind in a movie.
  388. // 
  389. //////////
  390.  
  391. short QTEffSeg_GetFrontmostTrackLayer (Movie theMovie, OSType theTrackType)
  392. {
  393.     short        myLayer = 0;
  394.     short        myIndex = 1;
  395.     Track        myTrack = NULL;
  396.     
  397.     // get the layer number of the first track of the specified kind;
  398.     // if no track of that kind exists in the movie, return 0
  399.     myTrack = GetMovieIndTrackType(theMovie, 1, theTrackType, movieTrackMediaType | movieTrackEnabledOnly);
  400.     if (myTrack == NULL)
  401.         return(myLayer);
  402.         
  403.     myLayer = GetTrackLayer(myTrack);
  404.     
  405.     // see if any of the remaining tracks have lower layer numbers
  406.     while (myTrack != NULL) {
  407.         if (myLayer > GetTrackLayer(myTrack))
  408.             myLayer = GetTrackLayer(myTrack);
  409.         myIndex++;
  410.         myTrack = GetMovieIndTrackType(theMovie, myIndex, theTrackType, movieTrackMediaType | movieTrackEnabledOnly);
  411.     }
  412.     
  413.     return(myLayer);
  414. }
  415.  
  416.  
  417.