Compaq Multimedia Services
for OpenVMS Alpha
Programmer's Guide


Previous Contents Index


Chapter 5
Video Compression and Decompression Services

This chapter presents an overview of video compression and decompression devices and the video compression and decompression (VCD) services available to applications. Applications use these services to compress and decompress video data stored in AVI files.

5.1 Video Compression and Decompression Services Overview

The video compression and decompression library provides low-level video compression and decompression services to applications through the Installable Compression Manager (ICM) described in Section 5.1.2. Even though compression and decompression devices are often referred to as separate entities, usually a single device provides both functions. Applications use these services to control the compression and decompression of video data.

The video compression and decompression library provides the following services:

5.1.1 Video Compression and Decompression Architecture Overview

Figure 5-1 shows the architecture of a video compression operation.

Figure 5-1 Architecture of a Video Compression Operation


In Figure 5-1:

Figure 5-2 shows the architecture of a video decompression operation.

Figure 5-2 Architecture of a Video Decompression Operation


In Figure 5-2:

5.1.2 Installable Compression Manager

Video compression and decompression services are provided to applications by the Installable Compression Manager (ICM). ICM is the intermediary between an application and the actual video compression and decompression devices. It is the video compression and decompression devices that compress and decompress individual frames of data.

As an application makes calls to the ICM to compress or decompress data, the ICM translates this to a message to be sent to the appropriate compression or decompression device. The ICM receives the return from the device and then returns it to the calling application.

In general, an application does the following to compress or decompress video data:

These tasks are covered in Section 5.2.

5.1.3 Streaming Video Compression/Decompression Interface

The standard ICCompress and ICDecompress functions are blocking functions in that the application must wait for the operation to complete before the functions return. This prevents the application from processing other tasks concurrently. If the compressor or decompressor is a hardware device, then the device might be processing the next frame while the application processes other data such as audio data.

To allow better response time, Compaq has extended the standard ICCompress and ICDecompress functions by supporting a streaming interface. The application may choose to register a callback function which will be called by the compressor or decompressor when the operation has completed. The ICCompress or ICDecompress function will register all the information needed with the compressor or decompressor and then return, leaving the device to complete the operation concurrently while returning control to the application. When the operation has completed, the callback function will be executed to return the required information and data to the application.

Another advantage of this method is to take full advantage of the processing power of some hardware solutions. If the hardware device can operate almost independently of the host machine, then the hardware device might be able to begin processing the next frame as the application is being notified of the completion of the previous frame, allowing the operations to be efficiently pipelined to the hardware with no interruption from the application, as long as the application can provide the next operation and buffers to the hardware device (through ICCompress or ICDecompress ) before the hardware runs out of work to do.

In addition, since the analog video capture and playback interfaces provide streaming interfaces and since many hardware solutions combine analog video capture and playback as well as compression and decompression, streaming video compression and decompression allows both types of applications to share the hardware resource more efficiently.

For example, assume there are two applications, an analog video capture application and a video decompression application. The analog video capture application uses 3 streaming buffers and the video decompression application uses the blocking ICDecompress interface (no callbacks).

By using streaming for both applications, the decompression application would run at least as fast as the capture application (provided hardware could handle decompression at 30 frames per second) and if the hardware could decompress more than 30 frames per second, then streaming would allow for the possibility of a 30 frame per second capture application running concurrently with multiple 30 frame per second decompression applications.

5.2 Using Video Compression and Decompression Services

Video compression and decompression services control video compressors and decompressors. This section presents information about using the video compression and decompression services.

5.2.1 Locating and Opening Video Compressors and Decompressors

To use ICM, an application must open a video compressor or decompressor. If an application does not know about the compressors or decompressors installed on a system, it must find a suitable compressor to open by calling the ICInfo function to list them.

An application can use the ICLocate function to locate a compressor or decompressor of a specific type. A handle to the open compressor or decompressor is returned to the application for use in other ICM functions.

If an application knows the compressor or decompressor it needs, it can open the compressor or decompressor with the ICOpen function. An application uses the handle returned by the function to identify the opened compressor or decompressor when it calls other ICM functions.

Once an application finishes with a compressor or decompressor, it closes it by calling the ICClose function to free any resources used for compression or decompression.

Example 5-1 shows how to locate a decompressor that can decompress JPEG-formatted video data.

Example 5-1 Locating a Decompressor That Decompresses JPEG Format

*/ 
 
#include <stdio.h> 
#include <mme/mme_api.h> 
 
