sources/SimplePres.c

/*
    File:       SimplePres.c
 
    Copyright:  © 2000-2001 by Apple Computer, Inc., all rights reserved.
 
 
*/
 
#include <ConditionalMacros.h>
 
#include <string.h>
 
#include <QuickTimeStreaming.h>
 
#include "AppSupport.h"
#include "SimplePres.h"
#include "QTSSampleCodeUtils.h"
    
// ---------------------------------------------------------------------------
//      D E F I N I T I O N S
// ---------------------------------------------------------------------------
 
#define kDefaultPresTimeScale       600
 
#define kSimplePresSignature            FOUR_CHAR_CODE('smpr')
 
// ---------------------------------------------------------------------------
//      P R O T O T Y P E S
// ---------------------------------------------------------------------------
 
 
static OSErr SimplePresPriv_StartInternal(SimplePresRecord *inSimplePres);
 
static ComponentResult _SimplePresNotification(ComponentResult inErr, OSType inNotificationType,
                                void *inNotificationParams, void *inRefCon);
 
static ComponentResult SimplePresPriv_HandlePreviewAck(SimplePresRecord *inSimplePres, ComponentResult inErr);
static ComponentResult SimplePresPriv_HandlePrerollAck(SimplePresRecord *inSimplePres, ComponentResult inErr);
static ComponentResult SimplePresPriv_HandleStartAck(SimplePresRecord *inSimplePres, ComponentResult inErr);
static ComponentResult SimplePresPriv_HandleStopAck(SimplePresRecord *inSimplePres, ComponentResult inErr);
static ComponentResult SimplePresPriv_HandleStatusNotification(SimplePresRecord *inSimplePres,
            ComponentResult inErr, QTSStatusParams *inStatusParams);
static ComponentResult SimplePresPriv_HandleErrorNotification(SimplePresRecord *inSimplePres,
            const char *inNotificationTypeString,
            ComponentResult inErr, QTSErrorParams *inErrorParams);
 
// ---------------------------------------------------------------------------
//      U P P   S T U F F
// ---------------------------------------------------------------------------
 
static QTSNotificationUPP sNotificationUPP = NULL;
 
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      SimplePres_NewFromFile
// ---------------------------------------------------------------------------
 
