AddFrameToMovie.c

/*
    File:       AddFrameToMovie.c
 
    Contains:   Adding a Frame to the End of an Existing Movie.
                How To Test:
                    Run the application, open a movie file, the application will now add an additional
                    frame at the end of this existing movie.
    Written by: John Wang   
 
    Copyright:  Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/28/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                12/4/94     khs             changed the format of the file to the new look and feel
                94          JW              Fixed error where ind was assumed to be 0 based
                                            rather than 1 based.  And, added code to update
                                            movie rather than require a flatten movie for
                                            saving the new edited movie.
*/
 
// INCLUDES
#include    <GestaltEqu.h>
#include    <Segload.h>
#include    <ToolUtils.h>
#include    <Devices.h>
#include    <Errors.h>
 
#include    <Movies.h>
 
 
// DEFINES
#define Gestalttest     0xA1AD
#define NoTrap          0xA89F
 
#define appleID         128         
#define appleMenu       0
#define aboutMeCommand  1
 
#define fileID          129
#define openCommand     1
#define flattenCommand  2
#define closeCommand    3
#define quitCommand     5
 
#define aboutMeDLOG     128
#define okButton        1
 
#define MAXWINDOWS      5
 
// FUNCTION PROTOTYPES
Movie GetMovieFromFile(void);
OSErr PlayMovie(int index);
short Flatten(int index);
void showAboutMeDialog(void);
void Init(void);
void Finish(void);
void DoOpenCommand(void);
void DoFlattenCommand(void);
void DoCloseCommand(void);
void PlayMovies(void);
void DoCommand(long mResult);
 
 
// GLOBALS
Boolean DoneFlag = false;
MenuHandle mymenu0, mymenu1;
Boolean playingMovie[MAXWINDOWS];
Movie myMovie[MAXWINDOWS];
WindowPtr myWindow[MAXWINDOWS];
int startlocation;
 
 
// FUNCTIONS
 
/*------------------------------------------------------*/
/*  GetMovieFromFile().                                 */
/*------------------------------------------------------*/
 
