< Previous PageNext Page > Hide TOC

Using Image Compressor Components

This chapter shows you how to use compressors and decompressors in conjunction with the Image Compression Manager.

In this section:

Performing Image Compression
Decompressing an Image
Asynchronous Decompression
Hardware Cursors
Timecode Support
Working With Video Fields
Accelerated Video Support
Packetization Information
DV Image Compressor Component
DV Image Decompressor Component
Specifying the Size of an Image Buffer


Performing Image Compression

This section describes what the Image Compression Manager does that affects compressors. It then provides sample code that shows how the compressor components prepare for image compression and how to compress an entire image or a horizontal band of an image.

When compressing an image, the Image Compression Manager performs three major tasks:

Choosing a Compressor

Listing 9-1 shows how the Image Compression Manager calls the ImageCodecPreCompress function before an image is compressed. The compressor component returns information about how it is able to compress the image to the Image Compression Manager, so that it can fit the destination data to the requirements of the compressor component. This information includes compressor capabilities for

When your compressor component is called with the ImageCodecPreCompress function, it can handle all aspects of the function itself, or only the most common ones. All image compressor components must handle at least one case.

Listing 9-1  Preparing for simple compression operations

pascal long ImageCodecPreCompress (Handle storage,
                                    register CodecCompressParams *p) 
{
    CodecCapabilities *capabilities = p->capabilities;
/*
    First the compressor returns which depth input pixels it
    supports based on what the application has available. This
    compressor can only work with 32-bit input pixels.
*/  
    switch ( (*p->imageDescription)->depth ) {
        case 16:
            capabilities->wantedPixelSize = 32;
            break;
        default:
            return(codecConditionErr);
            break;
    }
 
    /*
        If the buffer gets banded, return the smallest one the
        compressor can handle.
    */  
    capabilities->bandMin = 2;
 
    /*
        If the buffer gets banded, return the increment
        by which it should increase.
    */
    capabilities->bandInc = 2;
        
    capabilities->extendWidth = (*p->imageDescription)->width & 1;
    capabilities->extendHeight = (*p->imageDescription)->height & 1;
    /*
        For efficiency, if the compressor could perform extension,
        these flags would be set to 0.
    */
    return(noErr);
}

Here is a list of some of the operations your compressor component can perform during compression. It describes parameters in the compression parameters structure and indicates the operations that are required and which flags in the compressor capabilities flags field of the compressor capabilities structure must be set to allow your compressor to handle them (see Data Structures and Data Structures).

Compressing a Horizontal Band of an Image

Listing 9-2 shows how the Image Compression Manager calls the ImageCodecBandCompress function when it wants the compressor to compress a horizontal band of an image.

Note:  This example does not perform compression on bands with a bit depth of more than 1 or an extension of width and height. If the example did do so, it would handle these cases faster.

Listing 9-2  Performing simple compression on a horizontal band of an image

