MySGStuff.c

/*
    File:       MySGStuff.c
    
    Contains:   Sequence grabber code.
 
    Written by: John Wang
 
    Copyright:  © 1994 by Apple Computer, Inc., all rights reserved.
 
    Change History (most recent first):
 
        <5>     07/01/94    JW      1.0     Added workaround for AV machines that don't initialize video
                                            settings properly.  The fix is to call GetSetting and then SetSettings
                                            when no preferences is loaded for the channel.
        <4>     04/25/94    JW      1.0b4.  Fixed minor bug in 1.0b3 where if the sound channel wasn't
                                            opened, then MyUpdateChannels would fail.
        <3>     04/18/94    JW      1.0b3.  Support for multiple capture channels.
        <2>     04/08/94    JW      1.0b2.  Support for preferences file added so that channel
                                            settings is preserved.
        <1>     04/04/94    JW      1.0b1   Started and created as 1.0b1.
 
    To Do:
    
*/
 
#ifdef THINK_C
#define     applec
#endif
 
#include    "MyHeaders"
/*
#include    <Types.h>
#include    <Memory.h>
#include    <QuickDraw.h>
#include    <Palettes.h>
#include    <QDOffscreen.h>
#include    <Errors.h>
#include    <Fonts.h>
#include    <Dialogs.h>
#include    <Windows.h>
#include    <Menus.h>
#include    <Events.h>
#include    <Desk.h>
#include    <DiskInit.h>
#include    <OSUtils.h>
#include    <Resources.h>
#include    <ToolUtils.h>
#include    <AppleEvents.h>
#include    <EPPC.h>
#include    <GestaltEqu.h>
#include    <Processes.h>
#include    <Balloons.h>
#include    <Aliases.h>
#include    <MixedMode.h>
#include    <Scrap.h>
#include    <LowMem.h>
 
#include    <Movies.h>
#include    <QuickTimeComponents.h>
*/
 
#include    "MyCaptureAppShell.h"
#include    "MySGStuff.h"
#include    "MyUtils.h"
 
/* ------------------------------------------------------------------------- */
 
//  Contains application runtime variables.  Stored in window refCon as handle block.
struct WindowInfo {
    ComponentInstance       theSG;
    SGChannel               channel[kMAXCHANNELS];
    Boolean                 recordPlayThru;
    Boolean                 createSeparateFiles;
};
typedef     struct WindowInfo WindowInfo, *WindowInfoPtr, **WindowInfoHandle;
 
//  Contains compression settings for the video channel.  Used in SGInfo.
struct CompressionInfo {
    OSType      compressorType;
    short       depth;
    CodecQ      spatialQuality;
    CodecQ      temporalQuality;
    long        keyFrameRate;
};
typedef     struct CompressionInfo CompressionInfo;
 
//  Contains Sequence Grabber channel information.  Stored as a global variable.
struct SGInfo {
    CompressionInfo     cInfo;
    OSType              channelType[kMAXCHANNELS];
    Handle              channelName[kMAXCHANNELS];
    UserData            channelSettings[kMAXCHANNELS];
};
typedef     struct SGInfo SGInfo;
SGInfo      gSGInfo;
 
//  Boolean variable.  true is QuickTime 2.0 or later.  false otherwise i.e. 1.6.2.
Boolean     gHasQuickTime20;
 
/* ------------------------------------------------------------------------- */
 
//  MyInitialize is called at init time after the toolbox is initialized.  This routine is
//  called only once.
 
