Sample Components/ImportScrapbook.c

/*
    File:       ImportScrapbook.r
 
    Written by: Peter Hoddie
 
    Copyright:  © 1992 by Apple Computer, Inc., all rights reserved.
 
*/
 
#include <Files.h>
#include <FixMath.h>
#include <QDOffscreen.h>
#include <QuickDraw.h>
#include <Resources.h>
#include <SysEqu.h>
#include <ToolUtils.h>
 
#include <QuickTimeComponents.h>
 
#define kMediaTimeScale 600
 
typedef struct {
    ComponentInstance self;
    TimeValue frameDuration;
} ImportScrapbookGlobalsRecord, **ImportScrapbookGlobals;
 
pascal ComponentResult ImportScrapbookDispatcher(ComponentParameters *params, Handle storage);
pascal ComponentResult ImportScrapbookOpen(ImportScrapbookGlobals storage, ComponentInstance self);
pascal ComponentResult ImportScrapbookClose(ImportScrapbookGlobals storage, ComponentInstance self);
pascal ComponentResult ImportScrapbookCanDo( ImportScrapbookGlobals storage, short ftnNumber );
pascal ComponentResult ImportScrapbookVersion( ImportScrapbookGlobals storage );
pascal ComponentResult ImportScrapbookSetSampleDuration(ImportScrapbookGlobals storage, 
            TimeValue duration, TimeScale scale);
pascal ComponentResult ImportScrapbookFile(ImportScrapbookGlobals storage, FSSpec *theFile, 
            Movie theMovie, Track targetTrack, Track *usedTrack, 
            TimeValue atTime, TimeValue *addedTime, long inFlags, long *outFlags);
 
short pageToMapIndex(short page, Ptr map);
 
// entry point for all Component Manager requests
pascal ComponentResult ImportScrapbookDispatcher(ComponentParameters *params, Handle storage)
{
    OSErr err = badComponentSelector;
    ComponentFunction componentProc = 0;
 
    switch (params->what) {
        case kComponentOpenSelect: componentProc = ImportScrapbookOpen; break;
        case kComponentCloseSelect: componentProc = ImportScrapbookClose; break;
        case kComponentCanDoSelect: componentProc = ImportScrapbookCanDo; break;
        case kComponentVersionSelect: componentProc = ImportScrapbookVersion; break;
        case kMovieImportFileSelect: componentProc = ImportScrapbookFile; break;
        case kMovieImportSetSampleDurationSelect: componentProc = ImportScrapbookSetSampleDuration; break;
    }
 
    if (componentProc)
        err = CallComponentFunctionWithStorage(storage, params, componentProc);
 
    return err;
}
 
pascal ComponentResult ImportScrapbookCanDo( ImportScrapbookGlobals storage, short ftnNumber )
{
    switch (ftnNumber) {
        case kComponentOpenSelect: 
        case kComponentCloseSelect: 
        case kComponentCanDoSelect: 
        case kComponentVersionSelect: 
        case kMovieImportFileSelect: 
        case kMovieImportSetSampleDurationSelect: 
            return true;
        default:
            return false;
    }
}
 
pascal ComponentResult ImportScrapbookVersion( ImportScrapbookGlobals storage )
{
    return 0x00010001;
}
 
pascal ComponentResult ImportScrapbookOpen(ImportScrapbookGlobals storage, ComponentInstance self)
{
    storage = (ImportScrapbookGlobals)NewHandleClear(sizeof(ImportScrapbookGlobalsRecord));
    if (!storage) return MemError();
    (**storage).self = self;
    SetComponentInstanceStorage(self, (Handle)storage);
 
    return noErr;
}
 
pascal ComponentResult ImportScrapbookClose(ImportScrapbookGlobals storage, ComponentInstance self)
{
    if (storage) DisposeHandle((Handle)storage);
 
    return noErr;
}
 