pascal long ImageCodecBandCompress (Handle storage,
                                  register CodecCompressParams *p) 
{
    short                   width,height;
    Ptr                     cDataPtr,dataStart;
    short                   depth;
    Rect                    sRect;
    long                    offsetH,offsetV;
    Globals                 **glob = (Globals **)storage;
    register char           *baseAddr;
    long                    numLines,numStrips;
    short                   rowBytes;
    long                    stripBytes;
    char                    mmuMode = 1;
    register short          y;
    ImageDescription        **desc = p->imageDescription;
    OSErr                   result = noErr;
    
    /*
    If there is a progress function, give it an open call at
        the start of this band.
    */
 
    if (p->progressProcRecord.progressProc)
        p->progressProcRecord.progressProc (codecProgressOpen, 0,
            p->progressProcRecord.progressRefCon);
    width = (*desc)->width;
    height = (*desc)->height;
    depth = (*desc)->depth;
    dataStart = cDataPtr = p->data;
    /*
        Figure out offset to first pixel in baseAddr from the
        pixel size and bounds.
     */
    rowBytes = p->srcPixMap.rowBytes;
    sRect = p->srcPixMap.bounds;
 
    numLines = p->stopLine - p->startLine; /* number of scan lines */
    numStrips = (numLines+1)>>1;           /* number of strips in */
    stripBytes = ((width+1)>>1) * 5;
    
    /*
        Adjust the source baseAddress to be at the beginning
        of the desired rect.
    */
    switch ( p->srcPixMap.pixelSize ) {
    case 32:
        offsetH = sRect.left<<2;
        break;
    case 16:
        offsetH = sRect.left<<1;
        break;
    case 8:
        offsetH = sRect.left;
        break;
    /*
        This compressor does not handle the other cases directly.
    */
    default:
        result = codecErr;
        goto bail;
    }
    offsetV = sRect.top * rowBytes;
    baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV;
    /*
        If there is not a data-unloading function,
        adjust the pointer to the next band.
    */
    
    if ( p->flushProcRecord.flushProc == nil ) {
        cDataPtr += (p->startLine>>1) * stripBytes;
    }
    else { /*
                 Make sure the compressor can deal with the
                 data-unloading function in this case.
            */
        if ( p->bufferSize < stripBytes ) {
            result = codecSpoolErr;
            goto bail;
        }
    }
    /*
        Perform the slower data-loading or progress operation, as
        required.
    */
    
    if ( p->flushProcRecord.flushProc ||
        p->progressProcRecord.progressProc ) {
        SharedGlobals *sg = (*glob)->sharedGlob;
        for ( y=0; y < numStrips; y++) {
            SwapMMUMode(&mmuMode);
            CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
            SwapMMUMode(&mmuMode);
            baseAddr += rowBytes<<1;
            if ( p->flushProcRecord.flushProc ) {
                if ( (result=
            p->flushProcRecord.flushProc(cDataPtr,stripBytes,
            p->flushProcRecord.flushRefCon)) != noErr) {
                    result = codecSpoolErr;
                    goto bail;
                }
            } else {
                cDataPtr += stripBytes;
            }
            if (p->progressProcRecord.progressProc) {
                if ( (result=
                    p->progressProcRecord.progressProc)
                        codecProgressUpdatePercent,
                        FixDiv(y,numStrips),
                        p->progressProcRecord.progressRefCon)
                )   != noErr ) {
                    result = codecAbortErr;
                    goto bail;
                }
            }
        }
    } else {
        SharedGlobals *sg = (*glob)->sharedGlob;
        short tRowBytes = rowBytes<<1;
        SwapMMUMode(&mmuMode);
        for ( y=numStrips; y--; ) {
            CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
            cDataPtr += stripBytes;
            baseAddr += tRowBytes;
        }
        SwapMMUMode(&mmuMode);
    }
}

Decompressing an Image

When decompressing an image, the Image Compression Manager performs these three major tasks:

Choosing a Decompressor

Listing 9-3 provides an example of how a decompressor is chosen. The Image Compression Manager calls the ImageCodecPreDecompress function before an image is decompressed. The decompressor returns information about how it can decompress an image. The Image Compression Manager can fit the destination pixel map to your decompressor’s requirements if it is not able to support decompression to the destination directly. The capability information the decompressor returns includes

When your decompressor component is called with the ImageCodecPreDecompress function, it can handle all aspects of the call itself, or only the most common ones. All decompressors must handle at least one case.

Listing 9-3  Preparing for simple decompression

pascal long ImageCodecPreDecompress( Handle storage,
                                 register CodecDecompressParams *p)
{
    register CodecCapabilities*capabilities = p->capabilities;
    RectdRect = p->srcRect;
    
    /*  
        Check if the matrix is OK for this decompressor.
        This decompressor doesn't do anything fancy.
    */
    
    if ( !TransformRect(p->matrix,&dRect,nil) )
        return(codecConditionErr);
    /*  
        Decide which depth compressed data this decompressor can
        deal with.
    */
    
    switch ( (*p->imageDescription)->depth ) {
        case 16:
            break;
        default:
            return(codecConditionErr);
            break;
    }
        /*
            This decompressor can deal only with 32-bit pixels.
        */
    capabilities->wantedPixelSize = 32;
    
    /*
        The smallest possible band the decompressor can handle is
        2 scan lines.
    */
    
    capabilities->bandMin = 2;
    /* This decompressor can deal with 2 scan line high bands. */
    capabilities->bandInc = 2;
    
    /*
        If this decompressor needed its pixels be aligned on
        some integer multiple, you would set extendWidth and
        extendHeight to the number of pixels by which you need the
        destination extended. If you don't have such requirements
        or if you take care of them yourself, you set extendWidth
        and extendHeight to 0.
    */
    capabilities->extendWidth = p->srcRect.right & 1;
    capabilities->extendHeight = p->srcRect.bottom & 1;
    
    return(noErr);
}

Decompressor Operations