Movie GetMovieFromFile(void)
{
    OSErr err;
    StandardFileReply reply;
    Point where =
    {
        200,  50
    };
    SFTypeList types;
    short movieResRefNum;
    short actualResId;
    Movie theMovie;
    long i,
     maxCompressionSize;
    Track myVideoTrack;
    Media myVideoMedia;
    OSType myMediaType;
    Boolean done = false;
    GWorldPtr myGWorld;
    Rect movieBounds;
    GDHandle oldGDevice;
    CGrafPtr oldPort;
    Handle compressedData;
    ImageDescriptionHandle imageDescH;
    TimeValue sampleDuration;
    int x,y;
 
    types[0] = 'MooV';
    StandardGetFilePreview(nil, 1, types, &reply);
    if (!reply.sfGood)
        return ((Movie)0);
 
    err = OpenMovieFile(&reply.sfFile, &movieResRefNum, fsWrPerm);
    if (GetMoviesError())
        return ((Movie)0);
    if (err)
        return ((Movie)0);
    actualResId = 0;
 
    err = NewMovieFromFile(&theMovie, movieResRefNum, &actualResId, 
                            (StringPtr)0, newMovieActive, (Boolean *)0);
    if (GetMoviesError())
        return ((Movie)0);
    if (err)
        return ((Movie)0);
 
    /*  This is where I add a frame to the end of the movie's video track.  */
 
    for (i = 1; ((i <= GetMovieTrackCount(theMovie)) && (!done)); i++)
    {
        myVideoTrack = GetMovieIndTrack(theMovie, i);
        myVideoMedia = GetTrackMedia(myVideoTrack);
        GetMediaHandlerDescription(myVideoMedia, &myMediaType, nil, nil);
        if (myMediaType == VideoMediaType)
            done = true;
    }
    if (done == false)
        DebugStr("\pMovie contains no video tracks.");
    else
    {
        if (BeginMediaEdits(myVideoMedia))
            DebugStr("\pBeginMediaEdits failed.");
 
        GetMovieBox(theMovie, &movieBounds);
        if (NewGWorld(&myGWorld, 1, &movieBounds, nil, nil, 0))
            DebugStr("\pNewGWorld failed.");
        GetGWorld(&oldPort, &oldGDevice);
        SetGWorld(myGWorld, nil);
        LockPixels(GetGWorldPixMap(myGWorld));
        EraseRect(&movieBounds);
        x=movieBounds.right/2;
        y=movieBounds.bottom/2;
        MoveTo(x, y);
        DrawString("\pHi there");
        imageDescH = (ImageDescriptionHandle)NewHandle(4);
 
        if (GetMaxCompressionSize(GetGWorldPixMap(myGWorld), &movieBounds, 1, 
                                        codecNormalQuality, 'raw ', anyCodec, &maxCompressionSize))
            DebugStr("\pCompressImage.");
        compressedData = NewHandle(maxCompressionSize);
        if (compressedData == nil)
            DebugStr("\pCould not allocate compressedData block");
        MoveHHi(compressedData);
        HLock(compressedData);
        if (CompressImage(GetGWorldPixMap(myGWorld), &movieBounds, codecNormalQuality, 
                                'raw ', imageDescH, StripAddress(*compressedData)))
            DebugStr("\pCompressImage.");
 
        if (AddMediaSample(myVideoMedia, compressedData, 0, (**imageDescH).dataSize, 
                            GetMediaTimeScale(myVideoMedia), (SampleDescriptionHandle)imageDescH, 
                            1, 0, &sampleDuration))
            DebugStr("\pInsertMediaIntoTracks.");
 
        if (InsertMediaIntoTrack(myVideoTrack, GetTrackDuration(myVideoTrack), sampleDuration, 
                                    GetMediaTimeScale(myVideoMedia), 0x00010000))
            DebugStr("\pInsertMediaIntoTracks.");
 
        if (EndMediaEdits(myVideoMedia))
            DebugStr("\pEndMediaEdits failed.");
        SetGWorld(oldPort, oldGDevice);
        HUnlock(compressedData);
        DisposeGWorld(myGWorld);
        DisposeHandle(compressedData);
        DisposeHandle((Handle)imageDescH);
    }
 
    err = UpdateMovieResource(theMovie, movieResRefNum, actualResId, nil);
    if (err != noErr)
        DebugStr("\pUpdateResource failed.");
 
    /*  This is the end of the code for adding the one frame to the movie.  */
 
    err = CloseMovieFile(movieResRefNum);
    if (GetMoviesError())
        return ((Movie)0);
    if (err)
        return ((Movie)0);
 
    return (theMovie);
}
 
/*------------------------------------------------------*/
/*  PlayMovie().                                            */
/*------------------------------------------------------*/
 
OSErr PlayMovie(int index)
{
    Rect movieBounds;
 
    GetMovieBox(myMovie[index], &movieBounds);
    OffsetRect(&movieBounds, -movieBounds.left, -movieBounds.top);
    if (movieBounds.right < 40)
        movieBounds.right = 40;
    if (movieBounds.bottom < 20)
        movieBounds.bottom = 20;
    SetMovieBox(myMovie[index], &movieBounds);
    OffsetRect(&movieBounds, startlocation, startlocation);
    myWindow[index] = NewCWindow(0L, &movieBounds, "\pMovie!", 1, 0, 
                                    (WindowPtr) - 1, true, 0L);
    startlocation += 50;
    if (startlocation > 300)
        startlocation = 50;
 
    SetMovieGWorld(myMovie[index], (CGrafPtr)myWindow[index], 0);
    if (GetMoviesError())
        DebugStr("\pSetMovieGWorld error.");
 
    /*  Uncomment these lines if you want to pre load the movie into ram.
      GotoBeginningOfMovie(myMovie[index]);
      if (LoadMovieIntoRam(myMovie[index], GetMovieTime(myMovie[index], 0L),
      GetMovieDuration(myMovie[index]),
      0) != noErr)
      DebugStr("\pNot enough memory to load movie into ram.");
    */
    SetMovieRate(myMovie[index], 0x00010000);
 
    return noErr;
}
 
/*------------------------------------------------------*/
/*  Flatten().                                          */
/*------------------------------------------------------*/
 