// if this routine is called, it provides a hint from the caller as to the
//  desired sample (frame) duration in the new media.
pascal ComponentResult ImportScrapbookSetSampleDuration(ImportScrapbookGlobals storage, 
                TimeValue duration, TimeScale scale)
{
    TimeRecord tr;
 
    tr.value.lo = duration;
    tr.value.hi = 0;
    tr.scale = 0;
    tr.base = nil;
    ConvertTimeScale(&tr, kMediaTimeScale);     // our new media will have a TimeScale of 600
 
    (**storage).frameDuration = tr.value.lo;
 
    return noErr;
}
 
pascal ComponentResult ImportScrapbookFile(ImportScrapbookGlobals storage, FSSpec *theFile,
        Movie theMovie, Track targetTrack, Track *usedTrack, 
        TimeValue atTime, TimeValue *addedTime, long inFlags, long *outFlags)
{
    OSErr err;
    short resRef = 0, saveRes = CurResFile();
    PicHandle thePict;
    Rect trackRect;
    short pageIndex = 0;
    Track newTrack = 0;
    Media newMedia;
    Boolean endMediaEdits = false;
    TimeValue frameDuration;
    SampleDescriptionHandle sampleDesc = 0;
 
    *outFlags = 0;
    if (inFlags & movieImportMustUseTrack)
        return invalidTrack;
 
    // open up source file
    resRef = FSpOpenResFile(theFile, fsRdPerm);
    if (err = ResError()) goto bail;
    UseResFile(resRef);
 
    // get the first PICT to determine the track size
    thePict = (PicHandle)Get1IndResource('PICT', 1);
    if (!thePict) {
        err = ResError();
        goto bail;
    }
    trackRect = (**thePict).picFrame;
    OffsetRect(&trackRect, -trackRect.left, -trackRect.top);
 
 
    // create a track and 'PICT' media
    newTrack = NewMovieTrack(theMovie, trackRect.right << 16, trackRect.bottom << 16, kNoVolume);
    if (err = GetMoviesError()) goto bail;
    newMedia = NewTrackMedia(newTrack, 'PICT', kMediaTimeScale, nil, 0);
    if (err = GetMoviesError()) goto bail;
    if (err = BeginMediaEdits(newMedia)) goto bail;
    endMediaEdits = true;
 
    // determine the frame duration (check the hint we may have been called with)
    frameDuration = (**storage).frameDuration;
    if (!frameDuration) frameDuration = kMediaTimeScale/5;                  // default is 1/5th sec 
 
    // set up a simple sample description
    sampleDesc = (SampleDescriptionHandle)NewHandleClear(sizeof(SampleDescription));
    (**sampleDesc).descSize = sizeof(SampleDescription);
    (**sampleDesc).dataFormat = 'PICT';
 
    // interate through all source frames and add them to the media
    do {
        Handle thePict;
        short resID = pageToMapIndex(++pageIndex, *GetResource('SMAP', 0));
 
        if (resID == 0) break;
        thePict = Get1Resource('PICT', resID);
        if (thePict == nil) continue;       // some pages may not contain a PICT
 
        err = AddMediaSample(newMedia, thePict, 0, GetHandleSize(thePict),
            frameDuration, sampleDesc, 1, 0, nil);
 
        ReleaseResource(thePict);
        DisposeHandle(thePict);
    } while (!err);
    if (err) goto bail;
 
    // add the new media to the track
    err = InsertMediaIntoTrack(newTrack, 0, 0, GetMediaDuration(newMedia), kFix1);
 
bail:
    if (resRef) CloseResFile(resRef);
    if (endMediaEdits) EndMediaEdits(newMedia);
    if (err && newTrack) {
        DisposeMovieTrack(newTrack);
        newTrack = 0;
    }
    UseResFile(saveRes);
    if (sampleDesc) DisposeHandle((Handle)sampleDesc);
    *usedTrack = newTrack;
 
    return err;
}
 
// map from a Scrapbook page number to a resource id
short pageToMapIndex(short page, Ptr map)
{
    short mapIndex;
 
    for (mapIndex = 0; mapIndex < 256; mapIndex++)
        if (*map++ == page)
            return mapIndex | 0x8000;
 
    return 0;
}