Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
OpenGLCodec.m
/* |
File: OpenGLCodec.c |
Description: This is an example of a Transfer Codec - it is dedicated to be used with SoftVOut |
a fake software implementation of a video output 'vout' component. |
Author: QuickTime Engineering |
Copyright: © Copyright 1998 - 2001 Apple Computer, Inc. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): <1> 12/20/01 Initial Release |
*/ |
/* |
If your video output device cannot display a pixel format defined by QuickTime, you should include |
a special decompressor, known as a transfer codec, that converts one of the supported QuickTime pixel |
formats (preferably 32-bit RGB) to data that the device can display. When this transfer codec is |
available, the QuickTime Image Compression Manager automatically uses it together with its built-in |
decompressors. This, in turn, lets applications or other software draw any QuickTime video directly |
to the video output component's graphics world. |
A transfer codec is a specialized image decompressor component, and should be based on the Base Image |
Decompressor. |
*/ |
#if __APPLE_CC__ || __MACH__ |
#include <Carbon/Carbon.h> |
#include <QuickTime/QuickTime.h> |
#import <Foundation/Foundation.h> |
#else |
#include <ConditionalMacros.h> |
#include <Endian.h> |
#include <ImageCodec.h> |
#include <Resources.h> |
#endif |
#import "Layer.h" |
// Constants |
static const UInt8 kNumPixelFormatsSupported = 1; |
static const UInt8 kCodecInfoResNum = 129; |
// Because this is a custom codec which implements a custom pixel format, you have to provide |
// all codec functionality, for example Masking(Clipping) and Scaling, yourself. QuickTime |
// isn't going to do any of this work for you. |
// NOTE: This example does not actually scale, but we say we do because it's expected of us. |
static const long kCodecCapabilitiesFlags = codecCanMask | codecCanScale | codecCanTransform | codecCanRemapColor | codecCanRemapResolution; |
// Per frame globals |
typedef struct { |
long width; |
long height; |
long depth; |
long maxBytesPerRow; |
long maxRows; |
} OpenGLCodecDecompressRecord; |
// Per instance globals |
typedef struct { |
ComponentInstance self; |
ComponentInstance target; |
ComponentInstance baseCodec; |
OSType codecType; |
OSType** wantedDestinationPixelTypeH; |
ImageCodecMPDrawBandUPP drawBandUPP; |
unsigned char *imageBuffer; |
unsigned long imageBufferRowBytes; |
id owner; |
} OpenGLCodecGlobalsRecord, *OpenGLCodecGlobals; |
/************************************************************************************/ |
// Setup required for ComponentDispatchHelper.c |
pascal ComponentResult |
OpenGLCodec_LockBits(OpenGLCodecGlobals storage, CGrafPtr port); |
pascal ComponentResult |
OpenGLCodec_UnlockBits(OpenGLCodecGlobals storage, CGrafPtr port); |
enum { |
kImageCodecLockBitsSelect = 0x0026, |
kImageCodecUnlockBitsSelect = 0x0027 |
}; |
enum { |
uppImageCodecLockBitsProcInfo = 0x000003F0, |
uppImageCodecUnlockBitsProcInfo = 0x000003F0 |
}; |
#define IMAGECODEC_BASENAME() OpenGLCodec_ |
#define IMAGECODEC_GLOBALS() OpenGLCodecGlobals storage |
#define CALLCOMPONENT_BASENAME() IMAGECODEC_BASENAME() |
#define CALLCOMPONENT_GLOBALS() IMAGECODEC_GLOBALS() |
#define COMPONENT_DISPATCH_FILE "OpenGLCodecDispatch.h" |
#define GET_DELEGATE_COMPONENT() (storage->baseCodec) |
#define COMPONENT_UPP_SELECT_ROOT() ImageCodec |
#include "Components.k.h" // Standard .k.h |
#include "ImageCodec.k.h" |
#include "ComponentDispatchHelper.c" // Make the dispatcher and canDo |
#pragma mark- |
Component OpenGLARGBComponent; |
Component OpenGL2VUYComponent; |
Component OpenGLYUVSComponent; |
void OpenGLCodec_DoRegister() |
{ |
ComponentRoutineUPP glComponentUPP; |
ComponentDescription cd; |
ICMPixelFormatInfo pixelInfo; |
cd.componentType = decompressorComponentType; |
cd.componentSubType = 'OGLR'; |
cd.componentManufacturer = 'WWDC'; |
cd.componentFlags = codecInfoDoes32 | |
codecInfoDoes16 | |
codecInfoDoesStretch | |
codecInfoDoesDouble | |
codecInfoDoesMask | |
codecInfoDoesQuad; // component flags |
cd.componentFlagsMask = 0; |
glComponentUPP = NewComponentRoutineUPP((ComponentRoutineProcPtr)OpenGLCodec_ComponentDispatch); |
OpenGLARGBComponent = RegisterComponent(&cd, glComponentUPP, 0, NULL, NULL, NULL); |
cd.componentSubType = '2vuy'; |
OpenGL2VUYComponent = RegisterComponent(&cd, glComponentUPP, 0, NULL, NULL, NULL); |
cd.componentSubType = 'yuvs'; |
OpenGLYUVSComponent = RegisterComponent(&cd, glComponentUPP, 0, NULL, NULL, NULL); |
// Register information about our custom pixel format with the ICM, this is |
// needed only for the case where the VOut is using a transfer codec (SoftCodec) |
memset(&pixelInfo, 0, sizeof(pixelInfo)); |
pixelInfo.size = sizeof(ICMPixelFormatInfo); |
pixelInfo.formatFlags = 0; |
pixelInfo.bitsPerPixel[0] = 32; |
// Ignore any errors as this could be a duplicate registration |
ICMSetPixelFormatInfo('OGLR', &pixelInfo); |
} |
/* -- This Image Decompressor User the Base Image Decompressor Component -- |
The base image decompressor is an Apple-supplied component |
that makes it easier for developers to create new decompressors. |
The base image decompressor does most of the housekeeping and |
interface functions required for a QuickTime decompressor component, |
including scheduling for asynchronous decompression. |
*/ |
/************************************************************************************/ |
// Component Manager Calls |
// Component Open Request - Required |
pascal ComponentResult OpenGLCodec_Open(OpenGLCodecGlobals glob, ComponentInstance self) |
{ |
ComponentDescription cd; |
ComponentResult err; |
// Allocate memory for our globals, set them up and inform the component |
// manager that we've done so |
glob = (OpenGLCodecGlobals)NewPtrClear(sizeof(OpenGLCodecGlobalsRecord)); |
if ((err = MemError())) goto bail; |
SetComponentInstanceStorage(self, (Handle)glob); |
glob->self = self; |
glob->target = self; |
glob->drawBandUPP = NULL; |
// Open and target an instance of the base decompressor |
err = OpenADefaultComponent(decompressorComponentType, kBaseCodecType, &glob->baseCodec); |
if (err) goto bail; |
// Set us as the base component's target |
CallComponentTarget(glob->baseCodec, self); |
// Record our codecType for posterity |
err = GetComponentInfo((Component)self, &cd, NULL, NULL, NULL); |
if (err) goto bail; |
glob->codecType = cd.componentSubType; |
// Allocate memory for our wantedDestinationPixelType list, we fill it in during the Preflight call. |
glob->wantedDestinationPixelTypeH = (OSType **)NewHandle(sizeof(OSType) * (kNumPixelFormatsSupported + 1)); |
bail: |
return err; |
} |
// Component Close Request - Required |
pascal ComponentResult OpenGLCodec_Close(OpenGLCodecGlobals glob, ComponentInstance self) |
{ |
if (glob) { |
if (glob->baseCodec) |
CloseComponent(glob->baseCodec); |
if (glob->wantedDestinationPixelTypeH) |
DisposeHandle((Handle)glob->wantedDestinationPixelTypeH); |
if (glob->drawBandUPP) { |
DisposeImageCodecMPDrawBandUPP(glob->drawBandUPP); |
} |
DisposePtr((Ptr)glob); |
} |
return noErr; |
} |
// Component Version Request - Required |
pascal ComponentResult OpenGLCodec_Version(OpenGLCodecGlobals glob) |
{ |
#pragma unused(glob) |
return (codecInterfaceVersion << 2) + 1; |
} |
// Component Register Request |
pascal ComponentResult OpenGLCodec_Register(OpenGLCodecGlobals glob) |
{ |
#pragma unused(glob) |
// Always register |
return noErr; |
} |
// Component Target Request |
// Allows another component to "target" you i.e., you call another component whenever |
// you would call yourself (as a result of your component being used by another component). |
pascal ComponentResult OpenGLCodec_Target(OpenGLCodecGlobals glob, ComponentInstance target) |
{ |
ComponentResult err; |
// Tell the base component to target the instance |
err = CallComponentTarget(glob->baseCodec, target); |
if (err) goto bail; |
// Remember our target |
glob->target = target; |
bail: |
return err; |
} |
#pragma mark- |
/************************************************************************************/ |
// Base Component Calls |
// ImageCodecInitialize |
// The first function call that your image decompressor component receives from the base image |
// decompressor is always a call to ImageCodecInitialize . In response to this call, your image decompressor |
// component returns an ImageSubCodecDecompressCapabilities structure that specifies its capabilities. |
pascal ComponentResult OpenGLCodec_Initialize(OpenGLCodecGlobals glob, ImageSubCodecDecompressCapabilities *cap) |
{ |
#pragma unused(glob) |
cap->decompressRecordSize = sizeof(OpenGLCodecDecompressRecord); |
cap->canAsync = true; |
return noErr; |
} |
// ImageCodecPreflight |
// The base image decompressor gets additional information about the capabilities of your image |
// decompressor component by calling ImageCodecPreflight. The base image decompressor uses this |
// information when responding to a call to the ImageCodecPredecompress function, |
// which the ICM makes before decompressing an image. You are required only to provide values for |
// the wantedDestinationPixelSize and wantedDestinationPixelTypes fields and can also modify other |
// fields if necessary. |
pascal ComponentResult OpenGLCodec_Preflight(OpenGLCodecGlobals glob, CodecDecompressParams *p) |
{ |
CodecCapabilities *capabilities = p->capabilities; |
OSTypePtr formats = *glob->wantedDestinationPixelTypeH; |
// Fill in formats for wantedDestinationPixelTypeH |
// Terminate with an OSType value 0 - see IceFloe #7 |
// http://developer.apple.com/quicktime/icefloe/dispatch007.html |
*formats++ = kOpenGLPixelFormat; |
*formats++ = 0; |
// The base codec adds some flags, so OR in our own flags as well |
capabilities->flags = capabilities->flags | kCodecCapabilitiesFlags; // | codecIsDirectToScreenOnly | codecWantsDestinationPixels; |
//capabilities->flags2 = codecUsesOverlaySurface | codecImageBufferIsOverlaySurface | codecSrcMustBeImageBuffer; |
capabilities->flags2 = codecSrcMustBeImageBuffer; |
capabilities->wantedPixelSize = 0; |
p->wantedDestinationPixelTypes = glob->wantedDestinationPixelTypeH; |
capabilities->extendWidth = 0; |
capabilities->extendHeight = 0; |
return noErr; |
} |
// ImageCodecBeginBand |
// The ImageCodecBeginBand function allows your image decompressor component to save information about |
// a band before decompressing it. This function is never called at interrupt time. The base image decompressor |
// preserves any changes your component makes to any of the fields in the ImageSubCodecDecompressRecord |
// or CodecDecompressParams structures. If your component supports asynchronous scheduled decompression, it |
// may receive more than one ImageCodecBeginBand call before receiving an ImageCodecDrawBand call. |
pascal ComponentResult OpenGLCodec_BeginBand(OpenGLCodecGlobals glob, CodecDecompressParams *p, ImageSubCodecDecompressRecord *drp, long flags) |
{ |
#pragma unused(glob, flags) |
return noErr; |
} |
// ImageCodecDrawBand |
// The base image decompressor calls your image decompressor component's ImageCodecDrawBand function |
// to decompress a band or frame. Your component must implement this function. If the ImageSubCodecDecompressRecord |
// structure specifies a progress function or data-loading function, the base image decompressor will never call ImageCodecDrawBand |
// at interrupt time. If the ImageSubCodecDecompressRecord structure specifies a progress function, the base image decompressor |
// handles codecProgressOpen and codecProgressClose calls, and your image decompressor component must not implement these functions. |
// You can however optionally implement the codecProgressUpdatePercent function to provide progress information during lengthy |
// decompression operations. |
// If the ImageSubCodecDecompressRecord structure does not specify a progress function the base image decompressor may call the |
// ImageCodecDrawBand function at interrupt time. |
// When the base image decompressor calls your ImageCodecDrawBand function, your component must perform the decompression specified |
// by the fields of the ImageSubCodecDecompressRecord structure. The structure includes any changes your component made to it |
// when performing the ImageCodecBeginBand function. If your component supports asynchronous scheduled decompression, |
// it may receive more than one ImageCodecBeginBand call before receiving an ImageCodecDrawBand call. |
pascal ComponentResult OpenGLCodec_DrawBand(OpenGLCodecGlobals glob, ImageSubCodecDecompressRecord *drp) |
{ |
#pragma unused(glob) |
return noErr; |
} |
// ImageCodecEndBand |
// The ImageCodecEndBand function notifies your image decompressor component that decompression of a band has finished or |
// that it was terminated by the Image Compression Manager. Your image decompressor component is not required to implement |
// the ImageCodecEndBand function. The base image decompressor may call the ImageCodecEndBand function at interrupt time. |
// After your image decompressor component handles an ImageCodecEndBand call, it can perform any tasks that are required |
// when decompression is finished, such as disposing of data structures that are no longer needed. Because this function |
// can be called at interrupt time, your component cannot use this function to dispose of data structures; this |
// must occur after handling the function. The value of the result parameter should be set to noErr if the band or frame was |
// drawn successfully. If it is any other value, the band or frame was not drawn. |
pascal ComponentResult OpenGLCodec_EndBand(OpenGLCodecGlobals glob, ImageSubCodecDecompressRecord *drp, OSErr result, long flags) |
{ |
#pragma unused(glob, drp, result, flags) |
return noErr; |
} |
// ImageCodecQueueStarting |
// If your component supports asynchronous scheduled decompression, the base image decompressor calls your image decompressor component's |
// ImageCodecQueueStarting function before decompressing the frames in the queue. Your component is not required to implement this function. |
// It can implement the function if it needs to perform any tasks at this time, such as locking data structures. |
// The base image decompressor never calls the ImageCodecQueueStarting function at interrupt time. |
pascal ComponentResult OpenGLCodec_QueueStarting(OpenGLCodecGlobals glob) |
{ |
#pragma unused(glob) |
return noErr; |
} |
// ImageCodecQueueStopping |
// If your image decompressor component supports asynchronous scheduled decompression, the ImageCodecQueueStopping function notifies |
// your component that the frames in the queue have been decompressed. Your component is not required to implement this function. |
// After your image decompressor component handles an ImageCodecQueueStopping call, it can perform any tasks that are required when decompression |
// of the frames is finished, such as disposing of data structures that are no longer needed. |
// The base image decompressor never calls the ImageCodecQueueStopping function at interrupt time. |
pascal ComponentResult OpenGLCodec_QueueStopping(OpenGLCodecGlobals glob) |
{ |
#pragma unused(glob) |
return noErr; |
} |
#pragma mark- |
/************************************************************************************/ |
// Codec Component Calls |
// ImageCodecGetCodecInfo |
// Your component receives the ImageCodecGetCodecInfo request whenever an application calls the Image Compression Manager's GetCodecInfo |
// function. Your component should return a formatted compressor information structure defining its capabilities. |
// Both compressors and decompressors may receive this request. |
pascal ComponentResult OpenGLCodec_GetCodecInfo(OpenGLCodecGlobals glob, CodecInfo *info) |
{ |
if (!info) return paramErr; |
c2pstrcpy((unsigned char *)info->typeName,"OpenGL Output Codec"); |
info->version = 0x0001; |
info->revisionLevel = 0x0001; |
info->vendor = 'dts '; |
info->decompressFlags = codecInfoDoes32 | |
codecInfoDoes16 | |
codecInfoDoesStretch | |
codecInfoDoesDouble | |
codecInfoDoesMask | |
codecInfoDoesQuad; // component flags |
info->compressFlags = 0, |
info->formatFlags = codecInfoDepth16|codecInfoDepth32 | codecInfoDoesLossless; |
info->compressionAccuracy = 100; |
info->decompressionAccuracy = 100; |
info->compressionSpeed = 1; |
info->decompressionSpeed = 1; |
info->compressionLevel = 0; |
info->resvd = 0; |
info->minimumHeight = 2; |
info->minimumWidth = 2; |
info->decompressPipelineLatency = 0; |
info->compressPipelineLatency = 0; |
info->privateData = 0; |
return noErr; |
} |
// ImageCodecNewImageGWorld |
pascal ComponentResult OpenGLCodec_NewImageGWorld(OpenGLCodecGlobals glob, CodecDecompressParams *p, GWorldPtr *newGW, long flags) |
{ |
#pragma unused(glob, flags) |
PixMapPtr portPixMap; |
Rect voutRect; |
long pixMapType; |
long pixelType; |
OSErr err = codecConditionErr; |
// Make sure the destination port is of the type we expect. This is done by checking |
// the pixelFormat of the destination image. If the pixel format isn't ours, |
// (kOpenGLPixelFormat) it is a bogus usage of the transfer codec. |
portPixMap = *(GetPortPixMap(p->port)); |
pixMapType = GETPIXMAPPIXELFORMAT(portPixMap); |
if (pixMapType == kOpenGLPixelFormat) { |
/* We know that our special pixel format really just points to the |
layer object for this codec. */ |
id owner = (id)portPixMap->baseAddr; |
voutRect.top = voutRect.left = 0; |
voutRect.right = p->srcRect.right - p->srcRect.left; |
voutRect.bottom = p->srcRect.bottom - p->srcRect.top; |
if(glob->codecType == 'oglr') |
{ |
glob->imageBufferRowBytes = (voutRect.right * 4 + 31) & ~31; |
pixelType = glob->codecType; |
} |
else |
{ |
glob->imageBufferRowBytes = (voutRect.right * 2 + 31) & ~31; |
pixelType = glob->codecType; |
} |
glob->imageBuffer = malloc(glob->imageBufferRowBytes * voutRect.bottom); |
glob->owner = owner; |
err = QTNewGWorldFromPtr(newGW, |
pixelType, //glob->codecType, |
&voutRect, |
NULL, |
NULL, |
0, |
glob->imageBuffer, |
glob->imageBufferRowBytes); |
[owner setColorFormat:glob->codecType |
colorWidth:voutRect.right |
colorHeight:voutRect.bottom |
colorData:glob->imageBuffer |
colorRowBytes:glob->imageBufferRowBytes]; |
} |
return err; |
} |
// ImageCodecDisposeImageGWorld |
pascal ComponentResult OpenGLCodec_DisposeImageGWorld(OpenGLCodecGlobals glob, GWorldPtr theGW) |
{ |
#pragma unused(glob) |
DisposeGWorld(theGW); |
return noErr; |
} |
pascal ComponentResult |
OpenGLCodec_LockBits(OpenGLCodecGlobals storage, CGrafPtr port) |
{ |
[storage->owner lockBits]; |
return noErr; |
} |
pascal ComponentResult |
OpenGLCodec_UnlockBits(OpenGLCodecGlobals storage, CGrafPtr port) |
{ |
[storage->owner unlockBits]; |
return noErr; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-04-21