short Flatten(int index)
{
    StandardFileReply reply;
    OSErr theErr = noErr;
 
    StandardPutFile("\pName of Flattened movie.", "\pUntitled", &reply);
    if (!reply.sfGood)
        return fnOpnErr;
 
    theErr = GetMoviesError();
    if (theErr != noErr)
        DebugStr("\pCall Before FlattenMovies failed.");
 
    FlattenMovie(myMovie[index], flattenAddMovieToDataFork, &reply.sfFile, 
                        'TWOD', 0, createMovieFileDeleteCurFile, nil, nil);
 
    theErr = GetMoviesError();
    if (theErr != noErr)
        DebugStr("\pFlattenMovies failed.");
 
    return (theErr);
}
 
/*------------------------------------------------------*/
/*  showAboutMeDialog()                                 */
/*------------------------------------------------------*/
 
void showAboutMeDialog(void)
{
    GrafPtr savePort;
    DialogPtr theDialog;
    short itemHit;
 
    GetPort(&savePort);
    theDialog = GetNewDialog(aboutMeDLOG, nil, (WindowPtr) - 1);
    SetPort(theDialog);
 
    do
    {
        ModalDialog(nil, &itemHit);
    } while (itemHit != okButton);
 
    CloseDialog(theDialog);
 
    SetPort(savePort);
    return;
}
 
/*------------------------------------------------------*/
/*  Init().                                             */
/*------------------------------------------------------*/
 
void Init(void)
{
    OSErr err;
    int i;
    long QDfeature,
     OSfeature;
 
    /*  Initialize Managaer.    */
    InitGraf(&qd.thePort);
    FlushEvents(everyEvent, 0);
    InitWindows();
    InitDialogs(nil);
    InitCursor();
 
    /*  Set up menus.   */
    mymenu0 = GetMenu(appleID);
    AppendResMenu(mymenu0, 'DRVR');
    InsertMenu(mymenu0, 0);
    mymenu1 = GetMenu(fileID);
    InsertMenu(mymenu1, 0);
    DrawMenuBar();
 
    /*  Set up variables.   */
    startlocation = 50;
    for (i = 0; i < MAXWINDOWS; i++)
    {
        playingMovie[i] = false;
        myWindow[i] = nil;
    }
 
    /*  Use Gestalt to find if QuickDraw and QuickTime is available.    */
    if ((NGetTrapAddress(Gestalttest,OSTrap) != NGetTrapAddress(NoTrap,OSTrap)))
    {
        err = Gestalt(gestaltQuickdrawVersion, &QDfeature);
        if (err)
            ExitToShell();
        err = Gestalt(gestaltSystemVersion, &OSfeature);
        if (err)
            ExitToShell();
        if (!DoneFlag && (QDfeature & 0x0f00) != 0x0200 && OSfeature < 0x0607)
            ExitToShell();
        err = Gestalt(gestaltQuickTime, &QDfeature);
        if (err)
            ExitToShell();
    }
    else
        ExitToShell();
 
    /*  Open QuickTime last.    */
    err = EnterMovies();
    if (err)
        ExitToShell();
}
 
/*------------------------------------------------------*/
/*  Finish().                                           */
/*------------------------------------------------------*/
 
void Finish(void)
{
    ExitMovies();
    ExitToShell();
}
 
/*------------------------------------------------------*/
/*  DoOpenCommand().                                        */
/*------------------------------------------------------*/
 
void DoOpenCommand(void)
{
    int i,
     useThisIndex;
 
    useThisIndex = -1;
 
    /*  Search for the first window that is nil.    */
    for (i = MAXWINDOWS - 1; i >= 0; i--)
        if (myWindow[i] == nil)
            useThisIndex = i;
 
        /*  If index = -1, then it means that there are no windows avaiable.    */
    if (useThisIndex != -1)
    {
        myMovie[useThisIndex] = GetMovieFromFile();
        if (myMovie[useThisIndex] != 0)
        {
            PlayMovie(useThisIndex);
            playingMovie[useThisIndex] = true;
        }
    }
}
 
/*------------------------------------------------------*/
/*  DoFlattenCommand().                                     */
/*------------------------------------------------------*/
 
void DoFlattenCommand(void)
{
    int i;
    WindowPtr myTempWindow;
 
    /*  Flatten movie that is currently selected.   */
    myTempWindow = FrontWindow();
    if (myTempWindow == nil)
        return;
    for (i = 0; i < MAXWINDOWS; i++)
        if (myWindow[i] == myTempWindow)
            Flatten(i);
}
 