This section contains a bulleted list of some of the operations your decompressor component can perform during the decompression operation. The list describes which parameters in the decompression parameters structure indicate that the operations are required and which flags in the flags field of the compressor capabilities structure must be set to allow your decompressor to handle them (see Data Structures).

For sequences of images the conditionFlags field in the decompression parameters structure can be used to determine which parameters may have changed since the last decompression operation. These parameters are also indicated in the bulleted list.

Since your decompressor’s capabilities depend on the full combination of parameters, it must inspect all the relevant parameters before indicating that it will perform one of the operations itself. For instance, if your decompressor has hardware that can perform scaling only if the destination pixel depth is 32 and there is no clipping, then the pre-decompression operation would have to check the following fields in the decompression parameters structure: the matrix field, the pixelSize field of the destination pixel map structure pointed to by the destPixMap field, and the maskBits fields. Only then could the decompressor decide whether to set the codecCanScale flag in the capabilities field of the decompression parameters structure.

Decompressing a Horizontal Band of an Image

Listing 9-4 shows how to decompress the horizontal band of an image. The Image Compression Manager calls the ImageCodecBandDecompress function when it wants a decompressor to decompress an image or a horizontal band of an image. The pixel data indicated by the baseAddr field is guaranteed to conform to the criteria your decompressor specified in the ImageCodecPreDecompress function.

Note:  This example does not perform decompression on bands with a bit depth of more than one or an extension of width and height. If the example did do so, it would handle these cases faster.

Listing 9-4  Performing a decompression operation

pascal long ImageCodecBandDecompress( Handle storage,
                               register CodecDecompressParams *p) 
{
    Rect                dRect;
    long                offsetH,offsetV;
    Globals             **glob = (Globals **)storage;
    long                numLines,numStrips;
    short               rowBytes;
    long                stripBytes;
    short               width;
    register short      y;
    register char*      baseAddr;
    char                *cDataPtr;
    char                mmuMode = 1;
    OSErr               result = noErr;
 
    /*
        Calculate the real base address based on the boundary
        rectangle. If it's not a linear transformation, this
        decompressor does not perform the operation.
    */
    dRect = p->srcRect;
    if ( !TransformRect(p->matrix,&dRect,nil) )
        return(paramErr);
    /*  If there is a progress function, give it an open call at
        the start of this band.
    */
    if (p->progressProcRecord.progressProc)
        p->progressProcRecord.progressProc(codecProgressOpen,0,
            p->progressProcRecord.progressRefCon);
    
    /*
        Initialize some local variables.
    */
    
    width = (*p->imageDescription)->width;
    rowBytes = p->dstPixMap.rowBytes;
    numLines = p->stopLine - p->startLine; /* number of scan lines
                                              in this band */
    numStrips = (numLines+1)>>1;           /* number of strips in
                                              this band */ 
    stripBytes = ((width+1)>>1) * 5;       /* number of bytes in
                                              1 strip of blocks */  
    cDataPtr = p->data;
    
    /*
        Adjust the destination base address to be at the beginning
        of the desired rectangle.
    */
    
    offsetH = (dRect.left - p->dstPixMap.bounds.left);
    switch ( p->dstPixMap.pixelSize ) {
        case 32:
            offsetH <<=2;       /* 1 pixel = 4 bytes */
            break;
        case 16:
            offsetH <<=1;       /* 1 pixel = 2 bytes */
            break;
        case 8:                          
            break;              /* 1 pixel = 1 byte */
        default:
            result = codecErr;  /* This decompressor doesn't handle
                                 these cases, although it could. */ 
        goto bail;
    }
    offsetV = (dRect.top - p->dstPixMap.bounds.top) * rowBytes;
    baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
 
    /*
        If your decompressor component is skipping some data,
        it just skips it here. You can tell because
        firstBandInFrame indicates this is the first band for a new
        frame, and if startLine is not 0, then that many lines were
        clipped out.
     */
    if ( (p->conditionFlags & codecConditionFirstBand) &&
            p->startLine != 0 ) {
        if ( p->dataProcRecord.dataProc ) {
            for ( y=0; y < p->startLine>>1; y++ ) {
                if ( (result=p->dataProcRecord.dataProc
                         (&cDataPtr,stripBytes,
                        p->dataProcRecord.dataRefCon)) != noErr ) {
                    result = codecSpoolErr;
                    goto bail;
                }
                cDataPtr += stripBytes;
            }
        } else
            cDataPtr += (p->startLine>>1) * stripBytes;
    }
    /*
        If there is a data-loading function spooling the data to your
        decompressor, then you have to decompress the data in the
        chunk size that is specified, or, if there is a progress
        function, you must make sure to call it as you go along.
    */
 
    if ( p->dataProcRecord.dataProc ||
         p->progressProcRecord.progressProc ) {
        SharedGlobals *sg = (*glob)->sharedGlob;
    
        for (y=0; y < numStrips; y++) {
            if (p->dataProcRecord.dataProc) {
                if ( (result=p->dataProcRecord.dataProc
                         (&cDataPtr,stripBytes,
                        p->dataProcRecord.dataRefCon)) != noErr ) {
                    result = codecSpoolErr;
                    goto bail;
                }
            }
            SwapMMUMode(&mmuMode);
            DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
            SwapMMUMode(&mmuMode);
            baseAddr += rowBytes<<1;
            cDataPtr += stripBytes;
 
            if (p->progressProcRecord.progressProc) {
                if ( (result=p->progressProcRecord.progressProc
                        (codecProgressUpdatePercent,
                    FixDiv(y, numStrips),
                    p->progressProcRecord.progressRefCon)) != noErr ) {
                    result = codecAbortErr;
                     goto bail;
                }
            }
        }
    
/*
    Otherwise, do the fast case.
*/
    } else {
        SharedGlobals *sg = (*glob)->sharedGlob;
        shorttRowBytes = rowBytes<<1;
 
        SwapMMUMode(&mmuMode);
        for ( y=numStrips; y--; ) {
            DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
            baseAddr += tRowBytes;
            cDataPtr += stripBytes;
        }
        SwapMMUMode(&mmuMode);
    }
/*
    IMPORTANT: Update the pointer to data in the decompression
    parameters structure, so that when your decompressor gets the
    next band, you'll be at the right place in your data.
*/
    p->data = cDataPtr;
    
    if ( p->conditionFlags & codecConditionLastBand ) {
        /*
            Tie up any loose ends on the last band of the frame.
        */
    }
bail:
    /*
        If there is a progress function, give it a close call
        at the end of this band.
    */
    if (p->progressProcRecord.progressProc)
        p->progressProcRecord.progressProc(codecProgressClose,0,
            p->progressProcRecord.progressRefCon);
    return(result);
}