long MyInitialize()
{
    long                    err;
    long                    QDfeature;
    short                   myRefNum;
    short                   i;
    ComponentDescription    cd, theCD;
    Component               aComponent;
    Boolean                 done;
    MenuHandle              mHandle;
    
    //  We require QuickTime so make sure it is available.
    err = Gestalt(gestaltQuickTime, &QDfeature);
    if ( err != noErr )
        return ( err );
        
    //  Check for QuickTime 2.0 or later.
    gHasQuickTime20 = ((QDfeature >> 16) & 0xffff) >= 0x200;
    
    //  Start the engine.
    err = EnterMovies();
    if ( err != noErr )
        return ( err) ;
    
    //  Find out what sequence grabber channels are available by searching all sequence
    //  grabber channel components.  Get channelType[] and channelName[].
    for ( i=0; i<kMAXCHANNELS; i++ ) {
        gSGInfo.channelType[i] = 0;
        gSGInfo.channelName[i] = nil;
    }
    cd.componentType = SeqGrabChannelType;
    cd.componentSubType = 0;
    cd.componentManufacturer = 0;
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;
    aComponent = 0;
    for ( i=0, done=false; i<kMAXCHANNELS && !done; i++ ) {
        aComponent = FindNextComponent(aComponent, &cd);
        if (aComponent != 0) {
            gSGInfo.channelName[i] = NewHandle(4);
            GetComponentInfo(aComponent, &theCD, gSGInfo.channelName[i], nil, nil);
            gSGInfo.channelType[i] = theCD.componentSubType;
        } else
            done = true;
    }
 
    //  Read preferences for compression settings and
    //  channelSettings[] (if channel has been previously found).
    if ( (myRefNum = readPreferencesFile()) != -1 ) {
        //  File opened.
        Handle          myHandle;
 
        //  Get Compression info.
        myHandle = Get1Resource('INFO', 128);
        if ( myHandle != nil ) {
            DetachResource(myHandle);
            HLock(myHandle);
            BlockMove(*myHandle, &(gSGInfo.cInfo), sizeof(CompressionInfo));
            HUnlock(myHandle);
            DisposeHandle(myHandle);
        } else {
            //  If no such resource, then manually udpate the values.
            gSGInfo.cInfo.compressorType = 'raw ';
            gSGInfo.cInfo.depth = 16;
            gSGInfo.cInfo.spatialQuality = codecLosslessQuality;
            gSGInfo.cInfo.temporalQuality = 0;
            gSGInfo.cInfo.keyFrameRate = 0;
        }
        
        //  Get all the saved channel settings for the channels that are available.
        for ( i=0; i< kMAXCHANNELS; i++ ) {
            if (gSGInfo.channelType[i] != 0) {
                myHandle = Get1Resource(gSGInfo.channelType[i], 128);
                if ( myHandle != nil ) {
                    err = NewUserDataFromHandle(myHandle, &(gSGInfo.channelSettings[i]));
                    if ( err != noErr ) {
                        ReportWarning("\pCould not create user data from handle: ", err);
                        gSGInfo.channelSettings[i] = nil;
                    }
                } else
                    gSGInfo.channelSettings[i] = nil;
            } else
                gSGInfo.channelSettings[i] = nil;
        }
        
        //  Finished.  Close the preferences file.
        closePreferencesFile(myRefNum);
    } else {
        //  If no preferences file, then use default values.
        gSGInfo.cInfo.compressorType = 'raw ';
        gSGInfo.cInfo.depth = 16;
        gSGInfo.cInfo.spatialQuality = codecLosslessQuality;
        gSGInfo.cInfo.temporalQuality = 0;
        gSGInfo.cInfo.keyFrameRate = 0;
        for ( i=0; i< kMAXCHANNELS; i++ )
            gSGInfo.channelSettings[i] = nil;
    }
 
    //  Add the channel names to the menu.
    mHandle = GetMHandle(kMENU_SETTINGSID);
    for ( i=0; i<kMAXCHANNELS; i++ ) {
        if (gSGInfo.channelType[i] != 0) {
            Str255      myStr;
            
            BlockMove("   Disable", &myStr[1], 11);
            BlockMove(*(gSGInfo.channelName[i]), &myStr[11], **(gSGInfo.channelName[i]) + 1);
            myStr[0] = 11 + **(gSGInfo.channelName[0]);
            myStr[11] = ' ';
            AppendMenu(mHandle, (unsigned char *) *(gSGInfo.channelName[i]));
            AppendMenu(mHandle, myStr);
        }
    }
 
    return ( noErr );
}
 
