Microsoft RIFF

Also Known As: RIFF, Resource Interchange File Format, RIFX, .WAV, .AVI, .BND, .RMI, .RDI, .PAL, .RMN, .ANI


Type Multimedia
Colors 24-bit
Compression RLE, uncompressed, audio, video
Maximum Image Size Varies
Multiple Images Per File No
Numerical Format Little- and big-endian
Originator Microsoft Corporation
Platform Microsoft Windows 3.x, Windows NT
Supporting Applications Microsoft Windows and OS/2 multimedia applications
See Also IFF, Microsoft Windows Cursor and Icon, Chapter 10, Multimedia

Usage
RIFF is a device control interface and common file format native to the Microsoft Windows system. It is used to store audio, video, and graphics information used in multimedia applications.

Comments
A complex format designed to accommodate various types of data for multimedia applications. Because it is quite new and vendor-controlled, the specification is likely to change in the future.

Vendor specifications are available for this format.


Microsoft RIFF (Resource Interchange File Format) is a multimedia file format created by Microsoft for use with the Windows GUI. RIFF itself does not define any new methods of storing data, as many of the bitmap formats described in this book do. Instead, RIFF defines a structured framework, which may contain existing data formats. Using this concept, you can create new, composite formats consisting of two or more existing file formats.

Contents:
File Organization
File Details
For Further Information

Multimedia applications require the storage and management of a wide variety of data, including bitmaps, audio data, video data, and peripheral device control information. RIFF provides an excellent way to store all these varied types of data. The type of data a RIFF file contains is indicated by the file extension. Examples of data that may be stored in RIFF files are:

NOTE:

At this point, AVI files are the only type of RIFF files that have been fully implemented using the current RIFF specification. Although WAV files have been implemented, these files are very simple, and their developers typically use an older specification in constructing them.

Because RIFF is an umbrella name for a variety of multimedia files, RIFF files are referred to by the type of data they contain, rather than by the actual format name of RIFF. For this reason, you may find RIFF files rather confusing when you start to use them. For example, a RIFF file containing Audio/Visual Interleaved data is normally referred to simply as an "AVI file" and not as a "RIFF Audio/Visual Interleaved Format File." Only a programmer might ever realize that all of these different files are the same format, or even care.

There is another area of potential confusion. Some people think that RIFF files are somehow similar in design to TIFF (Tag Image File Format) files. While it is true that both formats contain data structures that may be added or deleted to a file ("tags" in TIFF and "chunks" in RIFF), the internal concept and design of these structures within RIFF and TIFF differ greatly. Unlike TIFF, the RIFF file format is based on the Electronic Arts Interchange File Format (IFF) structure (see the article describing this format). And, although both formats use the same concept of data storage, they are not compatible in their design.

File Organization

RIFF is a binary file format containing multiple nested data structures. Each data structure within a RIFF file is called a chunk. Chunks do not have fixed positions within a RIFF file, and therefore standard offset values cannot be used to locate their fields. A chunk contains data such as a data structure, a data stream, or another chunk called a subchunk. Every RIFF chunk has the following basic structure:

typedef struct _Chunk
{
    DWORD ChunkId;              /* Chunk ID marker */
    DWORD ChunkSize;            /* Size of the chunk data in bytes */
    BYTE ChunkData[ChunkSize];  /* The chunk data */
} CHUNK;

ChunkId contains four ASCII characters that identify the data the chunk contains. For example, the characters RIFF are used to identify chunks containing RIFF data. If an ID is smaller than four characters, it is padded on the right using spaces (ASCII 32). Note that RIFF files are written in little-endian byte order. Files written using the big-endian byte ordering scheme have the identifier RIFX.

ChunkSize is the length of the data stored in the ChunkData field, not including any padding added to the data. The size of the ChunkId and ChunkSize fields are not themselves included in this value.

ChunkData contains data that is WORD-aligned within the RIFF file. If the data is an odd length in size, an extra byte of NULL padding is added to the end of the data. The ChunkSize value does not include the length of the padding.

