ImportExportMovie.c

/*
    File:       ImportExportMovie.c
 
    Written by: Peter Hoddie
 
    Copyright:  © 1992 by Apple Computer, Inc., all rights reserved.
 
*/
 
#include <SysEqu.h>
 
#include <Memory.h>
#include <Resources.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <StandardFile.h>
#include <ToolUtils.h>
#include <Desk.h>
#include <GestaltEqu.h>
 
#include <Movies.h>
#include <QuickTimeComponents.h>
 
#define kExportMenu 155
#define kMyCustomSaveDialog 128
#define kMyMBar 128
#define kAboutBox 129
 
enum {
    menuApple = 128,
    menuFile
};
enum {
    fileImport = 1,
    fileExport,
    fileUnused1,
    fileQuit
};
 
pascal Boolean myImportFileFilter(ParmBlkPtr PB);
void importMovie(void);
 
pascal Boolean myExportFileFilter(ParmBlkPtr PB);
pascal short myDlgHook(short item, DialogPtr theDialog, short *whichConverter);
void exportMovie(void);
 
Boolean doMenuItem(long menuChoice);
 
//
// IMPORT MOVIE
//
 
/*
    The import file filter checks the given file to see if there is a
        Movie Import Component available which could translate it into a
        movie. If one is available, the file is allowed to be shown.
*/
pascal Boolean myImportFileFilter(ParmBlkPtr PB)
{
    ComponentDescription cd;
    Boolean result = true;          // true means we don't want it
 
    cd.componentType = MovieImportType;
    cd.componentSubType = PB->fileParam.ioFlFndrInfo.fdType;
    cd.componentManufacturer = 0;
    cd.componentFlags = canMovieImportFiles;
    cd.componentFlagsMask = canMovieImportFiles;
 
    if (FindNextComponent(0, &cd))  // search for component to do the work
        result = false;
 
    return result;
}
 
void importMovie(void)
{
    OSErr err;
    StandardFileReply reply;
    SFReply putFile;
    FSSpec newFile;
    Str255 newName;
    Point where = {100,100};
    Component c;
    ComponentDescription cd;
 
    StandardGetFilePreview(myImportFileFilter, 0, nil, &reply);
    if (!reply.sfGood) return;
 
    BlockMove(reply.sfFile.name, newName, sizeof(reply.sfFile.name));
    newName[++newName[0]] = '!';
    SFPutFile(where, "\pName imported movie:", newName, nil, &putFile);
    if (!putFile.good) return;
 
    FSMakeFSSpec(putFile.vRefNum, 0, putFile.fName, &newFile);
 
    cd.componentType = MovieImportType;
    cd.componentSubType = reply.sfType;
    cd.componentManufacturer = 0;
    cd.componentFlags = canMovieImportFiles;
    cd.componentFlagsMask = canMovieImportFiles;
    c = FindNextComponent(nil, &cd);
    if (!c) return;                     // too weird. no import component exists
    GetComponentInfo(c, &cd, nil, nil, nil);
    if (cd.componentFlags & hasMovieImportUserInterface) {
        MovieImportComponent importer;
        Boolean canceled = false;
 
        importer = OpenComponent(c);
        err = MovieImportDoUserDialog(importer, &reply.sfFile, nil, &canceled);
        if (err || canceled) {
            CloseComponent(importer);
            return;
        }
        err = ConvertFileToMovieFile(&reply.sfFile, &newFile, 'TVOD', reply.sfScript, nil,
            createMovieFileDeleteCurFile, importer, (MovieProgressProcPtr)-1, 0);
        CloseComponent(importer);
    }
    else {
        // no import user interface option, so let the toolbox open the component
        err = ConvertFileToMovieFile(&reply.sfFile, &newFile, 'TVOD', reply.sfScript, nil,
            createMovieFileDeleteCurFile, nil, (MovieProgressProcPtr)-1, 0);
    }
    if (err) {
        SysBeep(1);
        DeleteMovieFile(&newFile);
    }
}
 
//
// EXPORT MOVIE
//
 
/*
    This file filter is particularly slimey. Standard File Preview automatically tries
        to show all non-movie files that it could convert to movies. In a dialog to select
        a movie to export, we only want to see movies. So what we do here is refetch the
        file type for the selected file via the File System to see if Standard File
        Preview is lying to us about the file type. If the file is indeed a movie, we
        let it be shown. 
*/
pascal Boolean myExportFileFilter(ParmBlkPtr PB)
{
    FSSpec fss;
    FInfo info;
 
    FSMakeFSSpec(-*(short *)SFSaveDisk, *(long *)CurDirStore, PB->fileParam.ioNamePtr, &fss);
    FSpGetFInfo(&fss, &info);
    if (info.fdType == MovieFileType)
        return false;
    else
        return true;
}
 