OSErr SimplePres_NewFromFile(const FSSpec *inFileSpec, GWorldPtr inGWorld,
                    GDHandle inGD, const Rect *inPresBox, SimplePresRecord **outSimplePres)
{
    OSErr                   err = noErr;
    SimplePresRecord        *simplePres = NULL;
    QTSPresParams           presParams; 
    QTSMediaParams          mediaParams;
    QTSPresentation         presentation = kQTSInvalidPresentation;
    
    memset(&presParams, 0, sizeof(presParams));
    memset(&mediaParams, 0, sizeof(mediaParams));
    QTSInitializeMediaParams(&mediaParams);
 
    if (outSimplePres == NULL)  {
        DEBUGF(("SimplePres_NewFromFile - outSimplePres == NULL"));
        EXITERR( err = paramErr );
    }
 
    simplePres = (SimplePresRecord*)QTSNewPtrClear(sizeof(SimplePresRecord));
    EXITIFERR( err = MemError() );
    simplePres->signature = kSimplePresSignature;
    
 
    if (inPresBox != NULL)  {
        mediaParams.v.width = (Fixed)(inPresBox->right - inPresBox->left) << 16;
        mediaParams.v.height = (Fixed)(inPresBox->bottom - inPresBox->top) << 16;
        
        if ((inPresBox->left != 0)  ||  (inPresBox->top != 0))  {
            Rect            sourceRect;
            
            sourceRect.left = sourceRect.top = 0;
            sourceRect.right = inPresBox->right - inPresBox->left;
            sourceRect.bottom = inPresBox->bottom - inPresBox->top;
            // need a matrix - this is just a matrix for the preview...
            RectMatrix(&mediaParams.v.matrix, &sourceRect, inPresBox);
        }
    }
    mediaParams.v.gWorld = inGWorld;
    mediaParams.v.gdHandle = inGD;
 
    if (sNotificationUPP == NULL)  {
        sNotificationUPP = (QTSNotificationUPP)NewQTSNotificationUPP(_SimplePresNotification);
    }
 
    presParams.version = kQTSPresParamsVersion1;
    presParams.flags = kQTSSendMediaFlag |  kQTSAutoModeFlag | kQTSDontShowStatusFlag;
    presParams.timeScale = kDefaultPresTimeScale;
    presParams.mediaParams = &mediaParams;
    presParams.notificationProc = sNotificationUPP;
    presParams.notificationRefCon = simplePres;
 
    
    EXITIFERR( err = QTSNewPresentationFromFile(inFileSpec, &presParams, &simplePres->presentation) );
    simplePres->state = kSimplePresState_Idle;
    simplePres->targetState = kSimplePresState_Idle;
    
    
    *outSimplePres = simplePres;
 
exit:
    QTSDisposeMediaParams(&mediaParams);
    if (err != noErr)  {
        DEBUGF(("SimplePres_NewFromFile err %ld", err));
        if (simplePres != NULL)  {
            SimplePres_Dispose(simplePres);
        }
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      SimplePres_Dispose
// ---------------------------------------------------------------------------
 
void SimplePres_Dispose(SimplePresRecord *inSimplePres)
{
    if (inSimplePres != NULL)  {        
        if (inSimplePres->presentation != kQTSInvalidPresentation)  {
            QTSDisposePresentation(inSimplePres->presentation, 0L);
        }
 
        DisposePtr((Ptr)inSimplePres);
    }
    return;
}
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      SimplePres_Idle
// ---------------------------------------------------------------------------
 
void SimplePres_Idle(SimplePresRecord *inSimplePres)
{
    if (inSimplePres == NULL)  {
        DEBUGF(("SimplePres_Idle-null inSimplePres"));
        goto exit;
    }
 
 
    if (inSimplePres->presentation != kQTSInvalidPresentation)  {
        QTSPresIdle(inSimplePres->presentation, NULL);
    }
 
    switch (inSimplePres->state)  {
        case kSimplePresState_ReadyToPlay:
            // right now we have to preroll before calling start
            if (inSimplePres->targetState > kSimplePresState_ReadyToPlay)  {
                SimplePresPriv_StartInternal(inSimplePres);
            }
            break;
            
        default:
            break;  
    }
exit:
    return;
}
 
// ---------------------------------------------------------------------------
//      SimplePres_Start
// ---------------------------------------------------------------------------
 
OSErr SimplePres_Start(SimplePresRecord *inSimplePres)
{
    OSErr           err = noErr;
 
    if (inSimplePres->presentation == kQTSInvalidPresentation)  {
        DEBUGF(("SimplePres_Start $%.8x - null presentation", inSimplePres));
        EXITERR( err = qtsBadStateErr );
    }
    if (inSimplePres->state >= kSimplePresState_Starting)  {
        // we're already playing or trying to start
        DEBUGF(("SimplePres_Start $%.8x - already starting or playing state %ld", inSimplePres, inSimplePres->state));
        EXITERR( err = qtsBadStateErr );;
    }
    
    //  right now, we have to preroll before we start
    inSimplePres->targetState = kSimplePresState_Playing;
    inSimplePres->state = kSimplePresState_StartingPreroll;
    EXITIFERR( err = QTSPresPreroll(inSimplePres->presentation, kQTSAllStreams, 0, kQTSNormalForwardRate, 0L) );
        
exit:
    return err;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_StartInternal
// ---------------------------------------------------------------------------
 
static OSErr SimplePresPriv_StartInternal(SimplePresRecord *inSimplePres)
{
    OSErr       err = noErr;
 
    if (inSimplePres->presentation == kQTSInvalidPresentation)  {
        DEBUGF(("SimplePresPriv_StartInternal $%.8x - null presentation", inSimplePres));
        EXITERR( err = qtsBadStateErr );
    }
    inSimplePres->state = kSimplePresState_Starting;
    EXITIFERR( err = QTSPresStart(inSimplePres->presentation, kQTSAllStreams, 0L) );
 
exit:
    return err;
}
// ---------------------------------------------------------------------------
//      SimplePres_Stop
// ---------------------------------------------------------------------------
 
OSErr SimplePres_Stop(SimplePresRecord *inSimplePres)
{
    OSErr           err = noErr;
 
    if (inSimplePres->presentation == kQTSInvalidPresentation)  {
        DEBUGF(("SimplePres_Stop $%.8x - no presentation", inSimplePres));
        EXITERR( err = qtsBadStateErr );
    }
 
    inSimplePres->targetState = kSimplePresState_Idle;
    if (inSimplePres->state != kSimplePresState_Idle)  {
        inSimplePres->state = kSimplePresState_Idle;
        EXITIFERR( err = QTSPresStop(inSimplePres->presentation, kQTSAllStreams, 0L) );
    }
exit:
    return err;
}
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      _SimplePresNotification
// ---------------------------------------------------------------------------
 
static ComponentResult _SimplePresNotification(ComponentResult inErr, OSType inNotificationType,
                                void *inNotificationParams, void *inRefCon)
{
    SimplePresRecord    *simplePres = (SimplePresRecord*)inRefCon;
    ComponentResult     err = noErr;
    
    switch (inNotificationType)  {
    
        case kQTSPreviewAckNotification:
            err = SimplePresPriv_HandlePreviewAck(simplePres, inErr);
            break;
            
        case kQTSPrerollAckNotification:
            err = SimplePresPriv_HandlePrerollAck(simplePres, inErr);
            break;
            
        case kQTSStartAckNotification:
            err = SimplePresPriv_HandleStartAck(simplePres, inErr);
            break;
            
        case kQTSStopAckNotification:
            err = SimplePresPriv_HandleStopAck(simplePres, inErr);
            break;
            
        case kQTSStatusNotification:
            err = SimplePresPriv_HandleStatusNotification(simplePres, inErr, (QTSStatusParams*)inNotificationParams);
            break;  
    
        case kQTSErrorNotification:
            err = SimplePresPriv_HandleErrorNotification(simplePres, "error", inErr, (QTSErrorParams*)inNotificationParams);
            break;
        default:
            // it's ok to get a notification you don't know about
            // just silently ignore it - this is not an error
            break;
 
        // all you can do in a kQTSNewPresentationNotification
        // is store the presentation - do not make any presentation calls
        // when you that notification
 
    }
    
    if (simplePres->ownerNotificationProc != NULL)  {
        CallQTSNotificationProc(simplePres->ownerNotificationProc, inErr,
                inNotificationType, inNotificationParams, simplePres->ownerNotificationRefCon);
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_HandlePreviewAck
// ---------------------------------------------------------------------------
 
static ComponentResult SimplePresPriv_HandlePreviewAck(SimplePresRecord *inSimplePres, ComponentResult inErr)
{
    if (inSimplePres->state != kSimplePresState_StartingPreview)  {
        // we're in the wrong state to be getting this ack
        // ignore it...
        DEBUGF(("SimplePresPriv_HandlePreviewAck $%.8x - preview ack but state %ld inErr %ld", inSimplePres, inSimplePres->state, inErr));
    }  else  {
        if (inErr != noErr)  {
            SimplePresPriv_HandleErrorNotification(inSimplePres, "Preview", inErr, NULL);   
            inSimplePres->targetState = kSimplePresState_Idle;
            inSimplePres->state = kSimplePresState_Idle;
        }  else  {
            inSimplePres->state = kSimplePresState_Previewing;
        }
    }
    return noErr;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_HandlePrerollAck
// ---------------------------------------------------------------------------
 
static ComponentResult SimplePresPriv_HandlePrerollAck(SimplePresRecord *inSimplePres, ComponentResult inErr)
{
    if (inSimplePres->state != kSimplePresState_StartingPreroll)  {
        // we're in the wrong state to be getting this ack
        // ignore it...
        DEBUGF(("SimplePresPriv_HandlePrerollAck $%.8x - preroll ack but state %ld inErr %ld", inSimplePres, inSimplePres->state, inErr));
    }  else  {
        if (inErr != noErr)  {
            DEBUGF(("SimplePresPriv_HandlePrerollAck $%.8x, ack err %ld", inSimplePres, inErr));
            inSimplePres->targetState = kSimplePresState_Idle;
            inSimplePres->state = kSimplePresState_Idle;
            SimplePresPriv_HandleErrorNotification(inSimplePres, "Preroll", inErr, NULL);   
        }  else  {
            inSimplePres->state = kSimplePresState_ReadyToPlay;
        }
    }
    return noErr;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_HandleStartAck
// ---------------------------------------------------------------------------
 
static ComponentResult SimplePresPriv_HandleStartAck(SimplePresRecord *inSimplePres, ComponentResult inErr)
{
    if (inSimplePres->state != kSimplePresState_Starting)  {
        // we're in the wrong state to be getting this ack
        // ignore it...
        DEBUGF(("SimplePresPriv_HandleStartAck $%.8x - start ack but state %ld inErr %ld", inSimplePres, inSimplePres->state, inErr));
    }  else  {
        if (inErr != noErr)  {
            DEBUGF(("SimplePresPriv_HandleStartAck $%.8x, ack err %ld", inSimplePres, inErr));
            inSimplePres->targetState = kSimplePresState_Idle;
            inSimplePres->state = kSimplePresState_Idle;
            SimplePresPriv_HandleErrorNotification(inSimplePres, "Start", inErr, NULL); 
        }  else  {
            inSimplePres->state = kSimplePresState_Playing;
        }
    }
    return noErr;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_HandleStopAck
// ---------------------------------------------------------------------------
 
static ComponentResult SimplePresPriv_HandleStopAck(SimplePresRecord *inSimplePres, ComponentResult inErr)
{
    // we don't even check state here, because in this app, we don't care
    // other apps might track it more
    if (inErr != noErr)  {
        DEBUGF(("SimplePresPriv_HandleStopAck $%.8x, ack err %ld", inSimplePres, inErr));
        SimplePresPriv_HandleErrorNotification(inSimplePres, "Stop", inErr, NULL);  
    }
    return noErr;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_HandleStatusNotification
// ---------------------------------------------------------------------------
 
static ComponentResult SimplePresPriv_HandleStatusNotification(SimplePresRecord *inSimplePres,
            ComponentResult inErr, QTSStatusParams *inStatusParams)
{
#pragma unused(inSimplePres, inErr, inStatusParams)
 
exit:
    return noErr;
}
 
// ---------------------------------------------------------------------------
//      SimplePresPriv_HandleErrorNotification
// ---------------------------------------------------------------------------
 
static ComponentResult SimplePresPriv_HandleErrorNotification(SimplePresRecord *inSimplePres,
            const char *inNotificationTypeString,
            ComponentResult inErr, QTSErrorParams *inErrorParams)
{
#pragma unused(inSimplePres)
    // tell the user about the error in some nice way
    //  inErrorParams can be NULL
    if (inErrorParams == NULL)  {
        ProcessUserMessage(kProcessMessageFlag_Log | kProcessMessageFlag_ShowDialog,
            "Error (%ld) in %s notification", inErr, inNotificationTypeString);
    }  else  {
        ProcessUserMessage(kProcessMessageFlag_Log | kProcessMessageFlag_ShowDialog,
            "Error (%ld) in %s notification '%s'", inErr, inNotificationTypeString, inErrorParams->errorString);
    }
    return noErr;
}
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      SimplePres_SetOwnerNotification
// ---------------------------------------------------------------------------
 
OSErr SimplePres_SetOwnerNotification(SimplePresRecord *inSimplePres,
                    QTSNotificationUPP inOwnerNotificationProc, void *inRefCon)
{
    inSimplePres->ownerNotificationProc = inOwnerNotificationProc;
    inSimplePres->ownerNotificationRefCon = inRefCon;
    return noErr;
}
 
// ---------------------------------------------------------------------------
//      SimplePres_GetInfo
// ---------------------------------------------------------------------------
 
OSErr SimplePres_GetInfo(SimplePresRecord *inSimplePres, OSType inSelector, void *ioParams)
{
    OSErr           err = noErr;
    
    if (inSimplePres->presentation != kQTSInvalidPresentation)  {
        err = QTSPresGetInfo(inSimplePres->presentation, kQTSAllStreams, inSelector, ioParams);
    }  else  {
        DEBUGF(("SimplePres_GetInfo $%.8x - info $%.8x no presentation", inSimplePres, inSelector));
        err = qtsBadSelectorErr;
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      SimplePres_SetInfo
// ---------------------------------------------------------------------------
 
OSErr SimplePres_SetInfo(SimplePresRecord *inSimplePres, OSType inSelector, void *ioParams)
{
    OSErr           err = noErr;
 
    if (inSimplePres->presentation != kQTSInvalidPresentation)  {
        err = QTSPresSetInfo(inSimplePres->presentation, kQTSAllStreams, inSelector, ioParams);
    }  else  {
        DEBUGF(("SimplePres_SetInfo $%.8x - info $%.8x no presentation", inSimplePres, inSelector));
        err = qtsBadSelectorErr;
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      SimplePres_SettingsDialog
// ---------------------------------------------------------------------------
 
OSErr SimplePres_SettingsDialog(SimplePresRecord *inSimplePres)
{
    OSErr           err = noErr;
 
    if (inSimplePres->presentation != kQTSInvalidPresentation)  {
        err = QTSPresSettingsDialog(inSimplePres->presentation, kQTSAllStreams,  0, NULL, 0);
        if (err != noErr)  {
            DEBUGF(("SimplePres_SettingsDialog $%.8x- settingsdialog err %ld", inSimplePres, err));
        }
    }  else  {
        DEBUGF(("SimplePres_SettingsDialog $%.8x - no presentation", inSimplePres));
        err = qtsBadStateErr;
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      SimplePres_ExportToFile
// ---------------------------------------------------------------------------
 
OSErr SimplePres_ExportToFile(SimplePresRecord *inSimplePres, OSType inFileCreator)
{
    OSErr               err = noErr;
    QTSExportParams     exportParams;
 
#pragma unused (inFileCreator)
        
    if (inSimplePres->presentation != kQTSInvalidPresentation)  {
        memset(&exportParams, 0, sizeof(exportParams));
        exportParams.version = kQTSExportParamsVersion1;
        //exportParams.fileCreator = inFileCreator;
        exportParams.flagsIn = kQTSExportFlag_ShowDialog;
 
        err = QTSPresExport(inSimplePres->presentation, kQTSAllStreams, &exportParams);
        if (err != noErr)  {
            DEBUGF(("SimplePres_ExportToFile $%.8x- export err %ld", inSimplePres, err));
        }
    }  else  {
        DEBUGF(("SimplePres_ExportToFile $%.8x - no presentation", inSimplePres));
        err = qtsBadStateErr;
    }
    return err;
}