Subchunks also have the same structure as chunks. A subchunk is simply any chunk that is contained within another chunk. The only chunks that may contain subchunks are the RIFF file chunk RIFF and the list chunk, LIST (explained in the next section). All other chunks may contain only data.

A RIFF file itself is one entire RIFF chunk. All other chunks and subchunks in the file are contained within this chunk. If you are decoding, your RIFF reader should ignore any chunks that the reader does not recognize or it cannot use. If you are encoding, your RIFF writer will write out all unknown and unused chunks that were read. Do not discard them.

File Details

RIFF files that are used to store audio and video information are called AVI files. The RIFF AVI file format normally contains only a single AVI chunk; however, other types of chunks may also appear. An AVI reader should ignore all chunks it does not need or recognize that are stored within a RIFF AVI file.

Although Microsoft uses a standard notation to describe the internal arrangement of data structures within RIFF files, we believe it is clearer to use our own C-like syntax to illustrate the placement of chunks and subchunks within a RIFF AVI file. The ChunkId for each chunk is listed in the comments:

struct _RIFF   /* "RIFF" */
{
    struct _AVICHUNK   /* "AVI " */
    {
        struct _LISTHEADERCHUNK   /* "hdrl" */
        {
            AVIHEADER AviHeader;     /* "avih" */
            struct _LISTHEADERCHUNK  /* "strl" */
            {
                AVISTREAMHEADER	StreamHeader; /* "strh" */
                AVISTREAMFORMAT	StreamFormat; /* "strf" */
                AVISTREAMDATA	StreamData;   /* "strd" */
            }
        }
        struct _LISTMOVIECHUNK  /* "movi" */
        {
            struct _LISTRECORDCHUNK  /* "rec " */
            {
                /* Subchunk 1 */
                /* Subchunk 2 */
                /* Subchunk N */
            }
        }
        struct _AVIINDEXCHUNK  /* "idx1" */
        {
            /* Index data */
        }
    }
}

The above structure represents the internal data layout of a RIFF file containing only one AVI chunk. This chunk follows the format of the chunk data structure previously described. The AVI chunk is identified by the 4-character chunk identifier "AVI " (note the final blank character). The AVI chunk contains two mandatory LIST subchunks, which indicate the format of the data stream(s) stored in the file.

AVI Header Subchunk

The first mandatory LIST chunk contains the main AVI header subchunk and has the identifier hdrl. The information in the header subchunk defines the format of the entire AVI chunk. The hdrl chunk must appear as the first chunk within the AVI chunk. The format of the header subchunk is the following:

typedef struct _AVIHeader
{
    DWORD TimeBetweenFrames;     /* Time delay between frames */
    DWORD MaximumDataRate;       /* Data rate of AVI data */
    DWORD PaddingGranularity;    /* Size of single unit of padding */
    DWORD Flags;                 /* Data parameters */
    DWORD TotalNumberOfFrames;   /* Number of video frame stored */
    DWORD NumberOfInitialFrames; /* Number of preview frames */
    DWORD NumberOfStreams;       /* Number of data streams in chunk*/
    DWORD SuggestedBufferSize;   /* Minimum playback buffer size */
    DWORD Width;                 /* Width of video frame in pixels */
    DWORD Height;                /* Height of video frame in pixels*/
    DWORD TimeScale;             /* Unit used to measure time */
    DWORD DataRate;              /* Data rate of playback */
    DWORD StartTime;             /* Starting time of AVI data */
    DWORD DataLength;            /* Size of AVI data chunk */
} AVIHEADER;

TimeBetweenFrames contains a value indicating the amount of delay between frames in microseconds.

MaximumDataRate value indicates the data rate of the AVI data in bytes per second.

PaddingGranularity specifies the multiple size of padding used in the data in bytes. When used, the value of this field is typically 2048.

Flags contains parameter settings specific to the AVI file and its data. The parameters correspond to the bit values of the Flags field as follows:

Bit 4

AVI chunk contains an index subchunk (idx1).

Bit 5

Use the index data to determine how to read the AVI data, rather than the physical order of the chunks with the RIFF file.