Asynchronous Decompression

The Image Compression Manager (ICM) supports scheduled asynchronous decompression operations. By calling the Image Compression Manager function DecompressSequenceFrameWhen, applications can schedule decompression requests in advance. This allows decompressor components that support this functionality to provide reliable playback performance under a wider range of conditions.

The Apple Cinepak, Video, Animation, Component Video, and Graphics decompressors provided in QuickTime support scheduled asynchronous decompression to 8-, 16-, and 32-bit destinations (the Cinepak decompressor also supports 4-bit grayscale destinations). QuickTime also adds asynchronous decompression support to the JPEG and None decompressor components on PowerPC systems (with the QuickTime PowerPlug extension installed).

If you want to support this functionality, you must modify your decompressor component in the following ways:

Hardware Cursors

The Image Compression Manager supports hardware cursors introduced in PCI-based Macintosh computers, which eliminates cursor flicker. For all software codecs, this support requires no changes.

For codecs that manage the cursor themselves, QuickTime has a flag, codecCompletionDontUnshield, for use when calling the ICMDecompressComplete function. Use this flag to prevent the Image Compression Manager from unshielding the cursor when ICMDecompressComplete is called.

Timecode Support

QuickTime provides timecode information to decompressor components when movies are played. To support timecodes, your codec must support the function ImageCodecSetTimeCode, which allows the Image Compression Manager to set the timecode value for the next frame to be decompressed.

Working With Video Fields

The functionality of the ImageFieldSequenceExtractCombine function is performed by individual image codecs. This is because the way in which fields are stored is different for every compression format. A codec component function, ImageCodecExtractAndCombineFields, is defined for this purpose. Apple encourages developers of codecs to incorporate this function, if their compressed data format is capable of separately storing both fields of a video frame.

Accelerated Video Support

QuickTime supports codecs that accelerate certain image decompression operations. These features are most likely used by developers of video hardware boards that provide special acceleration features, such as arbitrary scaling or color space conversion.

If a codec cannot decompress directly to the screen it has the option of specifying that it can decompress to one or more types of non-RGB pixel spaces, specified as an OSType (e.g., 'yuvs'). The ICM then attempts to find a decompressor component of that type (a transfer codec) that can transfer the image to the screen. Since the ICM does not define non-RGB pixel types, the transfer codec must support additional calls to set up the offscreen. If a transfer codec cannot be found that supports the specified non-RGB pixel types, the ICM uses the None codec with an RGB offscreen buffer.