void MyFinishup()
{
    long                err;
    short               myRefNum, i;
    
    //  Should close all windows.  But, since we know this app only supports one window, we
    //  don't need to loop.
    MyClose();
 
    //  Write preferences file for all channel settings and compression settings.
    if ((myRefNum = writePreferencesFile()) != -1) {
        Handle          mySetting, myInfo;
        
        //  Write the compressor settings to preferences file.
        myInfo = NewHandle(sizeof(CompressionInfo));
        if ( myInfo == nil ) {
            ReportWarning("\pCound not create compressor settings handle.", 0);
        } else {
            HLock((Handle) myInfo);
            BlockMove(&(gSGInfo.cInfo), *myInfo, sizeof(CompressionInfo));
            HUnlock((Handle) myInfo);
            AddResource(myInfo, 'INFO', 128, "\pCompression Settings.");
        }
        
        //  Write out channel settings.
        for ( i=0; i< kMAXCHANNELS; i++ ) {
            if (gSGInfo.channelType[i] != 0 && gSGInfo.channelSettings[i] != nil ) {
                mySetting = NewHandle(4);
                if ( mySetting == nil ) {
                    ReportWarning("\pCound not create settings handle.", 0);
                } else {
                    PutUserDataIntoHandle(gSGInfo.channelSettings[i], mySetting);
                    AddResource(mySetting, gSGInfo.channelType[i], 128, "\pSettings.");
                }
            } else
                gSGInfo.channelSettings[i] = nil;
        }
        
        closePreferencesFile(myRefNum);
    } else
        ReportWarning("\pSorry.  Could not create preferences file.", 0);
}
 
void MyIdle()
{
    WindowPtr       theWindow;
 
    theWindow = FrontWindow();
    
    //  Only one window allowed to be opened at a time.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        if ((**myWindowInfo).theSG != nil)
            SGIdle((**myWindowInfo).theSG);
    }
}
 
long MyYieldTime(long message)
{
    if ( message )
        //  Resume message
        return ( 0 );
    else
        //  Suspend message
        return ( 30 );
}
 
void MyAdjustMenus()
{
    MenuHandle          mHandle;
    WindowPtr           theWindow;
    WindowInfoHandle    myWindowInfo;
    short               i;
    
    theWindow = FrontWindow();
    
    myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
 
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        //  File menu.
        mHandle = GetMHandle(kMENU_FILEID);
        DisableItem(mHandle, kMENU_FILENEW);
        EnableItem(mHandle, kMENU_FILECLOSE);
        
        //  Settings menu.
        mHandle = GetMHandle(kMENU_SETTINGSID);
        EnableItem(mHandle, 0);
        for ( i=0; i<kMAXCHANNELS; i++ ) {
            if (gSGInfo.channelType[i] != 0) {
                if ( (**myWindowInfo).channel[i] != nil ) {
                    EnableItem(mHandle, i*2+1);
                    EnableItem(mHandle, i*2+2);
                } else {
                    DisableItem(mHandle, i*2+1);
                    DisableItem(mHandle, i*2+2);
                }
            }
        }
 
        //  Resize menu.
        mHandle = GetMHandle(kMENU_RESIZEID);
        EnableItem(mHandle, 0);
 
        //  Special menu.
        mHandle = GetMHandle(kMENU_SPECIALID);
        EnableItem(mHandle, 0);
        CheckItem(mHandle, kMENU_SPECIALPLAYTHRU, (**myWindowInfo).recordPlayThru);
        if ( !gHasQuickTime20 ) {
            (**myWindowInfo).createSeparateFiles = false;
            DisableItem(mHandle, kMENU_SPECIALSEPARATEFILES);
        } else
            EnableItem(mHandle, kMENU_SPECIALSEPARATEFILES);
        CheckItem(mHandle, kMENU_SPECIALSEPARATEFILES, (**myWindowInfo).createSeparateFiles);
    
        //  Record menu.
        mHandle = GetMHandle(kMENU_RECORDID);
        EnableItem(mHandle, 0);
 
    } else {    //  No window open.
        //  File menu.
        mHandle = GetMHandle(kMENU_FILEID);
        EnableItem(mHandle, kMENU_FILENEW);
        DisableItem(mHandle, kMENU_FILECLOSE);
 
        //  Settings menu.
        mHandle = GetMHandle(kMENU_SETTINGSID);
        DisableItem(mHandle, 0);
        for ( i=0; i<kMAXCHANNELS; i++ ) {
            if (gSGInfo.channelType[i] != 0) {
                EnableItem(mHandle, i*2);
                EnableItem(mHandle, i*2+1);
            }
        }
 
        //  Resize menu.
        mHandle = GetMHandle(kMENU_RESIZEID);
        DisableItem(mHandle, 0);
 
        //  Special menu.
        mHandle = GetMHandle(kMENU_SPECIALID);
        DisableItem(mHandle, 0);
        CheckItem(mHandle, kMENU_SPECIALPLAYTHRU, false);
        CheckItem(mHandle, kMENU_SPECIALSEPARATEFILES, false);
 
        //  Record menu.
        mHandle = GetMHandle(kMENU_RECORDID);
        DisableItem(mHandle, 0);
    }
    
    DrawMenuBar();
}
 