/*------------------------------------------------------*/
/*  DoCloseCommand().                                       */
/*------------------------------------------------------*/
 
void DoCloseCommand(void)
{
    int i;
    WindowPtr myTempWindow;
 
    /*  Close selected window.  */
    myTempWindow = FrontWindow();
    if (myTempWindow == nil)
        return;
    for (i = 0; i < MAXWINDOWS; i++)
        if (myWindow[i] == myTempWindow)
        {
            DisposeMovie(myMovie[i]);
            DisposeWindow(myTempWindow);
            playingMovie[i] = false;
            myWindow[i] = nil;
        }
}
 
/*------------------------------------------------------*/
/*  DoCommand().                                        */
/*------------------------------------------------------*/
 
void DoCommand(long mResult)
{
    int theMenu,
     theItem;
    Str255 daName;
    GrafPtr savePort;
 
    theItem = LoWord(mResult);
    theMenu = HiWord(mResult);
 
    switch (theMenu)
    {
        case appleID:
            if (theItem == aboutMeCommand)
                showAboutMeDialog();
            else
            {
                GetMenuItemText(mymenu0, theItem, daName);
                GetPort(&savePort);
                (void)OpenDeskAcc(daName);
                SetPort(savePort);
            }
            break;
 
        case fileID:
            switch (theItem)
            {
                case openCommand:
                    DoOpenCommand();
                    break;
                case flattenCommand:
                    DoFlattenCommand();
                    break;
                case closeCommand:
                    DoCloseCommand();
                    break;
                case quitCommand:
                    DoneFlag = true;
                    break;
                default:
                    break;
            }
            break;
    }
    HiliteMenu(0);
    return;
}
 
/*------------------------------------------------------*/
/*  PlayMovies().                                           */
/*------------------------------------------------------*/
 
void PlayMovies(void)
{
    int i;
 
    for (i = 0; i < MAXWINDOWS; i++)
        if (playingMovie[i] == true)
        {
            if (IsMovieDone(myMovie[i]) == false)
                MoviesTask(myMovie[i], DoTheRightThing);
        }
}
 
/*------------------------------------------------------*/
/*  main().                                             */
/*------------------------------------------------------*/
 
main()
{
    int i;
    char key;
    Boolean track;
    EventRecord myEvent;
    WindowPtr whichWindow;
    int yieldTime;
 
 
    Init();
    yieldTime = 0;
    for (;;)
    {
 
        /*  We can't just do ExitToShell because we must cann ExitMovies.   */
        if (DoneFlag)
            Finish();
 
        /*  Play movies which are active.   */
        PlayMovies();
 
        if (WaitNextEvent(everyEvent, &myEvent, yieldTime, nil))
        {
            switch (myEvent.what)
            {
                case mouseDown:
                    switch (FindWindow(myEvent.where, &whichWindow))
                    {
                        case inSysWindow:
                            SystemClick(&myEvent, whichWindow);
                            break;
                        case inMenuBar:
                            DoCommand(MenuSelect(myEvent.where));
                            break;
                        case inContent:
                            SelectWindow(whichWindow);
                            break;
                        case inDrag:
                            DragWindow(whichWindow, myEvent.where, &qd.screenBits.bounds);
                            break;
                        case inGrow:
                            break;
                        case inGoAway:
                            track = TrackGoAway(whichWindow, myEvent.where);
                            if (track)
                                DoCloseCommand();
                            break;
                        case inZoomIn:
                            break;
                        case inZoomOut:
                            break;
                        default:
                            break;
                    }
                    break;
                case keyDown:
                case autoKey:
                    key = myEvent.message & charCodeMask;
                    if (myEvent.modifiers & cmdKey)
                        if (myEvent.what == keyDown)
                            DoCommand(MenuKey(key));
                    break;
                case updateEvt:
                    for (i = 0; i < MAXWINDOWS; i++)
                        if ((WindowPtr)myEvent.message == myWindow[i])
                        {
                            BeginUpdate((WindowPtr)myWindow[i]);
                            EndUpdate((WindowPtr)myWindow[i]);
                        }
                    break;
                case diskEvt:
                    break;
                case activateEvt:
                    break;
                case app4Evt:
                    break;
                default:
                    break;
            }
        }
    }
}