The real speed benefit comes from the fact that since the transfer codec defines the offscreen buffer, it can place the buffer in on-board memory, or even point to an overlay plane so that the offscreen image really is on the screen. In this case, the additional step of transferring the bits from offscreen memory on to the screen is avoided.

For an image decompressor component to indicate that it can decompress to non-RGB pixel types, it should, in the ImageCodecPreDecompress call, fill in the wantedDestinationPixelTypes field with a handle to a zero-terminated list of pixel types that it can decompress to. The ICM immediately makes a copy of the handle. Cinepak, for example, returns a 12-byte handle containing yuvs, yuvu, and $00000000. Since ImageCodecPreDecompress can be called often, it is suggested that codecs allocate this handle when their component is opened and simply fill in the wantedDestinationPixelTypes field with this handle during ImageCodecPreDecompress. Components that use this method should be sure to dispose the handle at close.

Apple’s Cinepak decompressor supports decompressing to 'yuvs' and 'yuvu' pixel types. Type 'yuvs' is a YUV format with u and v components signed (center point at $00), while 'yuvu' has the u and v component centered at $80.

As an example, suppose XYZ Co. had a video board that had a YUV overlay plane capable of doing arbitrary scaling. The overlay plane takes data in the same format as Cinepak’s 'yuvs' format. In this case, XYZ would make a component of type 'imdc' and subtype 'yuvs'.

The ImageCodecPreDecompress call would set the codecCanScale, codecHasVolatileBuffer, and codecImageBufferIsOnScreen bits in the capabilities flags field. The codecImageBufferIsOnScreen bit is necessary to inform the ICM that the codec is a direct screen transfer codec. A direct screen transfer codec is one that sets up an offscreen buffer that is actually onscreen (such as an overlay plane). Not setting this bit correctly can cause unpredictable results.

The real work of the codec takes place in the ImageCodecNewImageBufferMemory call. This is where the codec is instructed to prepare the non-RGB pixel buffer. The codec must fill in the baseAddr and rowBytes fields of the dstPixMap structure in CodecDecompressParams. The ICM then passes these values to the original codec (e.g., Cinepak) to decompress into.

The codec must also implement ImageCodecDisposeMemory to balance ImageCodecNewImageBufferMemory.

Since Cinepak then decompresses into the card’s overlay plane, ImageCodecBandDecompress needs to do nothing aside from calling ICMDecompressComplete.

pascal ComponentResult
ImageCodecPreDecompress(Handle storage,
        CodecDecompressParams *p)
{
    CodecCapabilities   *capabilities = p->capabilities;
    // only allow 16 bpp source
    if ((**p->imageDescription).depth != 16)
        return codecConditionErr;
    /* we only support 16 bits per pixel dest */
    if (p->dstPixMap.pixelSize != 16)
        return codecConditionErr;
 
    capabilities->wantedPixelSize = p->dstPixMap.pixelSize;
 
    capabilities->bandInc = capabilities->bandMin =
                (*p->imageDescription)->height;
 
    capabilities->extendWidth = 0;
    capabilities->extendHeight = 0;
 
    capabilities->flags =
            codecCanScale | codecImageBufferIsOnScreen |
            codecHasVolatileBuffer;
 
    return noErr;
}
 
pascal ComponentResult
 
ImageCodecBandDecompress(Handle storage,
        CodecDecompressParams *p)
{
    ICMDecompressComplete(p->sequenceID, noErr,
                codecCompletionSource | codecCompletionDest,
                &p->completionProcRecord);
 
    return noErr;
}
 
pascal ComponentResult
ImageCodecNewImageBufferMemory(Handle storage,
        CodecDecompressParams *p, long flags,
        ICMMemoryDisposedUPP memoryGoneProc,
        void *refCon)
{
    OSErr err = noErr;
    long offsetH, offsetV;
    Ptr baseAddr;
    long rowBytes;
 
    // call predecompress to check to make sure we can handle
    // this destination
    err = ImageCodecPreDecompress(storage, p);
    if (err) goto bail;
 
    // set video board registers with the scale
    XYZVideoSetScale(p->matrix);
 
    // calculate a base address to write to
    offsetH = (p->dstRect.left - p->dstPixMap.bounds.left);
    offsetV = (p->dstRect.top - p->dstPixMap.bounds.top);
    XYZVideoGetBaseAddress(p->dstPixMap, offsetH, offsetV,
                &baseAddr, &rowBytes);
 
    p->dstPixMap.baseAddr = baseAddr;
    p->dstPixMap.rowBytes = rowBytes;
    p->capabilities->flags = codecImageBufferIsOnScreen;
bail:
    return err;
}
 