/* ------------------------------------------------------------------------- */
 
void MyNew()
{
    long                    err;
    WindowPtr               myWindow;
    Rect                    myBounds = {42, 4, 282, 324};
    WindowInfoHandle        myWindowInfo;
    short                   i, videoChannel, soundChannel;
    
    myWindow = nil;
    myWindowInfo = nil;
    
    //  Create window along with window info record.
    myWindow = NewCWindow(0L, &myBounds, "\pCapture window", 1, documentProc, (WindowPtr) -1, true, 0L);
    if (myWindow == nil) {
        ReportWarning("\pCould not create new window.",0);
        goto bail;
    }
    SetGWorld((CGrafPtr) myWindow, GetMainDevice());
    myWindowInfo = (WindowInfoHandle) NewHandleClear(sizeof(WindowInfo));
    if ( myWindowInfo == nil ) {
        ReportWarning("\pCould not create window info handle.", 0);
        goto bail;
    }
    MoveHHi((Handle) myWindowInfo);
    HLock((Handle) myWindowInfo);
    SetWRefCon(myWindow, (long) myWindowInfo);
    (**myWindowInfo).recordPlayThru = false;
    (**myWindowInfo).createSeparateFiles = false;
    
    //  Open sequence grabber and initialize the sequence grabber.
    (**myWindowInfo).theSG = OpenDefaultComponent(SeqGrabComponentType, 0);
    if ( (**myWindowInfo).theSG == nil) {
        ReportWarning("\pOpenDefaultComponent failed to open default sequence grabber component.", 0);
        goto bail;
    }
    err = SGInitialize((**myWindowInfo).theSG);
    if ( err != noErr ) {
        ReportWarning("\pCould not initialize sequence grabber: ", err);
        goto bail;
    }
    
    //  First things first, set the GWorld to the newly created window.
    err = SGSetGWorld((**myWindowInfo).theSG, (CGrafPtr) myWindow, GetMainDevice());
    if ( err != noErr ) {
        ReportWarning("\pCould not SGSetGWorld: ", err);
        goto bail;
    }
    
    //  Now, let's create the different channels.
    for ( i=0; i<kMAXCHANNELS; i++ ) {
        //  If the channel type exists, then create it.
        if ( gSGInfo.channelType[i] != 0) {
 
            //  Create channel.
            err = SGNewChannel((**myWindowInfo).theSG, gSGInfo.channelType[i],
                                        &((**myWindowInfo).channel[i]));
            if ( err != noErr ) {
                //  Fail with this channel.
                ReportWarning("\pCould not open channel: ", err);
                (**myWindowInfo).channel[i] = 0;
            } else {
                //  Set the settings retrieved from preferences file.
                if ( gSGInfo.channelSettings[i] != nil ) {
                    err = SGSetChannelSettings((**myWindowInfo).theSG, (**myWindowInfo).channel[i],
                                            gSGInfo.channelSettings[i], 0);
                    if ( err != noErr ) {
                        ReportWarning("\pFailed to set channel settings: ", err);
                    }
                } else {
                //  Workaround for AV vdigs that don't initialize correctly.
                    err = SGGetChannelSettings((**myWindowInfo).theSG, (**myWindowInfo).channel[i],
                                            &(gSGInfo.channelSettings[i]), 0);
                    if ( err != noErr ){
                        ReportWarning("\pCould not get channel settings: ", err);
                        gSGInfo.channelSettings[i] = nil;
                    }
                    err = SGSetChannelSettings((**myWindowInfo).theSG, (**myWindowInfo).channel[i],
                                            gSGInfo.channelSettings[i], 0);
                    if ( err != noErr ) {
                        ReportWarning("\pFailed to set channel settings: ", err);
                    }
                }
            }
        } else
            (**myWindowInfo).channel[i] = 0;
    }
    
    //  If there is a video channel, then set the compression settings.
    for ( videoChannel = -1, i=0; i<kMAXCHANNELS; i++ ) {
        if ( gSGInfo.channelType[i] == VideoMediaType )
            videoChannel = i;
    }
    if ( videoChannel >= 0 ) {
        err = SGSetVideoCompressorType((**myWindowInfo).channel[videoChannel], gSGInfo.cInfo.compressorType);
        if ( err != noErr ) {
            ReportWarning("\pCould not set video compressor type: ", err);
        }
        err = SGSetVideoCompressor((**myWindowInfo).channel[videoChannel], gSGInfo.cInfo.depth, nil,
                        gSGInfo.cInfo.spatialQuality, gSGInfo.cInfo.temporalQuality, gSGInfo.cInfo.keyFrameRate);
        if ( err != noErr ) {
            ReportWarning("\pCould not set video compressor info: ", err);
        }
    }
    
    //  Update the channels.
    err = MyUpdateChannels(myWindow);
    if ( err != noErr ) {
        ReportWarning("\pCould not update channels: ", err);
        goto bail;
    }
    
    //  Start the preview now that everything is set up!!!
    err = SGStartPreview((**myWindowInfo).theSG);
    if ( err != noErr ) {
        ReportWarning("\pCould not start preview.", err);
        goto bail;
    }
    
    return;
 
bail:
    SysBeep(50);
    if ( (**myWindowInfo).theSG != nil )
        CloseComponent((**myWindowInfo).theSG);
    if ( myWindowInfo != nil )
        DisposHandle((Handle) myWindowInfo);
    if ( myWindow != nil )
        DisposeWindow(myWindow);
    return;
}
 