Bit 8

AVI file is interleaved.

Bit 16

AVI file is optimized for live video capture.

Bit 17

AVI file contains copyrighted data.

TotalNumberOfFrames indicates the total number of frames of video data stored in the movi subchunk.

NumberOfInitialFrames specifies the number of frames in the file before the actual AVI data. For non-interleaved data this value is 0.

NumberOfStreams holds the number of data streams in the chunk. A file with an audio and video stream contains a value of 2 in this field, while an AVI file containing only video data has 1. In the current version of the RIFF format, one audio and one video stream are allowed.

SuggestedBufferSize is the minimum size of the buffer to allocate for playback of the AVI data. For non-interleaved AVI data, this value is at least the size of the largest chunk in the file. For interleaved AVI files, this value should be the size of an entire AVI record.

Width and Height values indicate the size of the video image in pixels.

TimeScale is the unit used to measure time in this chunk. It is used with DataRate to specify the time scale that the stream will use. For video streams, this value should be the frame rate and typically has a value of 30. For audio streams, this value is typically the audio sample rate.

DataRate is divided by the TimeScale value to calculate the number of samples per second.

StartTime is the starting time of the AVI data and is usually 0.

DataLength is the size of the AVI chunk in the units specified by the TimeScale value.

The hdrl subchunk also contains one or more LIST chunks with the identifier strl. There will be one of these LIST chunks per data stream stored in the AVI chunk.

Three subchunks are stored within the strl LIST chunk. The first is the Stream Header subchunk, which has the identifier strh. This header contains information specific to the data stream stored in the strl LIST chunk. A stream header is required and has the following format:

typedef struct _StreamHeader
{
    char  DataType[4];           /* Chunk identifier ("strl") */
    char  DataHandler[4];        /* Device handler identifier */
    DWORD Flags;                 /* Data parameters */
    DWORD Priority;              /* Set to 0 */
    DWORD InitialFrames;         /* Number of initial audio frames */
    DWORD TimeScale;             /* Unit used to measure time */
    DWORD DataRate;              /* Data rate of playback */
    DWORD StartTime;             /* Starting time of AVI data */
    DWORD DataLength;            /* Size of AVI data chunk */
    DWORD SuggestedBufferSize;   /* Minimum playback buffer size */
    DWORD Quality;               /* Sample quailty factor */
    DWORD SampleSize;            /* Size of the sample in bytes */
} STREAMHEADER;

DataType contains a 4-character identifier indicating the type of data the stream header refers to. Identifiers supported by the current version of the RIFF format are: vids for video data and auds for audio data.

DataHandler may contain a 4-character identifier specifying the preferred type of device to handle the data stream.

Flags contains a set of bit flags use to indicate parameter settings related to the data.

Priority is set to 0.

InitialFrames indicates in seconds how far the audio is placed ahead of the video in interleaved data.

TimeScale, DataRate, StartTime, DataLength, and SuggestedBufferSize all have the same function as the fields of the same names in the hdr1 chunk.

Quality is an integer in the range of 0 to 10,000, indicating the quality factor used to encode the sample.

SampleSize is the size of a single sample of data. If this value is 0, the sample varies in size and each sample is stored in a separate subchunk. If this value is non-zero, then all the samples are the same size and are stored in a single subchunk.

Immediately following the stream header is a stream format subchunk with the identifier strf. This header describes the format of the stream data. Its format varies depending on the type of data that is stored (audio or video). This subchunk is also required.

Another stream data subchunk with the identifier strd can optionally follow the stream format subchunk. The data in this chunk is used to configure the drivers required to interpret the data. The format of this chunk also varies depending upon the type of compression used on the stream data.

AVI Data Subchunk

The second mandatory LIST chunk contains the actual AVI data, has the identifier movi, and must appear as the second chunk within the AVI chunk.

The data in the movi chunk may be grouped in the form of LIST records (a LIST chunk containing one or more subchunks each with the identifier "rec "). Only data that is interleaved to be read from a CD-ROM is stored as a series of LIST records (data is read more efficiently from a CD-ROM when it is interleaved). If the data is not interleaved, it is stored as a single block of data within the movi chunk itself.