void ListVCDs() 
{ 
    ICINFO            * icinfo; 
    BITMAPINFOHEADER  * lpbi; 
    EXBMINFOHEADER    * exbi; 
    JPEGINFOHEADER    * jpegbi; 
    int               i; 
    DWORD             fccType; 
    HIC               hic; 
 
    icinfo = (ICINFO *)mmeAllocMem(sizeof(ICINFO)); 
    if ( icinfo == (ICINFO *)NULL ) { 
        fprintf(stderr,"Cannot allocate memory\n"); 
        fprintf(stderr,"Perhaps the mmeserver is not running\n"); 
        return; 
    } 
 
    /* Allocate enough memory for the extended JPEG bitmap 
    ** info header 
    */ 
    lpbi = (BITMAPINFOHEADER *)mmeAllocMem( 
         sizeof(EXBMINFOHEADER) + sizeof(JPEGINFOHEADER)); 
    if ( lpbi == (BITMAPINFOHEADER *)NULL )  { 
        mmeFreeMem(icinfo); 
        fprintf(stderr,"Cannot allocate memory\n"); 
        return; 
    } 
 
    /* Size is always set to reflect the entire structure size */ 
    lpbi->biSize = sizeof(EXBMINFOHEADER) + sizeof(JPEGINFOHEADER); 
 
    /* Set the compression for Still JPEG */ 
    lpbi->biCompression  = JPEG_DIB; 
 
    /* Bit count for JPEG or MJPG is 24 */ 
    lpbi->biBitCount     = 24; 
 
    /* Set other fields to standard values */ 
    lpbi->biWidth   = 320; 
    lpbi->biHeight   = 240; 
    lpbi->biPlanes   = 1; 
    lpbi->biXPelsPerMeter  = 0; 
    lpbi->biYPelsPerMeter  = 0; 
    lpbi->biClrUsed   = 0; 
    lpbi->biClrImportant  = 0; 
 
    /* Set up the extended bitmap info header properly. 
    ** The ExtDataOffset should point to the location in memory 
    ** just beyond the extended bitmap info header where we will 
    ** place the JPEG bitmap info header 
    */ 
    exbi = (EXBMINFOHEADER *)lpbi; 
    exbi->biExtDataOffset = sizeof(EXBMINFOHEADER); 
 
    /* Set up the JPEG bitmap info header. 
    ** We'll specify 
    **   baseline DCT as the process, 
    **   YCbCr colorspace, 
    **   bits per sample is always 8 for baseline DCT, 
    **   vertical subsampling at 1:1 and 
    **   horizontal subsampling at 1:2 
    ** The JPEGSize should match the size of the JPEG bitmap 
    ** info header we are using. 
    */ 
    jpegbi = (JPEGINFOHEADER *) 
         ((unsigned long)exbi + exbi->biExtDataOffset); 
    jpegbi->JPEGSize          = sizeof(JPEGINFOHEADER); 
    jpegbi->JPEGProcess       = JPEG_PROCESS_BASELINE; 
    jpegbi->JPEGColorSpaceID  = JPEG_YCbCr; 
    jpegbi->JPEGBitsPerSample = 8; 
    jpegbi->JPEGHSubSampling  = JPEG_SUBSAMPLING_2; 
    jpegbi->JPEGVSubSampling  = JPEG_SUBSAMPLING_1; 
 
    fccType = ICTYPE_VIDEO; 
    for ( i = 1; ICInfo(fccType, i, icinfo); i++ ) { 
        hic = ICOpen(icinfo->fccType, icinfo->fccHandler, 
              ICMODE_QUERY); 
        if ( hic ) { 
            if ( ICDecompressQuery(hic, lpbi, NULL) == ICERR_OK ) 
                printf("Device %s supports JPEG\n", icinfo->szName); 
            else 
                printf("Device %s does not support JPEG\n", 
                    icinfo->szName); 
            ICClose(hic); 
       } 
    } 
    mmeFreeMem(lpbi); 
    mmeFreeMem(icinfo); 
    return; 
} 
 
main() 
{ 
    ListVCDs(); 
} 

Example 5-2 shows how to find a compressor that can compress a YUV-formatted image.

Example 5-2 Locating a Compressor That Compresses YUV Image Format

#include <stdio.h> 
#include <mme/mme_api.h> 
 
