530 lines
20 KiB
C
530 lines
20 KiB
C
/****************************************************************************/
|
|
/* */
|
|
/* AVIFFMT.H - Include file for working with AVI files */
|
|
/* */
|
|
/* Note: You must include WINDOWS.H and MMSYSTEM.H before */
|
|
/* including this file. */
|
|
/* */
|
|
/* Copyright (c) 1991-1992, Microsoft Corp. All rights reserved. */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
*
|
|
* An AVI file is the following RIFF form:
|
|
*
|
|
* RIFF('AVI'
|
|
* LIST('hdrl'
|
|
* avih(<MainAVIHeader>)
|
|
* LIST ('strl'
|
|
* strh(<Stream header>)
|
|
* strf(<Stream format>)
|
|
* ... additional header data
|
|
* LIST('movi'
|
|
* { LIST('rec'
|
|
* SubChunk...
|
|
* )
|
|
* | SubChunk } ....
|
|
* )
|
|
* [ <AVIIndex> ]
|
|
* )
|
|
*
|
|
* The first two characters of each chunk are the track number.
|
|
* SubChunk = { xxdh(<AVI DIB header>)
|
|
* | xxdb(<AVI DIB bits>)
|
|
* | xxdc(<AVI compressed DIB bits>)
|
|
* | xxpc(<AVI Palette Change>)
|
|
* | xxwb(<AVI WAVE bytes>)
|
|
* | xxws(<AVI Silence record>)
|
|
* | xxmd(<MIDI data>)
|
|
* | additional custom chunks }
|
|
*
|
|
*/
|
|
/*
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
* We need a better description of the AVI file header here.
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
*
|
|
* The grouping into LIST 'rec' chunks implies only that the contents of
|
|
* the chunk should be read into memory at the same time. This
|
|
* grouping is only necessary for interleaved files.
|
|
*
|
|
* For loading efficiency, the beginning of each LIST 'rec' chunk may
|
|
* be aligned on a 2K boundary. (Actually, the beginning of the LIST
|
|
* chunk should be 12 bytes before a 2K boundary, so that the data chunks
|
|
* inside the LIST chunk are aligned.)
|
|
*
|
|
* If the AVI file is being played from CD-ROM in, it is recommended that
|
|
* the file be padded.
|
|
*
|
|
* Limitations for the Alpha release:
|
|
* If the AVI file has audio, each record LIST must contain exactly
|
|
* one audio chunk, which must be the first chunk.
|
|
* Each record must contain exactly one video chunk (possibly preceded
|
|
* by one or more palette change chunks).
|
|
* No wave format or DIB header chunks may occur outside of the header.
|
|
*/
|
|
|
|
#ifndef _INC_AVIFFMT
|
|
#define _INC_AVIFFMT
|
|
|
|
#ifndef RC_INVOKED
|
|
#pragma pack(1) /* Assume byte packing throughout */
|
|
#endif /* RC_INVOKED */
|
|
|
|
#ifndef mmioFOURCC
|
|
#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
|
|
( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \
|
|
( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) )
|
|
#endif
|
|
|
|
/* Macro to make a TWOCC out of two characters */
|
|
#ifndef aviTWOCC
|
|
#define aviTWOCC(ch0, ch1) ((WORD)(BYTE)(ch0) | ((WORD)(BYTE)(ch1) << 8))
|
|
#endif
|
|
|
|
typedef WORD TWOCC;
|
|
|
|
/* form types, list types, and chunk types */
|
|
#define formtypeAVI mmioFOURCC('A', 'V', 'I', ' ')
|
|
#define listtypeAVIHEADER mmioFOURCC('h', 'd', 'r', 'l')
|
|
#define ckidAVIMAINHDR mmioFOURCC('a', 'v', 'i', 'h')
|
|
#define listtypeSTREAMHEADER mmioFOURCC('s', 't', 'r', 'l')
|
|
#define ckidSTREAMHEADER mmioFOURCC('s', 't', 'r', 'h')
|
|
#define ckidSTREAMFORMAT mmioFOURCC('s', 't', 'r', 'f')
|
|
#define ckidSTREAMHANDLERDATA mmioFOURCC('s', 't', 'r', 'd')
|
|
|
|
#define listtypeAVIMOVIE mmioFOURCC('m', 'o', 'v', 'i')
|
|
#define listtypeAVIRECORD mmioFOURCC('r', 'e', 'c', ' ')
|
|
|
|
#define ckidAVINEWINDEX mmioFOURCC('i', 'd', 'x', '1')
|
|
|
|
/*
|
|
** Here are some stream types. Currently, only audio and video
|
|
** are supported.
|
|
*/
|
|
#define streamtypeVIDEO mmioFOURCC('v', 'i', 'd', 's')
|
|
#define streamtypeAUDIO mmioFOURCC('a', 'u', 'd', 's')
|
|
#define streamtypeMIDI mmioFOURCC('m', 'i', 'd', 's')
|
|
#define streamtypeTEXT mmioFOURCC('t', 'x', 't', 's')
|
|
|
|
/*
|
|
** Here are some compression types.
|
|
*/
|
|
#define comptypeRLE0 mmioFOURCC('R','L','E','0')
|
|
#define comptypeRLE mmioFOURCC('R','L','E',' ')
|
|
#define comptypeDIB mmioFOURCC('D','I','B',' ')
|
|
|
|
#define cktypeDIBbits aviTWOCC('d', 'b')
|
|
#define cktypeDIBcompressed aviTWOCC('d', 'c')
|
|
#define cktypeDIBhalf aviTWOCC('d', 'x')
|
|
#define cktypePALchange aviTWOCC('p', 'c')
|
|
#define cktypeWAVEbytes aviTWOCC('w', 'b')
|
|
#define cktypeWAVEsilence aviTWOCC('w', 's')
|
|
|
|
#define cktypeMIDIdata aviTWOCC('m', 'd')
|
|
|
|
#define cktypeDIBheader aviTWOCC('d', 'h')
|
|
#define cktypeWAVEformat aviTWOCC('w', 'f')
|
|
|
|
#define ckidAVIPADDING mmioFOURCC('J', 'U', 'N', 'K')
|
|
#define ckidOLDPADDING mmioFOURCC('p', 'a', 'd', 'd')
|
|
|
|
|
|
/*
|
|
** Useful macros
|
|
*/
|
|
#define ToHex(n) ((BYTE) (((n) > 9) ? ((n) - 10 + 'A') : ((n) + '0')))
|
|
#define FromHex(n) (((n) >= 'A') ? ((n) + 10 - 'A') : ((n) - '0'))
|
|
|
|
/* Macro to get stream number out of a FOURCC ckid */
|
|
#define StreamFromFOURCC(fcc) ((WORD) ((FromHex(LOBYTE(LOWORD(fcc))) << 4) + \
|
|
(FromHex(HIBYTE(LOWORD(fcc))))))
|
|
|
|
/* Macro to get TWOCC chunk type out of a FOURCC ckid */
|
|
#define TWOCCFromFOURCC(fcc) HIWORD(fcc)
|
|
|
|
/* Macro to make a ckid for a chunk out of a TWOCC and a stream number
|
|
** from 0-255.
|
|
**
|
|
** Warning: This is a nasty macro, and MS C 6.0 compiles it incorrectly
|
|
** if optimizations are on. Ack.
|
|
*/
|
|
#define MAKEAVICKID(tcc, stream) \
|
|
MAKELONG((ToHex((stream) & 0x0f) << 8) | ToHex(((stream) & 0xf0) >> 4), tcc)
|
|
|
|
|
|
|
|
/*
|
|
** Main AVI File Header
|
|
*/
|
|
|
|
/* flags for use in <dwFlags> in AVIFileHdr */
|
|
#define AVIF_HASINDEX 0x00000010 // Index at end of file?
|
|
#define AVIF_MUSTUSEINDEX 0x00000020
|
|
#define AVIF_ISINTERLEAVED 0x00000100
|
|
#define AVIF_VARIABLESIZEREC 0x00000200
|
|
#define AVIF_NOPADDING 0x00000400
|
|
#define AVIF_WASCAPTUREFILE 0x00010000
|
|
#define AVIF_COPYRIGHTED 0x00020000
|
|
|
|
/* The AVI File Header LIST chunk should be padded to this size */
|
|
#define AVI_HEADERSIZE 2048 // size of AVI header list
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL AVI_FFMT
|
|
*
|
|
* @types MainAVIHeader | The <t MainAVIHeader> structure contains
|
|
* global information for the entire AVI file. It is contained
|
|
* within an 'avih' chunk within the LIST 'hdrl' chunk at the
|
|
* beginning of an AVI RIFF file.
|
|
*
|
|
* @field DWORD | dwMicroSecPerFrame | Specifies the number of
|
|
* microseconds between frames.
|
|
*
|
|
* @field DWORD | dwMaxBytesPerSec | Specifies the approximate
|
|
* maximum data rate of file.
|
|
*
|
|
* @field DWORD | dwReserved1 | Reserved. (This field should be set to 0.)
|
|
*
|
|
* @field DWORD | dwFlags | Specifies any applicable flags.
|
|
* The following flags are defined:
|
|
*
|
|
* @flag AVIF_HASINDEX | Indicates
|
|
* the AVI file has an 'idx1' chunk containing an index
|
|
* at the end of the file. For good performance, all AVI
|
|
* files should contain an index.
|
|
*
|
|
* @flag AVIF_MUSTUSEINDEX | Indicates that the
|
|
* index, rather than the physical ordering of the chunks
|
|
* in the file, should be used to determine the order of
|
|
* presentation of the data. For example, this could be
|
|
* used for creating a list frames for editing.
|
|
*
|
|
* @flag AVIF_ISINTERLEAVED | Indicates
|
|
* the AVI file is interleaved.
|
|
*
|
|
* @flag AVIF_WASCAPTUREFILE | Indicates
|
|
* the AVI file is a specially allocated file used for
|
|
* capturing real-time video. Applications should warn the
|
|
* user before writing over a file with this flag set
|
|
* because the user probably defragmented
|
|
* this file.
|
|
*
|
|
* @flag AVIF_COPYRIGHTED | Indicates the
|
|
* AVI file contains copyrighted data and software.
|
|
* When this flag is used,
|
|
* software should not permit the data to be duplicated.
|
|
*
|
|
* @field DWORD | dwTotalFrames | Specifies the number of
|
|
* frames of data in file.
|
|
*
|
|
* @field DWORD | dwInitialFrames | Specifies the initial frame
|
|
* for interleaved files. Non-interleaved files should specify
|
|
* zero.
|
|
*
|
|
* @field DWORD | dwStreams | Specifies the number of streams in the file.
|
|
* For example, a file with audio and video has 2 streams.
|
|
*
|
|
* @field DWORD | dwSuggestedBufferSize | Specifies the suggested
|
|
* buffer size for reading the file. Generally, this size
|
|
* should be large enough to contain the largest chunk in
|
|
* the file. If set to zero, or if it is too small, the playback
|
|
* software will have to reallocate memory during playback
|
|
* which will reduce performance.
|
|
*
|
|
* For an interleaved file, this buffer size should be large
|
|
* enough to read an entire record and not just a chunk.
|
|
*
|
|
* @field DWORD | dwWidth | Specifies the width of the AVI file in pixels.
|
|
*
|
|
* @field DWORD | dwHeight | Specifies the height of the AVI file in pixels.
|
|
*
|
|
* @field DWORD | dwScale | This field is used with
|
|
* <e MainAVIHeader.dwRate> to specify the time scale that
|
|
* applies to the AVI file. In addition, each stream
|
|
* can have its own time scale.
|
|
*
|
|
* Dividing <e MainAVIHeader.dwRate> by <e AVIStreamHeader.dwScale>
|
|
* gives the number of samples per second.
|
|
*
|
|
* @field DWORD | dwRate | See <e MainAVIHeader.dwScale>.
|
|
*
|
|
* @field DWORD | dwStart | Specifies the starting time of the AVI file.
|
|
* The units are defined by <e MainAVIHeader.dwRate> and
|
|
* <e MainAVIHeader.dwScale>. This field is usually set to zero.
|
|
*
|
|
* @field DWORD | dwLength | Specifies the length of the AVI file.
|
|
* The units are defined by <e AVIStreamHeader.dwRate> and
|
|
* <e AVIStreamHeader.dwScale>. This length is returned by MCIAVI when
|
|
* using the frames time format.
|
|
*
|
|
****************************************************************************/
|
|
|
|
typedef struct
|
|
{
|
|
DWORD dwMicroSecPerFrame; // frame display rate (or 0L)
|
|
DWORD dwMaxBytesPerSec; // max. transfer rate
|
|
DWORD dwPaddingGranularity; // pad to multiples of this
|
|
// size; normally 2K.
|
|
DWORD dwFlags; // the ever-present flags
|
|
DWORD dwTotalFrames; // # frames in file
|
|
DWORD dwInitialFrames;
|
|
DWORD dwStreams;
|
|
DWORD dwSuggestedBufferSize;
|
|
|
|
DWORD dwWidth;
|
|
DWORD dwHeight;
|
|
|
|
/* Do we want the stuff below for the whole movie, or just
|
|
** for the individual streams?
|
|
*/
|
|
DWORD dwScale;
|
|
DWORD dwRate; /* dwRate / dwScale == samples/second */
|
|
DWORD dwStart; /* Is this always zero? */
|
|
DWORD dwLength; /* In units above... */
|
|
} MainAVIHeader;
|
|
|
|
|
|
/*
|
|
** Stream header
|
|
*/
|
|
|
|
/* !!! Do we need to distinguish between discrete and continuous streams? */
|
|
|
|
#define AVISF_DISABLED 0x00000001
|
|
#define AVISF_VIDEO_PALCHANGES 0x00010000
|
|
/* Do we need identity palette support? */
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL AVI_FFMT
|
|
*
|
|
* @types AVIStreamHeader | The <t AVIStreamHeader> structure contains
|
|
* header information for a single stream of an file. It is contained
|
|
* within an 'strh' chunk within a LIST 'strl' chunk that is itself
|
|
* contained within the LIST 'hdrl' chunk at the beginning of
|
|
* an AVI RIFF file.
|
|
*
|
|
* @field FOURCC | fccType | Contains a four-character code which specifies
|
|
* the type of data contained in the stream. The following values are
|
|
* currently defined:
|
|
*
|
|
* @flag 'vids' | Indicates the stream contains video data. The stream
|
|
* format chunk contains a <t BITMAPINFO> structure which can include
|
|
* palette information.
|
|
*
|
|
* @flag 'auds' | Indicates the stream contains video data. The stream
|
|
* format chunk contains a <t WAVEFORMATEX> or <t PCMWAVEFORMAT>
|
|
* structure.
|
|
*
|
|
* New data types should be registered with the <MI>Multimedia Developer
|
|
* Registration Kit<D>.
|
|
*
|
|
* @field FOURCC | fccHandler | Contains a four-character code that
|
|
* identifies a specific data handler.
|
|
*
|
|
* @field DWORD | dwFlags | Specifies any applicable flags.
|
|
* The bits in the high-order word of these flags
|
|
* are specific to the type of data contained in the stream.
|
|
* The following flags are currently defined:
|
|
*
|
|
* @flag AVISF_DISABLED | Indicates
|
|
* this stream should not be enabled by default.
|
|
*
|
|
* @flag AVISF_VIDEO_PALCHANGES | Indicates
|
|
* this video stream contains palette changes. This flag warns
|
|
* the playback software that it will need to animate the
|
|
* palette.
|
|
*
|
|
* @field DWORD | dwReserved1 | Reserved. (Should be set to 0.)
|
|
*
|
|
* @field DWORD | dwInitialFrames | Reserved for interleaved files.
|
|
* (Set this to 0 for non-interleaved files.)
|
|
*
|
|
* @field DWORD | dwScale | This field is used together with
|
|
* <e AVIStreamHeader.dwRate> to specify the time scale that
|
|
* this stream will use.
|
|
*
|
|
* Dividing <e AVIStreamHeader.dwRate> by <e AVIStreamHeader.dwScale>
|
|
* gives the number of samples per second.
|
|
*
|
|
* For video streams, this rate should be the frame rate.
|
|
*
|
|
* For audio streams, this rate should correspond to the time needed for
|
|
* <e WAVEFORMATEX.nBlockAlign> bytes of audio, which for PCM audio simply
|
|
* reduces to the sample rate.
|
|
*
|
|
* @field DWORD | dwRate | See <e AVIStreamHeader.dwScale>.
|
|
*
|
|
* @field DWORD | dwStart | Specifies the starting time of the AVI file.
|
|
* The units are defined by the
|
|
* <e MainAVIHeader.dwRate> and <e MainAVIHeader.dwScale> fields
|
|
* in the main file header. Normally, this is zero, but it can
|
|
* specify a delay time for a stream which does not start concurrently
|
|
* with the file.
|
|
*
|
|
* Note: The 1.0 release of the AVI tools does not support a non-zero
|
|
* starting time.
|
|
*
|
|
* @field DWORD | dwLength | Specifies the length of this stream.
|
|
* The units are defined by the
|
|
* <e AVIStreamHeader.dwRate> and <e AVIStreamHeader.dwScale>
|
|
* fields of the stream's header.
|
|
*
|
|
* @field DWORD | dwSuggestedBufferSize | Suggests how large a buffer
|
|
* should be used to read this stream. Typically, this contains a
|
|
* value corresponding to the largest chunk present in the stream.
|
|
* Using the correct buffer size makes playback more efficient.
|
|
* Use zero if you do not know the correct buffer size.
|
|
*
|
|
* @field DWORD | dwQuality | Specifies an indicator of the quality
|
|
* of the data in the stream. Quality is
|
|
* represented as a number between 0 and 10000. For compressed data,
|
|
* this typically represent the value of the quality parameter
|
|
* passed to the compression software.
|
|
*
|
|
* @field DWORD | dwSampleSize | Specifies the size of a single sample
|
|
* of data. This is set to
|
|
* zero if the samples can vary in size. If this number is non-zero, then
|
|
* multiple samples of data can be grouped into a single chunk within
|
|
* the file. If it is zero, each sample of data (such as a video
|
|
* frame) must be in a separate chunk.
|
|
*
|
|
* For video streams, this number is typically zero, although it
|
|
* can be non-zero if all video frames are the same size.
|
|
*
|
|
* For audio streams, this number should be the same as the
|
|
* <e WAVEFORMATEX.nBlockAlign> field of the <t WAVEFORMATEX> structure
|
|
* describing the audio.
|
|
*
|
|
****************************************************************************/
|
|
typedef struct {
|
|
FOURCC fccType;
|
|
FOURCC fccHandler;
|
|
DWORD dwFlags; /* Contains AVITF_* flags */
|
|
WORD wPriority;
|
|
WORD wLanguage;
|
|
DWORD dwInitialFrames;
|
|
DWORD dwScale;
|
|
DWORD dwRate; /* dwRate / dwScale == samples/second */
|
|
DWORD dwStart;
|
|
DWORD dwLength; /* In units above... */
|
|
|
|
// new....
|
|
DWORD dwSuggestedBufferSize;
|
|
DWORD dwQuality;
|
|
DWORD dwSampleSize;
|
|
RECT rcFrame; /* does each frame need this? */
|
|
|
|
/* additional type-specific data goes in StreamInfo chunk */
|
|
|
|
/* For video: position within rectangle... */
|
|
/* For audio: volume? stereo channel? */
|
|
} AVIStreamHeader;
|
|
|
|
typedef struct {
|
|
RECT rcFrame;
|
|
} AVIVideoStreamInfo;
|
|
|
|
typedef struct {
|
|
WORD wLeftVolume; // !!! Range?
|
|
WORD wRightVolume;
|
|
DWORD dwLanguage; // !!! Is there a standard representation of this?
|
|
} AVIAudioStreamInfo;
|
|
|
|
|
|
#define AVIIF_LIST 0x00000001L // chunk is a 'LIST'
|
|
#define AVIIF_TWOCC 0x00000002L // ckid is a TWOCC?
|
|
#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame.
|
|
#define AVIIF_FIRSTPART 0x00000020L // this frame is the start of a partial frame.
|
|
#define AVIIF_LASTPART 0x00000040L // this frame is the end of a partial frame.
|
|
#define AVIIF_MIDPART (AVIIF_LASTPART|AVIIF_FIRSTPART)
|
|
#define AVIIF_NOTIME 0x00000100L // this frame doesn't take any time
|
|
|
|
#define AVIIF_COMPUSE 0x0FFF0000L // these bits are for compressor use
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL AVI_FFMT
|
|
*
|
|
* @types AVIINDEXENTRY | The AVI file index consists of an array
|
|
* of <t AVIINDEXENTRY> structures contained within an 'idx1'
|
|
* chunk at the end of an AVI file. This chunk follows the main LIST 'movi'
|
|
* chunk which contains the actual data.
|
|
*
|
|
* @field DWORD | ckid | Specifies a four-character code corresponding
|
|
* to the chunk ID of a data chunk in the file.
|
|
*
|
|
* @field DWORD | dwFlags | Specifies any applicable flags.
|
|
* The flags in the low-order word are reserved for AVI,
|
|
* while those in the high-order word can be used
|
|
* for stream- and compressor/decompressor-specific information.
|
|
*
|
|
* The following values are currently defined:
|
|
*
|
|
* @flag AVIIF_LIST | Indicates the specified
|
|
* chunk is a 'LIST' chunk, and the <e AVIINDEXENTRY.ckid>
|
|
* field contains the list type of the chunk.
|
|
*
|
|
* @flag AVIIF_KEYFRAME | Indicates this chunk
|
|
* is a key frame. Key frames do not require
|
|
* additional preceding chunks to be properly decoded.
|
|
*
|
|
* @flag AVIIF_NOTIME | Indicates this chunk should have no effect
|
|
* on timing or calculating time values based on the number of chunks.
|
|
* For example, palette change chunks in a video stream
|
|
* should have this flag set, so that they are not counted
|
|
* as taking up a frame's worth of time.
|
|
*
|
|
* @field DWORD | dwChunkOffset | Specifies the position in the file of the
|
|
* specified chunk. The position value includes the eight byte RIFF header.
|
|
*
|
|
* @field DWORD | dwChunkLength | Specifies the length of the
|
|
* specified chunk. The length value does not include the eight
|
|
* byte RIFF header.
|
|
*
|
|
****************************************************************************/
|
|
typedef struct
|
|
{
|
|
DWORD ckid;
|
|
DWORD dwFlags;
|
|
DWORD dwChunkOffset; // Position of chunk
|
|
DWORD dwChunkLength; // Length of chunk
|
|
} AVIINDEXENTRY;
|
|
|
|
|
|
/*
|
|
** Palette change chunk
|
|
**
|
|
** Used in video streams.
|
|
*/
|
|
typedef struct
|
|
{
|
|
BYTE bFirstEntry; /* first entry to change */
|
|
BYTE bNumEntries; /* # entries to change (0 if 256) */
|
|
WORD wFlags; /* Mostly to preserve alignment... */
|
|
PALETTEENTRY peNew[]; /* New color specifications */
|
|
} AVIPALCHANGE;
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL AVI_FFMT
|
|
*
|
|
* @types AVIPALCHANGE | The <t AVIPALCHANGE> structure is used in
|
|
* video streams containing palettized data to indicate the
|
|
* palette should change for subsequent video data.
|
|
*
|
|
* @field BYTE | bFirstEntry | Specifies the first palette entry to change.
|
|
*
|
|
* @field BYTE | bNumEntries | Specifies the number of entries to change.
|
|
*
|
|
* @field WORD | wFlags | Reserved. (This should be set to 0.)
|
|
*
|
|
* @field PALETTEENTRY | peNew | Specifies an array of new palette entries.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef RC_INVOKED
|
|
#pragma pack() /* Revert to default packing */
|
|
#endif /* RC_INVOKED */
|
|
|
|
#endif /* INC_AVIFFMT */
|