Index Chunk

The AVI chunk may also contain a third chunk, called an index chunk. An index chunk has the identifier idx1 and must appear after the hdrl and movi chunks. This chunk contains a list of all chunks within the AVI chunk, along with their locations, and is used for random access of audio and video data. The index chunk has the following format:

typedef struct _AviIndex
{
    DWORD Identifier;    /* Chunk identifier reference */
    DWORD Flags;         /* Type of chunk referenced */
    DWORD Offset;        /* Position of chunk in file */
    DWORD Length;        /* Length of chunk in bytes */
} AVIINDEX;

Identifier contains the 4-byte identifier of the chunk it references (strh, strf, strd, and so on).

Flags bits are used to indicate the type of frame the chunk contains or to identify the index structure as pointing to a LIST chunk.

Offset indicates the start of the chunk in bytes relative to the movi list chunk.

Length is the size of the chunk in bytes.

The idx1 chunk contains one of these structures for every chunk and subchunk in the AVI chunk. The structures need not index each chunk in the order in which they occur within the AVI chunk. The order of the index structures in the idx1 may also be used to control the presentation order of the data stored in the AVI chunk. If an index is included in an AVI chunk, the appropriate indication bit must be set in the Flags field of the AVI header chunk. If an application reading a RIFF file decides to use the information in the index chunk, it must first find the hdrl chunk and determine if an index chunk exists by examining the Flags field value in the AVI header. If it does exist, the reader will skip past all the chunks in the AVI chunk until it encounters the idx1 chunk.

JUNK Chunk

One other type of chunk that is commonly encountered in an AVI chunk is the padding or JUNK chunk (so named because its chunk identifier is JUNK). This chunk is used to pad data out to specific boundaries (for example, CD-ROMs use 2048-byte boundaries). The size of the chunk is the number of bytes of padding it contains. If you are reading AVI data, do not use use the data in the JUNK chunk. Skip it when reading and preserve it when writing. The JUNK chunk uses the standard chunk structure:

typedef struct _JunkChunk
{
    DWORD ChunkId;             /* Chunk ID marker (JUNK)*/
    DWORD PaddingSize;         /* Size of the padding in bytes */
    BYTE Padding[ChunkSize];   /* Padding */
} JUNKCHUNK;

Animated Cursor

One of the more popular uses of RIFF are Animated Cursor files, also known as Windows NT Animated Cursors. If you have ever used Windows 95 or Windows NT you have seen the mouse cursor transform into different shapes, such as an hourglass or a clock. What you may also have noticed is the sand falling through the hour glass, or the hands moving about the clock face. These simple animations are stored as animated cursor (.ANI) files.

An animated cursor is just a flipbook animation created by two or more bitmaps stored in an ANI file. Each bitmap is typically Windows cursor or icon data, but may also be raw, uncompressed bitmaps. Additional information stored in the ANI file controls the rate and the sequence in which each frame is displayed.

Animated cursor RIFF files are identified by the "ACON" form identifier. RIFF ACON files must contain at least a Header subchunk and a LIST Frame chunk which stores the actual bitmap data. The Header subchunk must also appear before the List Frame chunk, or the Rate and Sequence subchunks (described below).

The Header subchunk is 44 bytes in length and has the following format:

typedef struct _AniHeaderSubchunk
{
    DWORD ChunkId;      /* Subchunk ID (always "anih") */
    DWORD Size;         /* Length of subchunk minus 8 */
    DWORD HeaderSize;   /* Size of the subchunk data in bytes */
    DWORD NumFrames;    /* Number of icon or cursor frames */
    DWORD NumSteps;     /* Number of steps in the animation */
    DWORD Width;        /* Width of frame in pixels */
    DWORD Height;       /* Height of frame in pixels */
    DWORD BitCount;     /* Number of bits in the frame pixels */
    DWORD NumPlanes;    /* Number of color planes in the frame data */
    DWORD DisplayRate;  /* Default frame display rate */
    DWORD Flags;        /* File attributes flags */
} ANIHEADERSUBCHUNK;