ListVCDs() 
{ 
    BITMAPINFOHEADER  * lpbi; 
    HIC               hic; 
    ICINFO            * icinfo; 
 
    icinfo = (ICINFO *)mmeAllocMem(sizeof(ICINFO)); 
    if ( icinfo == (ICINFO *)NULL ) { 
        fprintf(stderr,"Cannot allocate memory\n"); 
        fprintf(stderr,"Perhaps the mmeserver is not running\n"); 
        return; 
    } 
 
    lpbi = (BITMAPINFOHEADER *)mmeAllocMem(sizeof(BITMAPINFOHEADER)); 
    if ( lpbi == (BITMAPINFOHEADER *)NULL )  { 
        mmeFreeMem(icinfo); 
        fprintf(stderr,"Cannot allocate memory\n"); 
        return; 
    } 
 
    bzero(lpbi, sizeof(BITMAPINFOHEADER)); 
    /* set the size to the size of the appropriate bitmap info header */ 
    lpbi->biSize         = sizeof(BITMAPINFOHEADER); 
 
    /* set the compression to YUV decompressed */ 
    lpbi->biCompression  = BICOMP_DECYUVDIB; 
 
    /* set the bit count to 16 for YUV decompressed */ 
    lpbi->biBitCount     = 16; 
 
    /* Pick some other values */ 
    lpbi->biWidth   = 320; 
    lpbi->biHeight   = 240; 
    lpbi->biPlanes   = 1; 
    lpbi->biXPelsPerMeter  = 0; 
    lpbi->biYPelsPerMeter  = 0; 
    lpbi->biClrUsed   = 0; 
    lpbi->biClrImportant  = 0; 
 
    /* Setting the handle to 0 implies any handler will do. 
    ** Setting the output bitmap info header to NULL implies 
    **     that any output format will do. 
    */ 
    hic = ICLocate ( ICTYPE_VIDEO, 0, lpbi, NULL, ICMODE_COMPRESS); 
 
    if ( hic ) { 
        ICGetInfo(hic, icinfo, sizeof(ICINFO)); 
        printf("Compressor %s supports 16 bit YUV\n",icinfo->szName); 
        ICClose(hic); 
    } else { 
        printf("No compressor supports 16 bit YUV\n"); 
    } 
    mmeFreeMem(icinfo); 
    mmeFreeMem(lpbi); 
    return; 
} 
main() 
{ 
    ListVCDs(); 
} 

5.2.2 Getting Information About Compressors and Decompressors

To obtain information about a compressor or decompressor, an application can use the ICGetInfo function. This functions fills an ICINFO data structure with information about the compressor or decompressor. See Section 5.4.1 for more information about the ICINFO data structure.

Note

Use the mmeAllocMem function to allocate memory for the ICINFO data structure before passing it to the ICGetInfo function. See Chapter 2 for more information.

5.2.3 Compressing Image Data

An application uses a series of functions to coordinate the compression of video data. Compressing video data involves the following activities:

The following sections describe these activities.

5.2.3.1 Specifying Input and Determining Compression Formats

When an application wants to compress video data and the output format is not important, it must first use the ICLocate or ICOpen function to find a compressor that can handle the input format. (See Section 5.2.1 for more information.) Then, the application can use the ICCompressGetFormat function to have the compressor suggest an output format. (Before using the ICCompressGetFormat function, the application can use the ICCompressGetFormatSize function to determine the size of the buffer in which the ICCompressGetFormat function returns the output format suggested by the compressor.)

If the compressor can produce multiple formats, it returns the format that preserves the greatest amount of information rather than the one that compresses to the most compact size. This outcome helps preserve the image quality if the video data is later edited and recompressed.

The application can use the output-format data as the stream format ( strf ) chunk in an AVI RIFF file. (See Chapter 8 for more information about AVI RIFF files.) This data contains information similar to a BITMAPINFOHEADER data structure. Then, the compressor can add information required to decompress the file. Lastly, a color table (if used) follows the information required to decompress the file.

If an application requires a specific output format, it can use the ICCompressQuery function to determine if a compressor can support the required format. If the compressor cannot support the required format, the application must find an alternate compressor. If alternate formats are acceptable, then the application can use the ICCompressQuery function with the alternate formats to determine if the compressor can handle them. The application can also use the ICCompressGetFormat function to have the compressor suggest the output format.

An application also needs the size of the data returned from the compressor after the compression is complete. Use the ICCompressGetSize function to obtain the largest buffer required by the compressor. Then, use the number of bytes returned to allocate the buffer used for subsequent compression of images.

Note

Use the mmeAllocBuffer function to allocate the buffer for compression.

5.2.3.2 Initializing the Compression Sequence

