/****************************************************************************/
/*                                                                          */
/*        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 */