void MyClose()
{
    long                err;
    WindowPtr           closeWindow;
    WindowInfoHandle        myWindowInfo;
    short               i, videoChannel;
    
    closeWindow = FrontWindow();
    if ( closeWindow == nil )
        return;
    myWindowInfo = (WindowInfoHandle) GetWRefCon(closeWindow);
 
    //  If there is a video channel, then get the compression settings.
    for ( videoChannel = -1, i=0; i<kMAXCHANNELS; i++ ) {
        if ( gSGInfo.channelType[i] == VideoMediaType )
            videoChannel = i;
    }
    if ( videoChannel >= 0 ) {
        err = SGGetVideoCompressorType((**myWindowInfo).channel[videoChannel], &gSGInfo.cInfo.compressorType);
        if ( err != noErr )
            gSGInfo.cInfo.compressorType = 'raw ';
        err = SGGetVideoCompressor((**myWindowInfo).channel[videoChannel], &gSGInfo.cInfo.depth, nil,
                        &gSGInfo.cInfo.spatialQuality, &gSGInfo.cInfo.temporalQuality,
                        &gSGInfo.cInfo.keyFrameRate);
        if ( err != noErr ) {
            gSGInfo.cInfo.depth = 16;
            gSGInfo.cInfo.spatialQuality = codecLosslessQuality;
            gSGInfo.cInfo.temporalQuality = 0;
            gSGInfo.cInfo.keyFrameRate = 0;
        }
    }
    
    //  Get the video settings.
    for ( i=0; i<kMAXCHANNELS; i++ ) {
    
        //  Set the video settings retrieved from preferences file.
        if ( gSGInfo.channelType[i] != 0 && (**myWindowInfo).channel[i] != 0) {
            err = SGGetChannelSettings((**myWindowInfo).theSG, (**myWindowInfo).channel[i],
                                    &(gSGInfo.channelSettings[i]), 0);
            if ( err != noErr ){
                ReportWarning("\pCould not get channel settings: ", err);
                gSGInfo.channelSettings[i] = nil;
            }
        }
    }
        
    //  Close the component. 
    if ( (**myWindowInfo).theSG != nil )
        CloseComponent((**myWindowInfo).theSG);
    
    if ( myWindowInfo != nil )
        DisposHandle((Handle) myWindowInfo);
    
    DisposeWindow(closeWindow);
}
 
