home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Developer Kit / QuickTime 2.0 Developer Kit.iso / mac / MAC / Programming Stuff / Sample Code / Movie Toolbox / ConvertToMovie Jr. / ConvertToMovie Jr.c next >
Encoding:
C/C++ Source or Header  |  1994-12-08  |  25.7 KB  |  791 lines  |  [TEXT/MPS ]

  1. /*
  2.   File:            ConvertToMovie.c
  3.   Contains:        Movie Recompression Routines.
  4.   Written by:    QT Engineering
  5.   Copyright:    Ā© 1991-1994 by Apple Computer, Inc., all rights reserved.
  6.   Change History (most recent first):
  7.   <1>         12/8/94        khs        changed the format of the file to the new look and feel
  8.   To Do:
  9. */
  10.  
  11.  
  12. //    ConvertToMovie Jr. is an example application to recompress QuickTime
  13. //    movies and is based heavily on the venerable ConvertToMovieā„¢.  It shows
  14. //    how to use various parts of the Movie Toolbox, Image Compression Manager,
  15. //    and Standard Compression Component.
  16. //
  17. //    This code is not intended to show coding style, user interface
  18. //    or graceful error handling.
  19.  
  20.  
  21.  
  22. // INCLUDES
  23. #include <Traps.h>
  24. #include <GestaltEqu.h>
  25. #include <FixMath.h>
  26. #include <Fonts.h>
  27.  
  28. #include <QuicktimeComponents.h>
  29. #include <MoviesFormat.h>
  30. #include <Movies.h>
  31.  
  32.  
  33. // DEFINES
  34. #define    BailNil(n)        if (!n) goto bail;
  35. #define    BailError(n)    if (n) goto bail;
  36.  
  37.  
  38. // FUNCTION PROTOTYPES
  39. pascal short
  40. DefaultsHookProc(DialogPtr theDialog, short itemHit, void *params, long refcon);
  41.  
  42.  
  43. // MAIN
  44. void main()
  45. {
  46.     short        frameNum;
  47.     OSErr        result;
  48.     short        abort;
  49.     short        firstPass = true;
  50.     
  51.     Point        where;
  52.     SFTypeList    typeList;
  53.     SFReply        srcFile;
  54.     SFReply        dstFile;
  55.     short        movieRefNum = 0;
  56.     
  57.     ComponentInstance ci;
  58.     
  59.     Movie        srcMovie = nil;
  60.     Rect        srcRect;
  61.     GWorldPtr    srcGWorld = nil;
  62.     Movie        dstMovie = nil;
  63.     Track        dstTrack;
  64.     Media        dstMedia;
  65.     long        frameCount;
  66.     TimeValue    curMovieTime;
  67.     
  68. //    CWindowPtr    progressWindow = nil;
  69.     WindowRef    progressWindow = nil;
  70.     
  71.     ImageSequence    dstSeqID;
  72.     
  73.     ImageDescription **idh;
  74.     SCTemporalSettings ts;
  75.     SCDataRateSettings ds;
  76.     
  77.     InitGraf(&qd.thePort);
  78.     InitFonts();
  79.     FlushEvents(0xffff,0);
  80.     InitWindows();
  81.     InitMenus();
  82.     InitDialogs(0);
  83.     TEInit();
  84.     InitCursor();
  85.     MaxApplZone();
  86.     
  87.     
  88.     //---------------------------------------------------------------------------------------------
  89.     //    Check to make sure at least QuickTime 1.5 is installed.  We depend on features
  90.     //    of the Standard Compression component that are only present in 1.5 or later.
  91.     //---------------------------------------------------------------------------------------------
  92.     
  93.     {
  94.         long version;
  95.  
  96.         result = Gestalt(gestaltQuickTime,&version);
  97.         if (result || version < 0x01508000)
  98.             BailNil(0);
  99.     }
  100.     
  101.  
  102.     //---------------------------------------------------------------------------------------------
  103.     //    Initialize the Movie Toolbox.
  104.     //    Make sure you do this.  It's very easy to forget about.
  105.     //---------------------------------------------------------------------------------------------
  106.     
  107.     result = EnterMovies();
  108.     BailError(result);
  109.     
  110.  
  111.     //---------------------------------------------------------------------------------------------
  112.     //    Open the Standard Compression component and adjust it to meet our needs.
  113.     //---------------------------------------------------------------------------------------------
  114.     
  115.     ci = OpenDefaultComponent(StandardCompressionType,StandardCompressionSubType);
  116.     BailNil(ci);
  117.     
  118.     //    Turn off best depth option in the compression dialog.
  119.     //    Because all of our buffering is done at 32-bits, regardless
  120.     //    of the depth of the source data, best depth isn't very useful
  121.     //    as it will always choose 32-bit.
  122.     //
  123.     //    A more ambitious approach would be to loop through each of the
  124.     //    video sample descriptions in each of the video tracks looking
  125.     //    for the deepest depth, and using that for the best depth.
  126.     //    Better yet, we could find out which compressors were used
  127.     //    and set one of those as the default in the compression dialog.
  128.     
  129.     {
  130.         long flags;
  131.         
  132.         SCGetInfo(ci,scPreferenceFlagsType,&flags);
  133.         flags &= ~scShowBestDepth;
  134.         SCSetInfo(ci,scPreferenceFlagsType,&flags);
  135.     }
  136.     
  137.     //    Because we are recompressing a movie that may have a variable frame rate,
  138.     //    we want to allow the user to leave the frame rate text field blank.  We
  139.     //    can then preserve the frame durations of the source movie.  If they enter
  140.     //    a number we will resample the movie at a new frame rate.  If we don't clear
  141.     //    this flag, the compression dialog will not allow zero in the frame rate field.
  142.     //
  143.     //    NOTE: Setting this flag could have been done above when we cleared the
  144.     //    scShowBestDepth flag.  It is done separately for clarity.
  145.     
  146.     {
  147.         long flags;
  148.         
  149.         SCGetInfo(ci,scPreferenceFlagsType,&flags);
  150.         flags |= scAllowZeroFrameRate;
  151.         SCSetInfo(ci,scPreferenceFlagsType,&flags);
  152.     }
  153.     
  154.  
  155.     //---------------------------------------------------------------------------------------------
  156.     //    Ask for a source movie file using Standard Preview.
  157.     //    Use (-2,-2) to center on the best device.
  158.     //---------------------------------------------------------------------------------------------
  159.  
  160. NextPass:
  161.     where.h = where.v = -2;
  162.     typeList[0] = 'MooV';
  163.     SFGetFilePreview(where,"\p", nil,1,typeList,nil, &srcFile);
  164.     if (!srcFile.good)
  165.         goto bail;
  166.     
  167.     
  168.     //---------------------------------------------------------------------------------------------
  169.     //    Open up the movie file and get a movie from it.
  170.     //---------------------------------------------------------------------------------------------
  171.     
  172.     {
  173.         FSSpec    theFSSpec;
  174.         short    refnum;
  175.         
  176.         //    Create an FSSpec from the reply information.
  177.         
  178.         result = FSMakeFSSpec(srcFile.vRefNum,0,srcFile.fName,&theFSSpec);
  179.         BailError(result);
  180.         
  181.         //    Open a movie file using the FSSpec and create a movie from that file.
  182.         
  183.         result = OpenMovieFile(&theFSSpec, &refnum, 0);
  184.         BailError(result);
  185.         
  186.         result = NewMovieFromFile(&srcMovie,refnum, nil, nil,newMovieActive, nil);
  187.         BailError(result);
  188.         
  189.         //    We're done with the movie file.
  190.         
  191.         CloseMovieFile(refnum);
  192.     }
  193.     
  194.     
  195.     //---------------------------------------------------------------------------------------------
  196.     //    Count the number of video "frames" in the movie by stepping through all of the
  197.     //    video "interesting times", or in other words, the places where the movie displays
  198.     //    a new video sample. The time between these interesting times is not necessarily constant.
  199.     //---------------------------------------------------------------------------------------------
  200.     
  201.     {
  202.         OSType        whichMediaType = VIDEO_TYPE;
  203.         short        flags = nextTimeMediaSample + nextTimeEdgeOK;
  204.         TimeValue    duration;
  205.         TimeValue    theTime = 0;
  206.         
  207.         frameCount = -1;
  208.         while (theTime >= 0) {
  209.             frameCount++;
  210.             GetMovieNextInterestingTime(srcMovie,flags,1,&whichMediaType,theTime,0,&theTime,&duration);
  211.             
  212.             //    After the first interesting time, don't include the time we are currently at.
  213.             
  214.             flags = nextTimeMediaSample;
  215.         }
  216.     }
  217.     
  218.     
  219.     //---------------------------------------------------------------------------------------------
  220.     //    Get the bounding rectangle of the movie, create a 32-bit gworld with those dimensions,
  221.     //    and draw the movie poster picture into it.  This gworld will be used for the test image
  222.     //    in the compression dialog and for rendering movie frames into.
  223.     //---------------------------------------------------------------------------------------------
  224.     
  225.     {
  226.         PicHandle    ph = GetMoviePosterPict(srcMovie);
  227.         CGrafPtr    savePort;
  228.         GDHandle    saveDevice;
  229.         
  230.         result = GetMoviesError();
  231.         GetMovieBox(srcMovie,&srcRect);
  232.         result = NewGWorld(&srcGWorld,32,&srcRect,nil,nil,0);
  233.         BailError(result);
  234.         if (ph) {
  235.             GetGWorld(&savePort,&saveDevice);
  236.             SetGWorld(srcGWorld,nil);
  237.             EraseRect(&srcRect);
  238.             DrawPicture(ph,&srcRect);
  239.             KillPicture(ph);
  240.             SetGWorld(savePort,saveDevice);
  241.  
  242.             //    Use the gworld image of the movie poster frame as a compression dialog test image.
  243.             //    Pass nil for srcRect to use the entire image, and pass zero to use the default display method.
  244.         
  245.             result = SCSetTestImagePixMap(ci,srcGWorld->portPixMap,nil,0);
  246.             BailError(result);
  247.         }
  248.     }
  249.     
  250.     //---------------------------------------------------------------------------------------------
  251.     //    Set compression dialog extend procs for the "Defaults" button.
  252.     //    We wait until now so we can pass the srcGWorld pixmap in as a refcon.
  253.     //---------------------------------------------------------------------------------------------
  254.  
  255.     {
  256.         SCExtendedProcs xprocs;
  257.         
  258.         //    Because the compression dialog is movable modal, a filter proc
  259.         //    to handle update events for application windows is required.
  260.         //    Since our example application is completely modal, and we have
  261.         //    no other windows to update, we don't have a filter proc.
  262.         
  263.         xprocs.filterProc = nil;
  264.         
  265.         //    Proc to handle custom button click.
  266.         
  267.         xprocs.hookProc = DefaultsHookProc;
  268.         
  269.         //    Any information useful to the extended procs can be put
  270.         //    in the refcon.  For an application that has globals, a refcon
  271.         //    of the current A5 is handy for getting at those globals in
  272.         //    the extended procs.  In our case, we put the srcGWorld pixmap
  273.         //    in the refcon so we can set defaults on it in our hook proc.
  274.         
  275.         xprocs.refcon = (long)srcGWorld->portPixMap;
  276.         
  277.         //    Set the custom button name.
  278.         
  279.         BlockMove("\pDefaults",xprocs.customName,9);
  280.         
  281.         //    Tell the compression dialog about the extended procs.
  282.         
  283.         SCSetInfo(ci,scExtendedProcsType,&xprocs);
  284.     }
  285.     
  286.     
  287.     //---------------------------------------------------------------------------------------------
  288.     //    Set up some default settings for the compression dialog if needed, and ask
  289.     //    for compression settings from the user.
  290.     //---------------------------------------------------------------------------------------------
  291.     
  292.     if (firstPass) {
  293.         result = SCDefaultPixMapSettings(ci,srcGWorld->portPixMap,true);
  294.         BailError(result);
  295.     }
  296.     
  297.     result = SCGetInfo(ci,scTemporalSettingsType,&ts);
  298.     BailError(result);
  299.     
  300.     //    The first time through, clear out the default frame rate chosen by Standard Compression.
  301.     //    We know that a frame rate of 0 means use the rate of the source movie.  It probably should
  302.     //    have been smart enough to figure that out because we set the scAllowZeroFrameRate flag.
  303.     //    Oh well.
  304.     
  305.     if (firstPass) {
  306.         ts.frameRate = 0;
  307.         SCSetInfo(ci,scTemporalSettingsType,&ts);
  308.     }
  309.     
  310.     //    Get compression settings from the user.  The first time through this loop,
  311.     //    we choose default compression settings for the test image we set above.
  312.     //    On subsequent passes, the settings previously chosen by the user will be the defaults.
  313.     
  314.     result = SCRequestSequenceSettings(ci);
  315.     if (result == scUserCancelled) {
  316.         // deal with user cancelling.
  317.     }
  318.     BailError(result);
  319.     
  320.     //    Get a copy of the temporal settings the user entered.  We'll need them for
  321.     //    some of our calculations.  In a simpler application we'd never have to look at them.
  322.     
  323.     result = SCGetInfo(ci,scTemporalSettingsType,&ts);
  324.     BailError(result);
  325.     
  326.     
  327.     //---------------------------------------------------------------------------------------------
  328.     //    Take the overall data rate value entered by the user and subtract out the
  329.     //    part of the data rate allocated to sound.  We do this by looking at all of the
  330.     //    sound tracks in the source movie and using the one with the highest sample rate.
  331.     //    This number is then subtracted from the data rate leaving the amount of data per
  332.     //    second available to the compressed video data.  This is obviously only an approximation
  333.     //    because the various sound tracks may or may not overlap, be stereo, be compressed, etc.
  334.     //    A more accurate approximation would be almost mandatory for a real QuickTime movie
  335.     //    creating/editing application.
  336.     //---------------------------------------------------------------------------------------------
  337.     
  338.     if (!SCGetInfo(ci,scDataRateSettingsType,&ds)) {
  339.         if (ds.dataRate) {
  340.             short    i;
  341.             short    trackCount = GetMovieTrackCount(srcMovie);
  342.             long    maxSoundRate = 0;
  343.             for (i = 1; i <= trackCount; i++) {
  344.                 OSType    trackType;
  345.                 Track    strack = GetMovieIndTrack(srcMovie,i);
  346.                 Media    smedia = GetTrackMedia(strack);
  347.                 BailError(GetMoviesError());
  348.                 GetMediaHandlerDescription(smedia,&trackType,0,0);
  349.                 if (trackType == SOUND_TYPE) {
  350.                     long rate;
  351.                     SampleDescriptionHandle desc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription));
  352.                     GetMediaSampleDescription(smedia,1,desc);
  353.                     if (GetMoviesError()) {
  354.                         DisposeHandle((Handle)desc);
  355.                         continue;
  356.                     }
  357.                     rate = (*(SoundDescriptionHandle)desc)->sampleRate >> 16;
  358.                     if (rate > maxSoundRate)
  359.                         maxSoundRate = rate;
  360.                 }
  361.             }
  362.             ds.dataRate -= maxSoundRate;
  363.         }
  364.         SCSetInfo(ci,scDataRateSettingsType,&ds);
  365.     }
  366.  
  367.  
  368.     //---------------------------------------------------------------------------------------------
  369.     //    If the user said they want to resample the frame rate of the movie,
  370.     //    (by entering a non-zero value in the frame rate field) calculate
  371.     //    the number of frames and duration for the new movie.
  372.     //---------------------------------------------------------------------------------------------
  373.     
  374.     if (ts.frameRate) {
  375.         long    dur = GetMovieDuration(srcMovie);
  376.         long    timescale = GetMovieTimeScale(srcMovie);
  377.         float    f = (float)dur * ts.frameRate;
  378.         frameCount = f / timescale / 65536;
  379.         if (frameCount == 0)
  380.             frameCount = 1;
  381.     }
  382.     
  383.     
  384.     //---------------------------------------------------------------------------------------------
  385.     //    Ask the user for the name of the new movie file.
  386.     //    We'll be lazy here and just use "Untitled".  A real app would
  387.     //    base it on the name of the source movie and check if the user
  388.     //    tried to enter a name the same as the source movie.
  389.     //
  390.     //    Note we use the SCPositionDialog call to get a good position
  391.     //    point for the SFPutFile.  -3999 is the resource I.D. for
  392.     //    SFPutFile dialog.
  393.     //---------------------------------------------------------------------------------------------
  394.     
  395.     where.h = where.v = -2;
  396.     SCPositionDialog(ci,-3999,&where);
  397.     SFPutFile(where,"\pSave new movie file as:","\pUntitled",nil,&dstFile);
  398.     if (!dstFile.good)
  399.         goto bail;            // deal with user cancelling
  400.     
  401.     
  402.     //---------------------------------------------------------------------------------------------
  403.     //    Open a progress window to frames as they are compressed.  Use Standard
  404.     //    Compression utility routines to position the window.
  405.     //---------------------------------------------------------------------------------------------
  406.     
  407.     {
  408.         Rect r = srcRect;
  409.         where.h = where.v = -2;
  410.         result = SCPositionRect(ci,&r,&where);
  411.         progressWindow = NewCWindow(0,&r,dstFile.fName,true,0,(WindowPtr)-1,false,0);
  412.     }
  413.     
  414.     
  415.     //---------------------------------------------------------------------------------------------
  416.     //    Create the new movie file and prepare it for edits.
  417.     //---------------------------------------------------------------------------------------------
  418.     
  419.     {
  420.         FSSpec            theFSSpec;
  421.         MatrixRecord    matrix;
  422.         
  423.         //    Create an FSSpec for the destination movie.
  424.         
  425.         result = FSMakeFSSpec(dstFile.vRefNum,0,dstFile.fName,&theFSSpec);
  426.         if (result != fnfErr)        // ignore a file not found error
  427.             BailError(result);
  428.         
  429.         //    Using the FSSpec create a movie file for the destination movie.
  430.         
  431.         result = CreateMovieFile(&theFSSpec,'TVOD',0,createMovieFileDeleteCurFile,&movieRefNum,&dstMovie);
  432.         BailError(result);
  433.         
  434.         //    Create a new video movie track with the same dimensions as the entire source movie.
  435.         
  436.         dstTrack = NewMovieTrack(dstMovie,
  437.                 (long)(srcRect.right - srcRect.left) << 16,
  438.                 (long)(srcRect.bottom - srcRect.top) << 16,0);
  439.         
  440.         //    Create a media for the new track with the same time scale as the
  441.         //    source movie.  Because the time scales are the same, we don't have
  442.         //    to do any time scale conversions.
  443.         
  444.         dstMedia = NewTrackMedia(dstTrack,VIDEO_TYPE,GetMovieTimeScale(srcMovie),0,0);
  445.         BailError(GetMoviesError());
  446.         
  447.         //    Copy the user data and settings from the source to the dest movie.
  448.         //    These settings include information like user data.
  449.         
  450.         CopyMovieSettings(srcMovie,dstMovie);
  451.         
  452.         //    Set movie matrix to identity and clear the movie clip region
  453.         //    because conversion process transforms and composites all video
  454.         //    tracks into one untransformed video track.
  455.         
  456.         SetIdentityMatrix(&matrix);
  457.         SetMovieMatrix(dstMovie,&matrix);
  458.         SetMovieClipRgn(dstMovie,nil);
  459.         
  460.         //    Prepare for adding frames to the movie.
  461.         //    Make sure you do this.  It's very easy to forget about.
  462.         
  463.         result = BeginMediaEdits(dstMedia);
  464.         BailError(result);
  465.     }
  466.     
  467.  
  468.     //---------------------------------------------------------------------------------------------
  469.     //    Start a compression sequence using the parameters chosen by the user.
  470.     //    Pass nil for the source rect to use the entire image.  An image description
  471.     //    handle will be returned in idh.  Nil could be passed for that if we
  472.     //    didn't need it for our progress window display.  We do not have dispose
  473.     //    the image description handle.  It is disposed for use by SCCompressSequenceEnd.
  474.     //---------------------------------------------------------------------------------------------
  475.     
  476.     result = SCCompressSequenceBegin(ci,srcGWorld->portPixMap,nil,&idh);
  477.     BailError(result);
  478.     
  479.     //    Clear out our image gworld and set movie to draw into it.
  480.  
  481.     SetGWorld(srcGWorld,nil);
  482.     EraseRect(&srcGWorld->portRect);
  483.     SetMovieGWorld(srcMovie,srcGWorld,GetGWorldDevice(srcGWorld));
  484.     
  485.     //    Set current time value to begining of movie.
  486.     
  487.     curMovieTime = 0;
  488.     
  489.     //    Loop through all of the interesting times we counted above.
  490.     
  491.     for (frameNum = 0; frameNum < frameCount; frameNum++) {
  492.         
  493.         short            syncFlag;
  494.         TimeValue        duration;
  495.         long            dataSize;
  496.         Handle            compressedData;
  497.         
  498.         //    Abort if the user clicked the mouse or pressed a key.
  499.         
  500.         {
  501.             EventRecord event;
  502.             abort = false;
  503.             if (EventAvail(keyDownMask | mDownMask,&event)) {
  504.                 abort = true;
  505.                 break;
  506.             }
  507.         }
  508.         
  509.         //    Get the next frame of the source movie.
  510.         
  511.         {
  512.             //    If we are resampling the movie, step to the next frame.
  513.             
  514.             if (ts.frameRate) {
  515.                 
  516.                 //    This code could be much smarter about its calculations.
  517.                 //    The srcMovie duration and dstMovie frame duration are both
  518.                 //    constant and could be calculated once outside this loop
  519.                 
  520.                 long dur = GetMovieDuration(srcMovie);
  521.                 curMovieTime = frameNum*dur/(frameCount-1);
  522.                 duration = dur / frameCount;
  523.             } else {
  524.                 short flags = nextTimeMediaSample;
  525.                 OSType    whichMediaType = VIDEO_TYPE;
  526.                 
  527.                 //    If this is the first frame, include the frame we are currently on.
  528.                 
  529.                 if (frameNum == 0)
  530.                     flags |= nextTimeEdgeOK;
  531.                 
  532.                 //    If we are maintaining the frame durations of the source movie,
  533.                 //    skip to the next interesting time and get the duration for that frame.
  534.                 
  535.                 GetMovieNextInterestingTime(srcMovie,flags,1,&whichMediaType,curMovieTime,0,&curMovieTime,&duration);
  536.             }
  537.             SetMovieTimeValue(srcMovie,curMovieTime);
  538.             MoviesTask(srcMovie,0);
  539.             MoviesTask(srcMovie,0);
  540.             MoviesTask(srcMovie,0);
  541.         }
  542.         
  543.         //    If data rate constraining is being done, tell Standard Compression the
  544.         //    duration of the current frame in milliseconds.  We only need to do this
  545.         //    if the frames have variable durations.
  546.         
  547.         {
  548.             SCDataRateSettings ds;
  549.             if (!SCGetInfo(ci,scDataRateSettingsType,&ds)) {
  550.                 ds.frameDuration = duration * 1000 / GetMovieTimeScale(srcMovie);
  551.                 SCSetInfo(ci,scDataRateSettingsType,&ds);
  552.             }
  553.         }
  554.         
  555.         //    Compress the frame.  compressedData will hold a handle to the newly compressed
  556.         //    image data.  dataSize is the size of the compressed data, which will usually be
  557.         //    different than the size of the compressedData handle.  syncFlag is a value that
  558.         //    can be passed directly to AddMediaSample which indicates whether or not the frame
  559.         //    is a key frame.  Note that we do not have to dispose of the compressedData handle.
  560.         //    It will be dispose for us when we call SCCompressSequenceEnd.
  561.         
  562.         result = SCCompressSequenceFrame(ci,srcGWorld->portPixMap,&srcRect,&compressedData,&dataSize,&syncFlag);
  563.         BailError(result);
  564.         
  565.         //    Append the compressed image data to the media.
  566.         
  567.         result = AddMediaSample(dstMedia,compressedData,0,dataSize,duration,
  568.                 (SampleDescriptionHandle)idh,1,syncFlag,nil);
  569.         BailError(result);
  570.         
  571.         //    Decompress the compressed frame into the progress window.
  572.         
  573.         if (progressWindow) {
  574.             char hstate;
  575.             
  576.             //    Set port to progress window.
  577.             
  578.             SetGWorld((CGrafPtr)progressWindow,nil);
  579.             
  580.             //    If this is the first frame, start up a decompression sequence.
  581.             
  582.             if (frameNum == 0) {
  583.                 result = DecompressSequenceBegin(&dstSeqID,idh,nil,nil,&srcRect,nil,ditherCopy,
  584.                     nil,0,codecNormalQuality,anyCodec);
  585.                 BailError(result);
  586.             }
  587.             
  588.             //    Save the locked state of the compressed data and then lock it.
  589.             //    We want it locked but standard compression may or may not.
  590.             
  591.             hstate = HGetState(compressedData);
  592.             HLock(compressedData);
  593.             
  594.             //    Decompress the frame to the progress window.  Note that we StripAddress
  595.             //    the compressedData pointer because it must be 32-bit clean.
  596.             
  597.             result = DecompressSequenceFrame(dstSeqID,StripAddress(*compressedData),0,nil,nil);
  598.             
  599.             //    Restore the locked state of the data handle.
  600.             
  601.             HSetState(compressedData,hstate);
  602.             BailError(result);
  603.         }
  604.     }
  605.     
  606.     //    Close the compression sequence.  This will dispose of the image description
  607.     //    and compressed data handles allocated by SCCompressSequenceBegin.
  608.     
  609.     SCCompressSequenceEnd(ci);
  610.     
  611.     //    Close the decompression sequence.  Note that this is an Image Compression
  612.     //    Manager call, not Standard Compression.
  613.     
  614.     CDSequenceEnd(dstSeqID);
  615.     
  616.     
  617.     //    Copy all sound tracks from the source to dest movie.
  618.     //
  619.     //    NOTE: We are not copying any other track types here.  That means
  620.     //    text tracks, alternate tracks, etc. are not being copied.  A real
  621.     //    application would give the user some options here.
  622.     
  623.     {
  624.         short    i;
  625.         short    trackCount;
  626.         
  627.         //    Get a count of all the tracks present in the source movie.
  628.         
  629.         trackCount = GetMovieTrackCount(srcMovie);
  630.         
  631.         //    Loop through each of the tracks, looking for sound tracks.
  632.         
  633.         for (i = 1; i <= trackCount; i++) {
  634.             OSType    trackType;
  635.             Track    strack;
  636.             Media    smedia;
  637.             
  638.             //    Get the next track and its media.
  639.             
  640.             strack = GetMovieIndTrack(srcMovie,i);
  641.             smedia = GetTrackMedia(strack);
  642.             BailError(GetMoviesError());
  643.             
  644.             //    Find out what type of media this track has.
  645.             //    We only care about sound.
  646.             
  647.             GetMediaHandlerDescription(smedia,&trackType,0,0);
  648.             if (trackType == SOUND_TYPE) {
  649.                 Track    dtrack;
  650.                 Media    dmedia;
  651.                 
  652.                 //    Create a new sound track in the destination movie.
  653.                 
  654.                 dtrack = NewMovieTrack(dstMovie,0,0,GetTrackVolume(strack));
  655.                 BailError(GetMoviesError());
  656.                 
  657.                 //    Create a media for that sound track and prepare it for editing.
  658.                 
  659.                 dmedia = NewTrackMedia(dtrack,SOUND_TYPE,GetMediaTimeScale(smedia),0,0);
  660.                 BailError(GetMoviesError());
  661.                 
  662.                 result = BeginMediaEdits(dmedia);
  663.                 BailError(GetMoviesError());
  664.                 
  665.                 //    Insert the new track into the dest movie starting at time
  666.                 //    zero and lasting for the entire duration of the movie.
  667.                 
  668.                 InsertTrackSegment(strack,dtrack,0,GetTrackDuration(strack),0);
  669.                 BailError(GetMoviesError());
  670.                 
  671.                 //    We're done editing the media.
  672.                 
  673.                 EndMediaEdits(dmedia);
  674.             }
  675.         }
  676.     }
  677.     
  678.     //---------------------------------------------------------------------------------------------
  679.     //    Now that we're finished compressing video data, make that data part of our movie. 
  680.     //---------------------------------------------------------------------------------------------
  681.     
  682.     if (dstTrack) {
  683.         short resID = 128;
  684.         
  685.         //    End changes to the media.
  686.         
  687.         result = EndMediaEdits(dstMedia);
  688.         BailError(result);
  689.         
  690.         //    Insert the newly created media into the newly created track at
  691.         //    the begining of the track and lasting for the entire duration of
  692.         //    the media.  The media rate is 1.0 for normal playback rate.
  693.         
  694.         InsertMediaIntoTrack(dstTrack,0,0,GetMediaDuration(dstMedia),fixed1);
  695.         
  696.         //    Add the movie resource to the dst movie file.
  697.         
  698.         result = AddMovieResource(dstMovie,movieRefNum,&resID,"\pMovie 1");
  699.         BailError(result);
  700.  
  701.         //---------------------------------------------------------------------------------------------
  702.         //    Next we flatten the movie.  The movie file we just created has all of
  703.         //    the video data at the beginning and all of the sound data at the end.
  704.         //    This unnatural situation may cause the movie to play poorly.  By flattening
  705.         //    the movie, we are reinterleaving all of the tracks in a way optimal for playback.
  706.         //    Because we cannot flatten a movie in place, we create a temp file, flatten to
  707.         //    that file and if successful, delete the first file and rename the temp file to
  708.         //    be the real file.  For large files this takes some time.
  709.         //
  710.         //    Once again, a real application would choose a temp file name that doesn't
  711.         //    possibly conflict with other file names, as well as delete the temp file
  712.         //    if the flatten fails.
  713.         //---------------------------------------------------------------------------------------------
  714.         
  715.         {
  716.             FSSpec    theFSSpec;
  717.             short    resID = 128;
  718.             dstFile.fName[++dstFile.fName[0]] = '@';
  719.             result = FSMakeFSSpec(dstFile.vRefNum,0,dstFile.fName,&theFSSpec);
  720.             if (result != fnfErr)
  721.                 BailError(result);
  722.             FlattenMovie(dstMovie,0,&theFSSpec,'TVOD',-1,createMovieFileDeleteCurFile,&resID,"\p");
  723.             result = GetMoviesError();
  724.             CloseMovieFile(movieRefNum);
  725.             DisposeMovie(dstMovie);
  726.             dstTrack = nil;
  727.             if (!result) {
  728.                 Str255 tempStr;
  729.                 BlockMove(dstFile.fName,tempStr,256);
  730.                 tempStr[0]--;
  731.                 result = FSDelete(tempStr,dstFile.vRefNum);
  732.                 result = Rename(dstFile.fName,dstFile.vRefNum,tempStr);
  733.             }
  734.         }
  735.     }
  736.     
  737.     //    Throw away the progress window.
  738.     
  739.     if (progressWindow) {
  740.         CloseWindow(progressWindow);
  741.         progressWindow = nil;
  742.     }
  743.     
  744.     //    Throw away the movie buffer gworld.
  745.     
  746.     if (srcGWorld) {
  747.         DisposeGWorld(srcGWorld);
  748.         srcGWorld = nil;
  749.     
  750.         //    Just to be overly safe, we clear our the test image
  751.         //    because we just disposed the pixmap it depends on.
  752.     
  753.         SCSetTestImagePixMap(ci,nil,nil,0);
  754.     }
  755.     
  756.     if (!abort) {
  757.         firstPass = false;
  758.         goto NextPass;
  759.     }
  760.     
  761.     //    Close the Standard Compression component.
  762.     
  763.     CloseComponent(ci);
  764. bail:;
  765. }
  766.  
  767.  
  768. //    Handle clicks in the "Defaults" custom button.
  769.  
  770. pascal short
  771. DefaultsHookProc(DialogPtr theDialog, short itemHit, void *params, long refcon)
  772. {
  773.     if (itemHit == scCustomItem) {
  774.         SCTemporalSettings ts;
  775.         
  776.         //    Set defaults for our test image (passed in refcon).
  777.         
  778.         SCDefaultPixMapSettings(params,(PixMapHandle)refcon,true);
  779.         
  780.         //    Once again, don't use the default frame rate chosen
  781.         //    by Standard Compression.  Clear it out to zero.
  782.         
  783.         SCGetInfo(params,scTemporalSettingsType,&ts);
  784.         ts.frameRate = 0;
  785.         SCSetInfo(params,scTemporalSettingsType,&ts);
  786.     }
  787.     return (itemHit);
  788. }
  789.  
  790.  
  791.