Programming Indeo® Video Interactive
Using ICM Calls: Decompressing
If you are a multimedia application developer who wishes to include the advanced features of the Indeo® video interactive (IVI) codec into your 32bit application, read this document. It explains what you need to know in order to control the playback parameters of the Indeo video interactive codec programmatically from the ICM interface, so that you can fully integrate features such as transparent video and local decode. This document assumes you are familiar with Video for Windows*. Indeo video interactive is Intel's latest digital video capture, compression, and decompression software. The technology is based on a compressor-decompressor, or codec - a software driver used to compress digital video data for storage, and decompress it for playback on a multimedia PC. Indeo video interactive uses an efficient encoding algorithm and yields high quality images. It includes a wide variety of features designed for interactive multimedia applications, such as real-time video effects, access key file protection, local decode, alternate line zoom-by-two, and the ability to specify transparency for portions of a video frame. These features go beyond those provided for by Video for Windows, and the standard Video for Windows Media Control Interface (MCI) is not capable of exercising them. To do so requires knowledge of the codec's internal state that is available only at the level of the Installable Compression Manager (ICM). This document has four sections:
NOTE: For a complete application example, see the source code for IVIPlay, an example application that plays back video files, taking advantage of most of the special features provided by Indeo video interactive. (As of this writing, local decode is not included.) The executable and C source code is available in the file iviplay.exe, compressed as a self-extracting archive.
The ICM Interface to Indeo Video Interactive The Indeo video interactive codec complies with Video for Windows codec standards. All ICM communication with the codec uses the ICSendMessage() function call, expanded with various ICM macros. In order to access the codec's special features, Intel has introduced two new Indeo video-specific messages to use with the ICSendMessage() function: ICM_GETCODECSTATE and ICM_SETCODECSTATE. These two messages allow the calling application to retrieve and modify the state of the codec. Instructions are provided in the Video for Windows specification for using the ICSendMessage() function. This document and the Indeo Video Interactive Video for Windows Programming Interface Specification (the file named vfw_head.htm and its accompanying documentation vfw_spec.htm) explain how to use these two new messages in order to access state information for the Indeo video interactive codec. Keep those documents handy as you read this one.
Codec States and Data Structures The Indeo video interactive codec maintains two states while decoding: sequence state and frame state. Sequence state is the state of the codec during a sequence of decompression messages, and frame state is the state of the codec from one decompression message to the next. Two predefined data structures represent these states: R4_DEC_SEQ_DATA represents sequence state and R4_DEC_FRAME_DATA represents frame state. They are described in the Indeo Video Interactive Video for Windows Programming Interface Specification (the file vfw_spec.htm) and defined in the file vfw_head.htm. While decoding, you can examine or change the codec state by sending the message ICM_GETCODECSTATE or ICM_SETCODECSTATE by means of the ICSendMessage() function, passing as one of the parameters the address of one of these two predefined state structures. Both data structures contain header members that your application
initializes in the same way regardless of the operation to be performed,
as well as other members whose initialization and use is operation-specific.
The Decode Sequence Data Structure The following C code example demonstrates how to initialize the header members of the R4_DEC_SEQ_DATA structure before sending either ICM_GETCODECSTATE or ICM_SETCODECSTATE. (Initialize other members of this structure according to the type of action required, as detailed in the next section.) R4_DEC_SEQ_DATA r4SeqState; r4SeqState.dwSize = sizeof(R4_DEC_SEQ_DATA); r4SeqState.dwFourCC = mmioFOURCC('I','V','4','1'); r4SeqState.dwVersion = SPECIFIC_INTERFACE_VERSION; r4SeqState.mtType = MT_DECODE_SEQ_VALUE; r4SeqState.oeEnvironment = OE_32; r4SeqState.dwFlags = 0;
The Decode Frame Data Structure The following C code example demonstrates how to initialize the header members of the R4_DEC_FRAME_DATA structure before sending either ICM_GETCODECSTATE or ICM_SETCODECSTATE. (Initialize other members of this structure according to the type of action required, as detailed in the next section.) R4_DEC_FRAME_DATA r4FrmState; r4FrmState.dwSize = sizeof(R4_DEC_FRAME_DATA); r4FrmState.dwFourCC = mmioFOURCC('I','V','4','1'); r4FrmState.dwVersion = SPECIFIC_INTERFACE_VERSION; r4FrmState.mtType = MT_DECODE_FRAME_VALUE; r4FrmState.oeEnvironment = OE_32; r4FrmState.dwFlags = 0;
Current and Default Codec State
Changing Playback Parameters Before any operations such as those exemplified in the following code samples, you must initialize the header members of the decode data structures as shown in Codec States and Data Structures, above. All of the following examples assume operations are done on the current, not the default, codec state. The examples below demonstrate how to use the messages ICM_GETCODECSTATE and ICM_SETCODECSTATE to get and set sequence or frame parameters. These examples all follow the same general pattern:
NOTE: The hCodec parameter is a handle to an opened Indeo video interactive codec. Using these functions on other codecs produces unpredictable results.
Modifying the Decode Sequence Parameters NOTE: For the sake of clarity, the examples below do not check return values for errors. Your application, however, needs to check all return values for errors.
Transparent Pixel Fill Method Figure 1. Transparent Pixel Fill Method: Codec Writes Background
Figure 2. Transparent Pixel Fill Method: Application Writes
Background
If the codec is not to write the transparent pixels, your application is responsible for the state of the buffer before the frame is decoded. See Programming Indeo Video Interactive Using ICM Calls: Compressing for details on encoding options. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ r4State.dwFlags = DECSEQ_FILL_TRANSPARENT | DECSEQ_VALID; r4State.fFillTransparentPixels = 1; /* enable transparent pixel fill */ ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_SEQ_DATA) );
Decode Scalability By default, the time limit is determined by the frame rate with which the video was encoded. If your application requires faster decoding, you can set a more stringent time limit using the message discussed in the section entitled "Setting the decode time limit," below. Decode scalability is controlled with the eScalability field with one of the following:
NOTE: Scalability modes which deal with band dropping effect only playback of those video clips that were encoded with scalability on. See Programming Indeo Video Interactive Using ICM Calls: Compressing for details on encoding options. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ R4_SCALABILITY eScalability; /* the requested scalability mode, */ /* one of SC_ON, SC_OFF, */ /* SC_DONT_DROP_FRAMES, */ /* or SC_DONT_DROP_QUALITY */ r4State.dwFlags = DECSEQ_SCALABILITY | DECSEQ_VALID; r4State.eScalability = eScalability; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_SEQ_DATA) );
Access Key Protection An access key must have a numeric value only. If a clip has been encoded with access key protection enabled and the proper access key is not supplied when decoding, the codec returns the error ICERR_ERROR as soon as it receives the next decompression message. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ DWORD dwKey; /* the access key */ r4State.dwFlags = DECSEQ_KEY | DECSEQ_VALID; r4State.dwKey = dwKey; r4State.fEnabledKey = 1; /* enable access key */ ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_SEQ_DATA) );
Alternate Line Zoom-by-Two NOTE: This feature is not supported with transparency and local decode. Also, if the user stretches the window manually after zooming using alternate lines, the rows of black pixels are also stretched, and the resulting image looks poor. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ r4State.dwFlags = DECSEQ_ALT_LINE | DECSEQ_VALID; r4State.fAltLine = 1; /* enable alt-line zoom-by-2 */ ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_SEQ_DATA)); Modifying the decode frame parameters
Transparent Pixel Fill Color See Programming Indeo Video Interactive Using ICM Calls: Compressing for details on encoding options. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ r4State.dwFlags = DECFRAME_FILL_COLOR | DECFRAME_VALID; r4State.dwFillColor = 0x0000ff00; /* RGB( 0, 255, 0 ) ICSendMessage( hCodec,ICM_SETCODECSTATE, (DWORD)&r4State, (DWORD)sizeof(R4_DEC_FRAME_DATA));
Custom Palette Configuration To specify a custom palette, the address of the palette data must be supplied, as well as the indices of the first and last entries within the palette which are to be used. In addition, the same palette must subsequently be supplied to the codec via an ICDecompressSetPalette() procedure call before the palette will be used by the codec. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ LPRGBQUAD prgbq; /* a pointer to an array of RGBQUAD */ /* structures containing the */ /* custom palette. */ DWORD dwFirstPalIndex; /* index of the first entry */ DWORD dwLastPalIndex; /* index of the last entry */ r4State.dwFlags = DECFRAME_8BIT_CONFIG_PALETTE | DECFRAME_VALID; r4State.dwFirstPalIndex = dwFirstPalIndex; r4State.dwLastPalIndex = dwLastPalIndex; r4State.prgbPalette = prgbq; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); To specify the dither level: HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_DITHER eDither; /* the new dither value, one of OFF,*/ /* LOW, MEDIUM, or HIGH */ r4State.dwFlags = DECFRAME_8BIT_DITHER | DECFRAME_VALID; r4State.eDither = eDither; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); Setting the address of the transparency bounding rectangle As shown in Figure 3, the bounding rectangle is the smallest rectangle that can contain the nontransparent pixels. Figure 3. Bounding Rectangle of Nontransparent Figure
The application must specify the address of an R4_RECT structure to which the codec can return the origin, width, and height of the bounding rectangle in the last frame decoded: that is, which rectangular region of the frame was written over. This allows the application to repaint the background after the nontransparent shape has moved. Once you have set the address of the bounding rectangle, the codec updates the bounding rectangle's position after each frame is decoded so that the application can continue to clean up the background as necessary. If the codec returns all zeroes, no pixels were written in the last frame because the nontransparent shape did not appear. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4Rect; /* the update rectangle */ r4State.dwFlags = DECFRAME_BOUNDING_RECT | DECFRAME_VALID; r4State.pr4BoundingRect = &r4Rect /* Supply the address of the rect */ ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
Setting the Address of the Transparency Bitmask If you decide to handle the transparency in your application, this message provides the codec with the address of memory in which to write a onebit bitmask for the last frame decoded, and the address of a flag to be set if bitmask information is available. Enough memory must be allocated for one bit to represent each pixel of a frame. The bitmask specifies which areas of the frame have nontransparent video information: a value of zero means a pixel is transparent and a value of one means that it is not. Each row must begin on a DWORD boundary, and the total number of bytes must be a multiple of four. If it isn't, round up to the nearest multiple of four. See vfw_spec.htm for further details./* HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4DecodeRect; /* the decode rect */ R4_FLAG fBitmask; /* the bitmask update flag */ PTR_R4_BITMASK bmBitmask; /* a pointer to memory allocated */ /* for the bitmask */ r4State.dwFlags = DECFRAME_TRANS_BITMASK | DECFRAME_VALID; r4State.pfUpdatedTransparencyBitmask = &fBitmask r4State.pbmTransparencyBitmask = pbmBitmask; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
Input Transparency Bitmask HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ PTR_R4_BITMASK pbmInputBitmask; /* a pointer to memory allocated */ /* for the input bitmask */ r4State.dwFlags = DECFRAME_INPUT_TRANS_MASK | DECFRAME_VALID; r4State.pbmInputTransparencyBitmask = pbmInputBitmask; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); If the user has requested a transparency mask be returned through the pfUpDatedTransparencyBitmask field, the codec will return a bitmask containing only those bits which were drawn if the sequence contained transparency. Otherwise, the codec will return 0 in pfUpdatedTransparencyBitmask, in which case the input mask was used as the transparency mask, and defines which pixels were written. NOTE: The application may request that no frames be dropped during transparent video playback via the eScalability field of the R4_DEC_SEQ_DATA structure, discussed earlier in this document.
Setting the Decode Time Limit The milliseconds specified are wall clock milliseconds, not CPU cycles. The codec consults the system clock to determine the elapsed time. If you set the time limit to zero, the codec uses the frame rate with which the video was encoded to determine the time limit. This is the default. For example, a frame rate of ten frames per second indicates a time limit of one hundred milliseconds. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ DWORD dwTimeLimit; /* the time allotted for the codec */ r4State.dwFlags = DECFRAME_TIME_LIMIT | DECFRAME_VALID; r4State.dwTimeLimit = dwTimeLimit; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
Setting the Position and Dimensions of the Decode Rectangle for Local
Decode A decode rectangle cannot be smaller than the minimum size specified during encoding. It can be changed only immediately before a key frame; if you try to change it before any other frame, the codec returns the error ICERR_BADPARAM. The decode rectangle cannot extend outside the image and must wholly enclose the view rectangle, which is discussed below. If all fields are zero, the entire image is decoded. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4DecodeRect; /* the decode rectangle */ r4State.dwFlags = DECFRAME_DECODE_RECT | DECFRAME_VALID; r4State.rDecodeRect = &r4DecodeRect ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
Setting the Position and Dimensions of the View Rectangle for Local
Decode HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4ViewRect; /* the view rectangle */ r4State.dwFlags = DECFRAME_VIEW_RECT | DECFRAME_VALID; r4State.rDecodeRect = &r4ViewRect ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); The above method requires an output buffer large enough to hold the entire decoded frame if necessary. When using this method the size and position of the view rectangle may be freely adjusted without regard for the size of the output buffer. Support for minimizing the size of the output buffer is provided through the fViewRectOrigin field. If this field is set to TRUE, the codec decodes directly to the output buffer, without regard to the offsets provided for the view rectangle. In this manner, the required size of the output buffer is minimized to that of just the view rectangle. The codec will decode directly to the minimized buffer, however changes to the view rectangle dimensions might require changes to the buffer size. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4ViewRect; /* the view rectangle */ r4State.dwFlags = DECFRAME_VIEW_RECT_ORIGIN | DECFRAME_VALID; r4State.rDecodeRect = &r4ViewRect r4State.fViewRectOrigin = TRUE; /* no offset into the buffer */ ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
Setting the Brightness, Saturation, and Contrast Levels Brightness is an additive adjustment to luminance. Contrast and saturation are nonlinear adjustments. HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ LONG lBrightness; /* the brightness value (-255..255) */ LONG lSaturation; /* the saturation value (-255..255) */ LONG lContrast; /* the contrast value (-255..255) */ r4State.dwFlags = DECFRAME_BRIGHTNESS | DECFRAME_SATURATION | DECFRAME_CONTRAST | DECFRAME_VALID; r4State.lBrightness = lBrightness; r4State.lSaturation = lSaturation; r4State.lContrast = lContrast; ICSendMessage( hCodec, ICM_SETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
Retrieving the Decode Sequence Parameters
Transparent Pixel Fill Method HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ r4State.dwFlags = DECSEQ_FILL_TRANSPARENT | DECSEQ_VALID; ICSendMessage( hCodec, ICM_GETCODECSTATE, (DWORD)&r4State, (DWORD)sizeof(R4_DEC_SEQ_DATA)); /* If r4State.fFillTransparentPixels = 0, it's disabled */ /* otherwise it's enabled */
Decode Scalability HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ r4State.dwFlags = DECSEQ_SCALABILITY | DECSEQ_VALID; ICSendMessage( hCodec, ICM_GETCODECSTATE, (DWORD)&r4State, (DWORD)sizeof(R4_DEC_SEQ_DATA)); /* If r4State.fScalability = 0, decode scalability is disabled, */ /* otherwise it's enabled */
Alternate Line Zoom-by-Two HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_SEQ_DATA r4State; /* initialized sequence structure */ r4State.dwFlags = DECSEQ_ALT_LINE | DECSEQ_VALID; ICSendMessage( hCodec, ICM_GETCODECSTATE, (DWORD)&r4State, (DWORD)sizeof(R4_DEC_SEQ_DATA)); /* If r4State.fAltLine = 0, alt-line zoom-by-2 is disabled, otherwise */ /* it's enabled */
Retrieving the Decode Frame Parameters
Retrieving the Transparent Pixel Fill Color
HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ r4State.dwFlags = DECFRAME_FILL_COLOR | DECFRAME_VALID; ICSendMessage( hCodec,ICM_GETCODECSTATE, (DWORD)&r4State, (DWORD)sizeof(R4_DEC_FRAME_DATA)); Note: The value returned in the dwFillColor field is in the format of the current output color mode. If the current output mode is RGB24, the low order 3 bytes of dwFillColor contain the R, G and B values. If the current output mode is RGB8, the low byte of dwFillColor contains a palette index.
Retrieving the Decode Time Limit HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ r4State.dwFlags = DECFRAME_TIME_LIMIT | DECFRAME_VALID; ICSendMessage( hCodec, ICM_GETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); /* r4State.lTimeLimit now contains the current decode time limit */
Retrieving the Position and Dimensions of the Decode Rectangle for
Local Decode HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4DecodeRect; /* the rectangle for retrieving the */ /* decode rect */ r4State.dwFlags = DECFRAME_DECODE_RECT | DECFRAME_VALID; r4State.rDecodeRect = &r4DecodeRect ICSendMessage( hCodec,ICM_GETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); /* r4DecodeRect now contains the current decode rectangle position */ /* and dimensions. */
Retrieving the Position and Dimensions of the View Rectangle for Local
Decode HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ R4_RECT r4ViewRect; /* the rectangle for retrieving the */ /* view rect */ r4State.dwFlags = DECFRAME_VIEW_RECT | DECFRAME_VALID; r4State.rViewRect = &r4ViewRect ICSendMessage( hCodec,ICM_GETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) ); /* r4ViewRect now contains the current decode rectangle position */ /* and dimensions. */
Retrieving the Brightness, Saturation, and Contrast Levels HIC hCodec; /* handle to an opened IVI codec */ R4_DEC_FRAME_DATA r4State; /* initialized frame structure */ r4State.dwFlags = DECFRAME_BRIGHTNESS | DECFRAME_SATURATION | DECFRAME_CONTRAST | DECFRAME_VALID; ICSendMessage( hCodec, ICM_GETCODECSTATE, (DWORD)&r4State, sizeof(R4_DEC_FRAME_DATA) );
References
For latest information, also see:
|
* Legal Stuff © 1997 Intel Corporation