/* ------------------------------------------------------------------------- */
 
void MySettings(short item)
{
    long            err;
    WindowPtr       theWindow;
    short           index;
    
    theWindow = FrontWindow();
    
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        
        index = (item - 1) / 2;
        if ( (item & 1) == 0 ) {
            //  Pause before making changes.
            err = SGPause((**myWindowInfo).theSG, true);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
 
            //  Disable channel.
            if ( (**myWindowInfo).channel[index] != 0 ) {
                SGDisposeChannel((**myWindowInfo).theSG, (**myWindowInfo).channel[index]);
                (**myWindowInfo).channel[index] = 0;
            }
            
            err = SGPause((**myWindowInfo).theSG, false);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
 
        } else {
            //  Simply call SGSettingsDialog!  That simple!
            SGSettingsDialog((**myWindowInfo).theSG, (**myWindowInfo).channel[index], 0, nil, DoTheRightThing, nil , 0);
        }
    }
}
 
void MyResize(short item)
{
    WindowPtr       theWindow;
    long            err;
    Boolean         sizeChanged;
    short           width, height;
    
    theWindow = FrontWindow();
    
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        sizeChanged = false;
        switch ( item ) {
            case 1:
                width = 160; height = 120;
                sizeChanged = true;
                break;
            case 2:
                width = 240; height = 180;
                sizeChanged = true;
                break;
            case 3:
                width = 320; height = 240;
                sizeChanged = true;
                break;
            case 5:
                sizeChanged = GetCustomSize(&width, &height);
                break;
        }
        if ( sizeChanged ) {
            //  Pause the sequence grabber before resizing window.
            err = SGPause((**myWindowInfo).theSG, true);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
            
            //  Resize and then update the video channel.
            SizeWindow(theWindow, width, height, false);
            err = MyUpdateChannels(theWindow);
            if ( err != noErr ) {
                ReportWarning("\pCould not update channels: ", err);
            }
            
            //  OK.  We can restart again.
            err = SGPause((**myWindowInfo).theSG, false);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
        }
    }
    
}
 
void MySpecial(short item)
{
    WindowPtr       theWindow;
    long            err;
    Boolean         updateFlag;
    
    theWindow = FrontWindow();
    
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        updateFlag = false;
        switch ( item ) {
            case kMENU_SPECIALPLAYTHRU:
                (**myWindowInfo).recordPlayThru = !(**myWindowInfo).recordPlayThru;
                updateFlag = true;
                break;
            case kMENU_SPECIALSEPARATEFILES:
                (**myWindowInfo).createSeparateFiles = !(**myWindowInfo).createSeparateFiles;
                break;
        }
        
        //  Only update if needed.
        if ( updateFlag ) {
            //  Pause before changes.
            err = SGPause((**myWindowInfo).theSG, true);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
            
            //  Update the channels.
            err = MyUpdateChannels(theWindow);
            if ( err != noErr ) {
                ReportWarning("\pCould not update channels: ", err);
            }
            
            //  OK to continue.
            err = SGPause((**myWindowInfo).theSG, false);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
        }
    }
}
 