ChunkId is the subchunk identifier and is always 0x616E6968 ("anih").

Size is the number of bytes in the subchunk that appear after the Size field. This value is always 32.

HeaderSize is the size of the subchunk data (all the bytes appearing after the Size field) in bytes. This value is always equal to the Size value.

NumFrames specifies the number of frames used in the animation. This is also the number of icon, cursor, or raw bitmaps stored in the LIST Frame chunk.

NumSteps indicates the total number of steps in one playback of the animation. If there is no Sequence subchunk present, this value will be equal to NumIcons. A Sequence subchunk may specify that one or more frames are displayed more than once in a single playback of an animation.

Width and Height are the width and height of the frames in pixels respectively. This value is only used with frames stored as raw bitmap data.

BitCount is the number of bits in each pixel of each frame. This value is only used with frames stored as raw bitmap data.

NumPlanes is the number of color planes in each frame. This value is only used with frames stored as raw bitmap data.

DisplayRate is the default frame rate in jiffies (one jiffy equals 1/60th of a second). The rate is actually how long an animation frame remains on the screen before the next frame is displayed. If no Rate subchunk is present in an ANI file, this value is used as the duration that all frames will appear on the display. A rate of 0 indicates that there is no delay between frames.

Flags is a field of bit flags. The following flags are defined:

0x00000001 Frames are Windows icon or cursor data
0x00000002 File contains sequence data

If the icon data flag (0x00000001) is set, the frame data are Windows icon or cursor files. The width, height, bit count, and number of color planes information is stored in the frame data, and the Width, Height, BitCount, and NumPlanes Header values are 0. If the icon data flag is not set, then the frame data is assumed to be only raw pixel data that interpreted using the Width, Height, BitCount, and NumPlanes values.

The sequence flag (0x00000002) will be set if a Sequence subchunk is stored in the ANI file. The Sequence subchunk specifies the order in which frames are displayed. If no Sequence subchunk is present, the frames are displayed in the order that they are stored in the ANI file. If the sequence flag is not set, then the number of steps in the animation is indicated by the NumIcons value, otherwise it is specified by the NumSteps value.

The LIST Frame chunk is a LIST chunk with a list type of "fram". This chunk contains an array of all the bitmaps used to make the animation. The LIST Frame chunk is structured as follows:

typedef struct _ListFrameChunk
{
    DWORD        ListId;     /* "LIST" */
    DWORD        ListSize;   /* Length of LIST chunk minus 8 */
    DWORD        ListType;   /* "fram" */
    ICONSUBCHUNK Frames[];   /* Array of cursor, icon, or bitmap data */
} LISTFRAMECHUNK;

ListId is the chunk identifiers and is always 0x4C495354 ("LIST").

ListSize is the number of bytes in the subchunk that appear after the Size field.

ListType is the list type identifier. For LIST chunks storing frame data this value is always 0x6672616D ("fram").

Frames is an array of subchunks that store Windows icon or cursor bitmaps, or raw bitmap data. Each subchunk is implicitly assigned a zero-based index value by its order of appearance in the LIST Frame chunk. This index is used to locate information corresponding data stored in the Rate and Sequence subchunks.

Each bitmap in the animation is stored in a separate Icon subchunk. There will be one Icon subchunk per frame stored in an ANI file. An Icon subchunk has the following format:

typedef struct _IconSubchunk
{
    DWORD ChunkId;      /* Subchunk ID (always "icon") */
    DWORD Size;         /* Length of subchunk minus 8 */
    BYTE  Data[];       /* Icon, cursor, or raw bitmap data */ 
} ICONSUBCHUNK;

ChunkId is the subchunk identifier and is always 0x69636F6E ("icon").

Size is the number of bytes in the subchunk that appear after the Size field.

Data contains a single Windows icon or cursor file (complete with header), or a raw bitmap (no header). The icon flag in the Flags field of the Header subchunk will indicate the type of data stored in all Icon subchunks. Information such as bitmap width, height, and pixel depth will be found in the icon or cursor data header. For raw bitmaps this information is stored in the Header subchunk. Refer to the Microsoft Cursor and Icon file format article for more information.