pascal ComponentResult
ImageCodecDisposeMemory(Handle storage, Ptr data)
{
    return noErr;
}

Some video hardware boards that use an overlay plane require that the image area on screen be flooded with a particular RGB value or alpha-channel in order to have the overlay buffer “show through” at that location. Codecs that require this support should set the screenFloodMethod and screenFloodValue fields of the CodecDecompressParams record during ImageCodecPreDecompress. The ICM then manages the flooding of the screen buffer. This method is more reliable than having the codec attempt to flood the screen itself, and will ensure compatibility with future versions of QuickTime.

Packetization Information

QuickTime functions support packetizing compressed data streams, primarily for video conferencing applications. For this purpose, the field preferredPacketSizeInBytes was added to the compression parameters structure. Codec developers need only use this field.

Packet information is appended, word-aligned, to the end of video data. It is a variable-length array of 4-byte integers, each representing the offset in bits of the end of a packet, followed by another integer containing the number of packet hints, and finally a four-byte identifier indicating the type of appended data:

[boundary #1][boundary #2]...[boundary #N][N]['pkts']

Packets are given in bits, because some types of compressed image data (such as H.261) are cut up on bit-boundaries rather than byte-boundaries.

// given:  image data, length, and a packet number
// returns: a pointer to the start of the packet and a packet size, plus
// information about leading and trailing bits
 
char* GetNextPacket(char* data, int len, int packet, long* packet_size,
    char* leading_bits, char* trailing_bits)
{
    long *lp, packets;
    lp = (long*) data;  // 'data' must be word-aligned
    lp += len/4 - 1;
    if (*lp != 'pkts')
        return nil;
    
    packets = *lp[ -1 ];          // negative indexing is good for you
    if (packet >= packets)
        return nil;             // out of bounds
    lp -= packets;      // now 0-indexing into the packet array will work
    if (packet == 0)
    {
        *packet_size = (lp[0] + 7)/8;   // count the bits
        *leading_bits = 0;
        *trailing_bits = lp[0] % 8;
        return data;                    // in case of 0-length packet 
    }
    else
    {
        *packet_size = ( lp[pktnum] - lp[pktnum-1] + 7) / 8;
        *leading_bits = lp[packet-1] % 8 ? 8 - lp[packet-1] % 8 : 0;
        *trailing_bits = lp[packet] % 8;
        return data + lp[packet-1] / 8;
    }
}

Note that this technique can be used for further extensions by the addition of further appended formats. The last two words are always the number of words and an extension identifier.

DV Image Compressor Component

The DV image compressor component makes it possible to compress QuickTime video data into DV format. It is invoked automatically by the Image Compression Manager when an application requests output of type kDVCNTSCCodecType for NTSC DV data or kDVCPALCodecType for PAL DV data.

When creating NTSC video, the DV image compressor component generates 720 X 480 frames. When creating PAL video, it generates 720 X 576 frames.

Note:  Many DV devices use IEEE 1394 (FireWire) serial connections for input/output operations. QuickTime supports compression and decompression of DV data, but it does not include support for FireWire communication. You need additional software to communicate with DV devices.

DV Image Decompressor Component

The DV image decompressor component makes it possible to decompress DV video data. It is invoked automatically by the Image Compression Manager when an application specifies input of type kDVCNTSCCodecType for NTSC DV data or kDVCPALCodecType for PAL DV data.

There are two quality modes for DV decompression:

When a computer includes a video display adapter that performs YUV decompression in hardware, the DV image decompressor can use a YUV decompressor component written to use the hardware decompression capabilities in place of the software YUV decompressor in QuickTime, resulting in even higher performance.

Specifying the Size of an Image Buffer

You can specify the size of the image buffer used by your image compressor or decompressor component. When your component calls the ImageCodecPreDecompress or ImageCodecPreCompress function, you can specify the size of the buffer as follows:

This is illustrated in Listing 9-5.

Listing 9-5  Specifying the size of an image buffer for a codec

p->capabilities->flags |= codecWantsSpecialScaling;
p->requestedBufferWidth = 720;
p->requestedBufferHeight = 480;


< Previous PageNext Page > Hide TOC


© 2005, 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-01-10)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.