void MyRecord()
{
    WindowPtr           theWindow;
    long                err;
    StandardFileReply   reply;
    ComponentInstance   mySG;
    AliasHandle         alias;
    SGOutput            output;
    short               i;
    
    theWindow = FrontWindow();
    
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        mySG = (**myWindowInfo).theSG;
        if ( mySG != nil ) {
            
            if ( (**myWindowInfo).createSeparateFiles ) {
                for ( i=0; i<kMAXCHANNELS; i++ ) {
                    if ( (**myWindowInfo).channel[i] != 0) {
                        StandardPutFile("\PName of multiple file:", "\pMovie #", &reply);
                        if (!reply.sfGood)
                            return;
                        err = CreateMovieFile(&(reply.sfFile), 'TVOD', smSystemScript,
                            createMovieFileDeleteCurFile |
                            createMovieFileDontCreateMovie |
                            createMovieFileDontOpenFile, nil, nil);
                        if ( err != noErr ) {
                            ReportWarning("\pCould not create movie file 1: ", err);
                            goto bail;
                        }
                        NewAlias(nil, &(reply.sfFile), &alias);
                        if ( alias == nil )
                            return;
                        err = SGSetDataRef(mySG, (Handle) alias, 'alis', seqGrabToDisk);
                        if ( err != noErr ) {
                            ReportWarning("\pCould not set movie resource output: ", err);
                            goto bail;
                        }
                        err = SGNewOutput(mySG, (Handle) alias, 'alis', seqGrabToDisk, &output);
                        if ( err != noErr ) {
                            ReportWarning("\pCould not create data output1: ", err);
                            goto bail;
                        }
                        err = SGSetChannelOutput(mySG, (**myWindowInfo).channel[i], output);
                        if ( err != noErr ) {
                            ReportWarning("\pCould not set video channel output: ", err);
                            goto bail;
                        }
                    }
                }
            } else {
                //  If creating single file, then do this.
                StandardPutFile("\PName of new movie:", "\pMovie", &reply);
                if (!reply.sfGood)
                    return;
                err = SGSetDataOutput(mySG, &reply.sfFile, seqGrabToDisk);
                if ( err != noErr ) {
                    ReportWarning("\pCould not set data output: ", err);
                    goto bail;
                }
            }
 
            //  Set the window title so that the user knows that we are recording.
            SetWTitle(theWindow, "\pRecording... click mouse to stop.");
 
            //  Start recording.
            err = SGStartRecord(mySG);
            if ( err != noErr ) {
                ReportWarning("\pCould not start recording.  The following error was returned: ", err);
            }
            
            //  Keep recording until the mouse button is pressed.
            while (!Button() && !err) {
                err = SGIdle(mySG);
            }
            
            //  Stop recording.
            err = SGStop(mySG);
            if ( err != noErr ) {
                ReportWarning("\pCould not stop sequence grabber: ", err);
                goto bail;
            } else
                SetWTitle(theWindow, "\pMovie captured.");
 
            //  Start preview again.
 
    err = MyUpdateChannels(theWindow);
    if ( err != noErr ) {
        ReportWarning("\pCould not update channels: ", err);
        goto bail;
    }
    
            err = SGStartPreview((**myWindowInfo).theSG);
            if ( err != noErr ) {
                ReportWarning("\pCould not start preview: ", err);
                goto bail;
            }
            
            //  Reset the window title.
            SetWTitle(theWindow, "\pCapture window");
 
            FlushEvents(mDownMask | mUpMask, 0);
        }
    }
    
bail:
    return;
}
 
void MyDrag(WindowPtr theWindow, Point where)
{
    long            err;
 
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        if ((**myWindowInfo).theSG != nil)
            //  Pause preview.
            err = SGPause((**myWindowInfo).theSG, true);
            if ( err != noErr ) {
                ReportWarning("\pCould no pause preview: ", err);
            }
            
            //  Drag window.
            DragWindow (theWindow, where, &qd.screenBits.bounds);
            
            //  OK to restart preview.
            err = SGPause((**myWindowInfo).theSG, false);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
    }
}
 
void MyUpdate(WindowPtr theWindow)
{
    long            err;
 
    //  Allow only one window to be opened.
    if ( theWindow != nil ) {   //  Yes, window open.
        WindowInfoHandle    myWindowInfo;
        
        myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
        if ((**myWindowInfo).theSG != nil)
            //  Pause and continue to reset clip.
            err = SGPause((**myWindowInfo).theSG, true);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
            err = SGPause((**myWindowInfo).theSG, false);
            if ( err != noErr ) {
                ReportWarning("\pCould not pause preview: ", err);
            }
    }
}
 