/*
    This skanky hook just constantly (and stupidly) watches the value of the export
        types menu and jams it back into our local variable below.
*/
pascal short myDlgHook(short item, DialogPtr theDialog, short *whichConverter)
{
    short kind;
    Handle h;
    Rect r;
 
    if (GetWRefCon(theDialog) != sfMainDialogRefCon)
        return item;
 
    GetDItem(theDialog, sfItemNewFolderUser+1, &kind, &h, &r); // first custom item
    *whichConverter = GetCtlValue((ControlHandle)h);
 
    return item;
}
 
void exportMovie(void)
{
    OSErr err;
    StandardFileReply reply, putFile;
    OSType movieType = MovieFileType;
    MenuHandle mh = GetMenu(kExportMenu);
    ComponentDescription cd;
    Component c = 0;
    Point where = {0,0};
    Str255 newName;
    short convertItem = 1;
    Component **exportComponents;
    Movie theMovie = nil;
    short resRef;
    OSType creator;
 
    StandardGetFilePreview(myExportFileFilter, 1, &movieType, &reply);
    if (!reply.sfGood) return;
 
    // get the movie.
    OpenMovieFile(&reply.sfFile, &resRef, fsRdPerm);
        NewMovieFromFile(&theMovie, resRef, nil, nil,
                0, nil);
    CloseMovieFile(resRef);
    if (!theMovie) return;
    SetMovieProgressProc(theMovie, (MovieProgressProcPtr)-1, 0);
 
    // build a list of all export components which are applicable to this movie
    exportComponents = (Component **)NewHandle(0);
 
    cd.componentType = MovieExportType;
    cd.componentSubType = 0;
    cd.componentManufacturer = 0;
    cd.componentFlags = canMovieExportFiles;
    cd.componentFlagsMask = canMovieExportFiles;
    while (c = FindNextComponent(c, &cd)) {
        Handle h = NewHandle(4);
        ComponentDescription exportCD;
 
        if (GetComponentInfo(c, &exportCD, h, nil, nil) == noErr) {
            Str255 s;
            Handle h2 = NewHandle(4);
            ComponentDescription mhcd;
            Component mediaHandler;
 
            mhcd.componentType = MediaHandlerType;
            mhcd.componentSubType = exportCD.componentManufacturer;
            mhcd.componentManufacturer = 0;
            mhcd.componentFlags = 0;
            mhcd.componentFlagsMask = 0;
            if (mediaHandler = FindNextComponent(0, &mhcd)) {
                long trackCount = GetMovieTrackCount(theMovie);
                long i;
                Boolean foundMedia = true;
 
                // make sure the media type the component can export is in the movie
                if (exportCD.componentManufacturer) {
                    foundMedia = false;
                    for (i=1; i<=trackCount; i++) {
                        Track t = GetMovieIndTrack(theMovie, i);
                        OSType mediaType;
    
                        GetMediaHandlerDescription(GetTrackMedia(t), &mediaType, nil, nil);
                        foundMedia = (mediaType == exportCD.componentManufacturer);
                        if (foundMedia) break;
                    }
                }
 
                if (foundMedia && (GetComponentInfo(mediaHandler, nil, h2, nil, nil) == noErr)) {
                    Str255 s;
 
                    // build menu name in un-international friendly way
                    if (exportCD.componentManufacturer) {
                        BlockMove(*h2, s, sizeof(s));
                        s[++s[0]] = ' ';
                        s[++s[0]] = 't';
                        s[++s[0]] = 'o';
                        s[++s[0]] = ' ';
                    }
                    else
                        s[0] = 0;
                    BlockMove(*h + 1, &s[s[0] + 1], **h);
                    s[0] += **h;
 
                    AppendMenu(mh, s);
                    PtrAndHand((Ptr)&c, (Handle)exportComponents, sizeof(c));
                    DisposHandle(h);
                }
            }
        }
 
        DisposHandle(h);
    }
    InsertMenu(mh, -1);
 
    if (GetHandleSize((Handle)exportComponents) == 0) {
        // no export components for this movie are available
        SysBeep(1);
        goto bail;
    }
 
    BlockMove(reply.sfFile.name, newName, 255);
    newName[++newName[0]] = '!';
    CustomPutFile("\pExport a file", newName, &putFile,
                    kMyCustomSaveDialog, where, (DlgHookYDProcPtr)myDlgHook, 
                    nil, nil, nil, (void *)&convertItem);
    if (!putFile.sfGood) goto bail;
 
    GetComponentInfo((*exportComponents)[convertItem - 1], &cd, nil, nil, nil);
 
    // cheap map in the application to allow us to chose the file creator
    {
    Handle h = GetResource('fMap', 128);
    short count = GetHandleSize(h) / (sizeof(OSType) * 2);
    OSType *creators = *(OSType **)h;
 
    creator = '????';
    while (count-- > 0) {
        if (*creators++ == cd.componentSubType) {
            creator = *creators;
            break;
        }
        creators++;
    }
    }
 
    if (cd.componentFlags & hasMovieExportUserInterface) {
        MovieExportComponent exporter;
        Boolean canceled = false;
 
        exporter = OpenComponent((*exportComponents)[convertItem - 1]);
        err = MovieExportDoUserDialog(exporter, &reply.sfFile, nil, &canceled);
        if (err || canceled) {
            CloseComponent(exporter);
            return;
        }
        err = ConvertMovieToFile(theMovie, nil, &putFile.sfFile,
            cd.componentSubType, creator, putFile.sfScript, nil, createMovieFileDeleteCurFile,
            exporter);
        CloseComponent(exporter);
    }
    else {
        // no user interface available. let the movie toolbox do the hard part
        err = ConvertMovieToFile(theMovie, nil, &putFile.sfFile,
            cd.componentSubType, creator, putFile.sfScript, nil, createMovieFileDeleteCurFile,
            (ComponentInstance)(*exportComponents)[convertItem - 1]);
    }
 
    if (err)
        SysBeep(1);
 
bail:
    DeleteMenu(kExportMenu);
    DisposeMenu(mh);
    DisposeMovie(theMovie);
    DisposHandle((Handle)exportComponents);
}
 