Now that we have had a look at the Header subchunk and the LIST Frame chunk, let us now look at a minimal ANI file described as a C structure:

typedef struct _RiffAniFile
{
    DWORD              FileId;     /* File ID (always "RIFF") */
    DWORD              Size;       /* Length of file minus 8 in bytes */
    DWORD              FormID;     /* Format ID (always "ACON") */
    ANIHEADERSUBCHUNK  AniHeader;  /* Header subchunk */
    LISTFRAMECHUNK     ListFrame;  /* LIST Frame chunk */
} RIFFANIFILE;

Four additional RIFF chunks may optionally appear in an ANI file. Two of these chunks, the LIST INFO chunk and the Display chunk, are not necessary for the interpretation of animated cursor data and will not be discussed here. Refer to the Microsoft documentation listed in the For Further Information section for more details on these chunks. Two other subchunks, Rate and Sequences, are specifically defined for the RIFF ACON form and are described below.

The Rate subchunk is used to assign a duration time for each step in the animation. The duration of each step is measured in "jiffies", with one jiffy equaling 1/60th of a second. If a Rate subchunk does not appear in an ANI file, then the DisplayRate value in the Header subchunk is used as the default rate for all steps.

The Rate subchunk has the following format:

typedef struct _RateSubchunk
{
    DWORD ChunkId;      /* Subchunk ID (always "rate") */
    DWORD Size;         /* Total length of subchunk in bytes */
    DWORD Rates[];      /* Array of JIF rate values */
} RATESUBCHUNK;
ChunkId is the subchunk identifier and is always 0x72617465 ("rate").

Size is the number of bytes in the subchunk that appear after the Size field. This value is always a multiple of four.

Rates is an array of JIF rate values. The number of values is equal to the value of the NumSteps field in the Header subchunk. Each value corresponds, by position, to a step in the animation (value 0 corresponds to the first step, value 1 to the second step, and so on).

The Sequence subchunk stores the order in which the frames of the animation are displayed. The order is stored as a list of indices, with one index per step. Each index points to a particular bitmap stored in the LIST Frame chunk that is to be displayed for that step. Each bitmap in the LIST chunk is implicitly indexed, starting at zero, in the order that they are stored.

The Sequence subchunk has the following format:

typedef struct _SequenceSubchunk
{
    DWORD ChunkId;      /* Subchunk ID (always "seq ") */
    DWORD Size;         /* Length of subchunk minus 8 */
    DWORD Indices[];    /* Array of sequence values */
} SEQUENCESUBCHUNK;

ChunkId is the subchunk identifier and is always 0x73657120 ("seq ").

Size is the number of bytes in the subchunk that appear after the Size field. This value is always a multiple of four.

Indices is an array of values that determines the playing sequence of the frames stores in the ANI file. The number of values is equal to the value of the NumSteps field in the Header subchunk. Each index value corresponds, by position, to a bitmap stored in the LIST Frame chunk.

Let us now revise the ANI file C structure to contain all possible chunks and subchunks defined for the RIFF ACON file format:

typedef struct _RiffAniFile
{
    DWORD             FileId;           /* File ID (always "RIFF") */
    DWORD             Size;             /* Length of file minus 8 in bytes */
    DWORD             FormId;           /* Format ID (always "ACON") */
    LISTINFOCHUNK     ListInfoChunk;    /* File and content information */
    DISPLAYSUBCHUNK   DisplaySubchunk;  /* Display object */
    ANIHEADERSUBCHUNK AniHeader;        /* Header information */
    RATESUBCHUNK      RateSubchunk;     /* Frame rate data */
    SEQUENCESUBCHUNK  SequenceSubchunk; /* Frame sequence data */
    LISTFRAMECHUNK    ListFrame;        /* LIST Frame chunk */
} RIFFANIFILE;

And let's have a look at a real-world example of an ANI file. A hex dump of the first 256 bytes of the Windows 95 hand.ani file reveals the following information:

000000  52 49 46 46  D4 0C 00 00  41 43 4F 4E  4C 49 53 54  RIFF+...ACONLIST
000010  40 00 00 00  49 4E 46 4F  49 4E 41 4D  05 00 00 00  @...INFOINAM....
000020  48 61 6E 64  00 00 49 41  52 54 26 00  00 00 4D 69  Hand..IART&...Mi
000030  63 72 6F 73  6F 66 74 20  43 6F 72 70  6F 72 61 74  crosoft Corporat
000040  69 6F 6E 2C  20 43 6F 70  79 72 69 67  68 74 20 31  ion, Copyright 1
000050  39 39 33 00  61 6E 69 68  24 00 00 00  24 00 00 00  993.anih$...$...
000060  04 00 00 00  05 00 00 00  00 00 00 00  00 00 00 00  ................
000070  00 00 00 00  00 00 00 00  08 00 00 00  03 00 00 00  ................
000080  72 61 74 65  14 00 00 00  08 00 00 00  08 00 00 00  rate............
000090  08 00 00 00  08 00 00 00  1E 00 00 00  73 65 71 20  ........-...seq 
0000A0  14 00 00 00  00 00 00 00  01 00 00 00  02 00 00 00  ................
0000B0  03 00 00 00  00 00 00 00  4C 49 53 54  1C 0C 00 00  ........LIST....
0000C0  66 72 61 6D  69 63 6F 6E  FE 02 00 00  00 00 02 00  framicon_.......
0000D0  01 00 20 20  00 00 10 00  10 00 E8 02  00 00 16 00  ..  ......_.....
0000E0  00 00 28 00  00 00 20 00  00 00 40 00  00 00 01 00  ..(... ...@.....
0000F0  04 00 00 00  00 00 80 02  00 00 00 00  00 00 00 00  ......€.........

Note the file begins with the "RIFF" and "ACON" identifiers. Immediately following is a LIST INFO chunk that stores the name of the file and file's the copyright notice. You will note that the file's copyright notice is erroneously stored in an IART ("Artist") subchunk rather than an ICOP ("Copyright") subchunk. (What some people will do to save a few bytes).

After the LIST INFO chunk we see the "anih" Header subchunk identifier. The values of the Header fields are as follows:

ChunkId: 0x616E6968
Size: 0x00000024
HeaderSize: 0x00000024
NumIcons: 0x00000004
NumSteps: 0x00000005
Width: 0x00000000
Height: 0x00000000
BitCount: 0x00000000
NumPlanes: 0x00000000
DisplayRate: 0x00000008
Flags: 0x00000003

We can see that there are four bitmaps stored in the file and that they are Windows icon or cursor data. The animation is played in five steps and there is a Sequence subchunk in the file. The default frame rate is shown to be eight jiffies.

Following the Header is a rate subchunk. The five values it contains (one per step) are 8, 8, 8, 8, and 30. The Sequence subchunk follows and indicates that the four bitmaps are to be displayed in the order of 0, 1, 2, 3, 0. (HAND.ANI is a hand tapping its fingers on an imaginary surface).

A LIST Frame chunk follows the Sequence subchunk and we can see the first Icon subchunk and its header data. The icon data is 32 by 32 pixels in size and has a depth of one bit per pixel. There will be a total of four icons stored in this chunk.

Displaying an animated cursor under Windows is just a single call to the Win16 or Win32 API. But what are the steps if you wanted your code to display the cursor on a non-Windows operating system?

Your software will need to read all bitmaps into memory and keep track of the order that they are stored in the file. If no Sequence subchunk is present, the number of steps in the animation will be equal to the number of bitmaps stored in the ANI file. And each bitmap would be displayed in the order that it is stored. If there is no Rate subchunk, then each bitmap displayed by the length of time specified by the DisplayRate field in the Header subchunk.

If a Sequence subchunk is present, the display order of the bitmaps will need to be assigned. For example, an ANI file that contains four bitmaps (implicitly indexed as 0, 1, 2, and 3), but no Sequence subchunk, will play a four-step animation and display the bitmaps in the order of 0, 1, 2, and 3.

A Sequence subchunk makes it possible to display the bitmaps in different sequences and to use a bitmap more than once in a single playing of the animation. For example, a Sequence subchunk may indicate the same four bitmaps are played in a nine-step animation in the following order: 0, 1, 4, 3, 2, 4, 3, 2, 1.

If a Rate subchunk is present, then the steps in the animation are displayed using the jif values it contains. If there are nine steps in the animation, then the Rate subchunk will contain nine rate values. They might be all the same, in which case a single rate value could have been stored in the DisplayRate Header field and the Rate chunk not even created. But, if a Rate subchunk is present, it is likely that one or more rate values will be different.

Several other things to note are that animated cursors always play in a loop. There is no way to specify "one play only", or "play forwards and backwards". And playing may stop at any frame, as determined by the program controlling the cursor display.

For Further information

For further information about the Microsoft RIFF format, see the specification included on the CD_ROM that accompanies this book.

The primary sources of RIFF information are the Microsoft Multimedia Registration Kit (MRK), the Microsoft Windows Software Development Kit (SDK), and the Microsoft Developer Network Library (MSDN) CD-ROMs.

The Microsoft Multimedia Registration Kit is used to register new multimedia components for use with the Microsoft Windows operating systems. The MRK is distributed as an MS-DOS self-extracting archive and is available on the EAFF CR-ROM and also at:

ftp://ftp.microsoft.com/softlib/mslfiles/mdrk.exe

The MRK (revision 3.0) contains the following Microsoft Multimedia Standards Update documents (April 15, 1994, Revision 3.0):

The Windows SDK header file MMREG.H is also included in the MRK and contains the definitions of many RIFF structures and constants.

The Win16 and Win32 SDKs are distributed with the Microsoft Visual C++ compiler and the MSDN CR-ROMs. These SDKs also contains several header files (MMREG.H, MMSYSTEM.H, VFW.H, and WINUSER.H, etc.) that contain information related to RIFF, and are required for multimedia programming under Windows.

You can find the SDK documents on the MSDN Library CD-ROMs. The MSDN Library is only available by subscription However, Microsoft has made the October 1995 MSDN library available at:

ftp://ftp.microsoft.com/developr/MSDN/OctCD/

Other MSDN Library files of interest are:

SAMPLE: Multimedia Registration Kit, revision 3.0
PSS ID Number: Q120253, 02-15-96

MSDN Frequently Asked Questions (FAQ)
PSS ID Number: Q116437, 02-16-1996
ftp://ftp.microsoft.com/developr/MSDN/kb/Q116/4/37.txt
http://www.microsoft.com/msdn/msdnfaq.htm

The Win16 and Win32 SDKs also contain two sample applications that are necessary for understanding animated cursors. They are ANIEDIT, an animated cursor file editor, and IMAGEDIT, an icon and cursor bitmap editor. Both of these sample applications are distributed with complete source code, but no compiled binaries. The binaries are only distributed with the Windows 95 and Windows NT Resource kits.

The Video for Windows SDK contains the MS-DOS utility RIFFWALK which produces a formatted listing of the contents of a RIFF file. This is an excellent utility for examining not only the data but also the structure of any RIFF file.

You can contact the Microsoft MSDN group at:

Microsoft Developers Network
Voice: 206-936-2490
Email: msdn@microsoft.com
WWW: http://www.microsoft.com/msdn/

And here's the addresses of the Microsoft multimedia people. Try getting what you need from their FTP and Web sites first:

Microsoft Corporation
Attn: Heidi Breslauer
Multimedia Technology Group
One Microsoft Way
Redmond, WA 98052-6399
Voice: 800-227-4679 x11771
FAX: 206-936-7329
Email: mmreg@microsoft.com
FTP: ftp://ftp.microsoft.com/
WWW: http://www.microsoft.com/
CIS: WINSDK forum



Copyright © 1996, 1994 O'Reilly & Associates, Inc. All Rights Reserved.