long MyUpdateChannels(WindowPtr theWindow)
{
    long                err;
    WindowInfoHandle    myWindowInfo;
    long                usage;
    short               i, videoChannel;
    err = noErr;
    myWindowInfo = (WindowInfoHandle) GetWRefCon(theWindow);
    
    //  Update the video channel if it exists.
    for ( videoChannel = -1, i=0; i<kMAXCHANNELS; i++ ) {
        if ( gSGInfo.channelType[i] == VideoMediaType )
            videoChannel = i;
    }
    if ( videoChannel >= 0 ) {
        //  Set the bounds to the entire portRect.
        err = SGSetChannelBounds((**myWindowInfo).channel[videoChannel], &(theWindow->portRect));
        if ( err != noErr )
            goto bail;
            
        //  Set the video usage depending on whether or not there is playthru.
        usage = seqGrabPreview | seqGrabRecord;
        if ( !((**myWindowInfo).recordPlayThru) )
            usage |= seqGrabPlayDuringRecord;
        err = SGSetChannelUsage((**myWindowInfo).channel[videoChannel], usage);
        if ( err != noErr )
            goto bail;
    }
 
    for ( i=0; i<kMAXCHANNELS; i++ ) {
    //  Since sound may be turned off, check before setting sound usage.
        if ( (gSGInfo.channelType[i] != VideoMediaType && gSGInfo.channelType[i] != 0) &&
                (**myWindowInfo).channel[i] != 0) {
            err = SGSetChannelUsage((**myWindowInfo).channel[i], seqGrabPreview | seqGrabRecord |  seqGrabPlayDuringRecord);
            if ( err != noErr )
                goto bail;
        }
    }
    
bail:
    return ( err );
}
 
/* ------------------------------------------------------------------------- */
 
Boolean GetCustomSize(short *width, short *height)
{
    GrafPtr     savePort;
    GDHandle    saveGD;
    DialogPtr   theDialog;
    short       itemHit;
    Str255      myStr;
    Boolean     done, ret;
    long        lWidth, lHeight;
    
    GetPort(&savePort);
    saveGD = GetGDevice();
    theDialog = GetNewDialog(130, nil, (WindowPtr) -1);
    SetPort(theDialog);
    SetGDevice(GetMainDevice());
    
    //  Reset data to begin.
    SetText(theDialog, 4, "\p640");
    SetText(theDialog, 6, "\p480");
 
    //  Get membershipid and each inventory id
    done = false;
    do {
        ModalDialog(nil, &itemHit);
        GetText(theDialog, 4, myStr);
        StringToNum(myStr, &lWidth);
        GetText(theDialog, 6, myStr);
        StringToNum(myStr, &lHeight);
        if (itemHit == 1 ) {
            if (lWidth > 0 && lWidth <= 640 && lHeight >= 0 && lHeight <= 480)
                done = true;
            else
                SysBeep(50);
        }
    } while ((!done) && (itemHit != 2));
 
    if ( itemHit == 1 ) {
        GetText(theDialog, 4, myStr);
        StringToNum(myStr, &lWidth);
        *width = lWidth;
        GetText(theDialog, 6, myStr);
        StringToNum(myStr, &lHeight);
        *height = lHeight;
        ret = true;
    } else {
        ret = false;
    }
 
    DisposeDialog(theDialog);
    SetPort(savePort);
    SetGDevice(saveGD);
    
    return ( ret );
}
 
/* ------------------------------------------------------------------------- */
 
void GetText(DialogPtr theDialog, short item, Str255 myStr)
{
    Handle      myHandle;
    Rect        myRect;
    short       myType;
 
    GetDItem(theDialog, item, &myType, &myHandle, &myRect);
    GetIText(myHandle, myStr);
}
 
void SetText(DialogPtr theDialog, short item, Str255 myStr)
{
    Handle      myHandle;
    Rect        myRect;
    short       myType;
 
    GetDItem(theDialog, item, &myType, &myHandle, &myRect);
    SetIText(myHandle, myStr);
}