Boolean doMenuItem(long menuChoice)
{
    Boolean done = false;
    short whichMenu = HiWord(menuChoice);
    short whichItem = LoWord(menuChoice);
 
    switch (whichMenu) {
        case menuApple: 
                    if (whichItem > 2) {
                        Str255 daName;
                        
                        GetItem(GetMHandle(menuApple), whichItem, daName);
                        OpenDeskAcc(daName);
                    }
                    else
                        Alert(kAboutBox, nil);
                    break;
 
        case menuFile:  
                    switch (whichItem) {
                        case fileImport:
                                    importMovie();
                                    break;
                        case fileExport:
                                    exportMovie();
                                    break;
                        case fileQuit:
                                    done = true;
                                    break;
                    }
                    break;
    }
 
    HiliteMenu(0);
 
    return done;
}
 
 
void main(void)
{
    OSErr err;
    Boolean done = false;
    long response;
 
    // initialize the world
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(0L);
    InitCursor();
    MaxApplZone();
 
    // need system 7. slimey check
    //  we use pop-up cdef and custom putfile
    if (*(short *)SysVersion < 0x0700) return;
 
    // must have QuickTime around
    if (Gestalt(gestaltQuickTime, &response)) return;
 
    err = EnterMovies();
    if (err) return;
 
    SetMenuBar(GetNewMBar(kMyMBar));
    DrawMenuBar();
 
    AddResMenu(GetMHandle(menuApple), 'DRVR');
 
    while (!done) {
        EventRecord theEvent;
 
        SystemTask();
        GetNextEvent(everyEvent, &theEvent);
        switch (theEvent.what) {
            case mouseDown: {
                                short part;
                                WindowPtr whichWindow;
 
                                part = FindWindow(theEvent.where, &whichWindow);
                                switch (part) {
                                    case inMenuBar:
                                                done = doMenuItem(MenuSelect(theEvent.where));
                                                break;
                                    case inSysWindow:
                                                SystemClick(&theEvent, whichWindow);
                                                break;
                                }
                            }
                            break;
 
            case keyDown:   {
                            char c;
 
                            c = theEvent.message & charCodeMask;
                            if (theEvent.modifiers & cmdKey)
                                done = doMenuItem(MenuKey(c));
                            }
                            break;
        }
 
    }
}