Once an application selects a compressor that handles the input and output formats required, it can prepare the compressor for compression. An application uses the ICCompressBegin function to initialize the compressor.

5.2.3.3 Compressing the Video

The ICCompress function actually compresses the data. An application must call the function repeatedly, once for each frame of data, until all frames are compressed.

5.2.3.4 Ending Compression

After an application has compressed its data, it uses the ICCompressEnd function to notify the compressor that the compression is complete. To restart compression after using this function, an application must call the ICCompressBegin function again to reinitialize the compressor.

5.2.4 Decompressing Image Data

An application uses a series of functions to control the decompression of video data. Decompressing video data involves the following activities:

The following sections describe these activities.

5.2.4.1 Specifying Input and Determining Decompression Formats

Decompression is handled similarly to compression except that the input format is compressed data and the output format is a displayable format. The input format for decompression is generally obtained from the video stream header ( strh ) chunk in an AVI RIFF file, or from an X image if an application wants to render a 24-bit true color X image or BI_BITFIELDS image to an 8-bit dithered X image.

After determining the input format, an application must use the ICLocate or ICOpen function to find a decompressor that can handle the format. (See Section 5.2.1 for more information.) Once a decompressor is selected, the application can use the ICDecompressGetFormatSize function to determine the maximum amount of memory the decompressor requires for the output format. If the application wants the decompressor to suggest an output format, it uses the ICDecompressGetFormat function to obtain the output format.

If an application requires a specific output format, it can use the ICDecompressQuery function to determine if the decompressor can handle both the input format and the required output format. This function can also be used to determine if the decompressor can handle the input format only.

5.2.4.2 Negotiating with the Driver for Palette Usage

If an application requires a BICOMP_DECXIMAGEDIB 8-bit output format, the application must specify the palette to use. Call the ICDecompressGetPalette function to specify the palette entries to use (or reuse if already allocated). The driver returns the palette it will use. If the palette is not acceptable, alter the request and call the ICDecompressGetPalette function again until an acceptable palette is returned. See Section 5.2.4.3 for more information.

If an application requires BICOMP_DECYUVDIB, BICOMP_DECXIMAGEDIB, or BI_BITFIELDS 24-bit format, it does not need to specify a palette.

5.2.4.3 Specifying the Palette

The ICDecompressGetPalette call is extended for managing colormaps (palettes) with the X Window System.

In Microsoft Windows, the palette manager supports palette selection on a per-window basis, independent of the palette utilization of other windows. All Windows applications can have their own private palettes. Specialized window messages and system calls allow applications to share the hardware palette without being aware of other applications' palette requirements. Because of the flexibility of this system, a decompressor under Windows can dictate the 8-bit palette that it uses to display images without interfering with other applications' displays of colors.

The X Window System shares the hardware palette differently. The semantics of the ICDecompressGetPalette call are extended to accommodate this difference. With this extension to the OpenVMS system, the decompression driver allows the application to negotiate a colormap. The application does not interfere with the colormap entry usage of other applications with this X Window System method of managing colormaps. The negotiating process allows the application to specify which colormap entries are or are not available for change by the driver, along with the number of colors that should be used. This allows the driver to choose a best-fit colormap for the specified number of colors while trying to reuse the colormap entries that are not available for change. The negotiating process is described in this section.

Two arguments to the ICDecompressGetPalette function are lpbiInput and lpbiOutput. They represent pointers to BITMAPINFOHEADER data structures that represent the input and output formats for decompression.

The lpbiOutput argument has space allocated beyond the BITMAPINFOHEADER data structure that contains an array of type RGBQUAD. The number of entries in the array is determined by the output format: 8 bits of color require 256 entries, 2 bits of color require 4 entries, and 24 bits of color require zero entries because the output format is true color. The BICOMP_DECYUVDIB format requires zero entries even though it has 16 bits of color because YUV encodes the color information in the data.

The ICDecompressGetPalette function replaces the RGBQUAD array with the colors the device will use. Some decompressors allow applications to change the colormap entries dynamically. For some compressed bitmap formats, the colormap entries are stored with the compressed data. JPEG data contains color information, but the color information is true color information. To display a decompressed JPEG image rendered to an 8-bit X image, you must specify a palette with the X image's BITMAPINFOHEADER data structure, which the decompressor will use to dither the image.

To account for this and to enable applications to request the number of colors they use and to share color with other applications, the following changes were made to the lpbiOutput argument of the ICDecompressGetPalette function:


Previous Next Contents Index