Back to lectricstuff.co.uk

Sample code to parse an AVI header - uncompressed files, no audio, as created by VirtualDub. Supports 8.16 and 24bits per pixel

These are pulled from working applications - there will be bits you will need to tidy up but should be obvious-ish, and there will be some superfluous stuff .

Cross-reference between C and VB versions if necessary to figure out details.

After calling, the variable avi_start will hold the file offset of the first frame. Subsequent frames will be at (framesize)+8 byte intervals from there

VB6 version

C version

---------------------------------------------------------------------------------------------------------------------------------------------

Visual Basic 6 :

Dim avi_start As Long, avi_bpp As Long, avi_frames As Long, avi_framesize As Long, aviname As String

Private Function fgw(ofs As Long) As Long

' gets a 32 bit value form file
Dim l As Long
Seek #1, ofs + 1
Get #1, , l

fgw = l
End Function


Private Function openavi() As Integer
Dim avibad As Integer
Dim e As String, s As String, ff As String, a As Integer
Dim l As Long, i As Integer, j As Integer
Dim fr As Long, smval As Long
Dim ll As Long, headerbuf(0 To 64) As Byte
Dim fp As Long, cn As Long, cl As Long, X As Long, Y As Long
Dim ox As Long, oy As Long, obpp As Long, bpp As Long, flen As Long
Dim smv As Long
avibad = 1

avi_start = 0

CommonDialog1.FileName = ""
CommonDialog1.DialogTitle = "Open AVI File"
CommonDialog1.CancelError = True
CommonDialog1.DefaultExt = ".avi"
CommonDialog1.Filter = "Uncompressed 5:6:5 AVI files (*.AVI)|*.AVI"
On Error GoTo loaderror ' in case of cancel
CommonDialog1.ShowOpen
bfname = CommonDialog1.FileName
aviname = bfname
On Error Resume Next
Open bfname For Input As #1
If Err.Number <> 0 Then MsgBox "Error opening " + bfname, , "Doh!"
On Error GoTo 0
Close #1
Open bfname For Binary As #1

If fgw(8) <> &H20495641 Then MsgBox "Not an AVI File :" + f: GoTo badavi
fp = &HC
cn = fgw(fp)
cl = fgw(fp + 4)

If cn <> &H5453494C Then MsgBox ("Header LIST not found " + f): GoTo badavi 'hdrl
If fgw(fp + 8) <> &H6C726468 Then MsgBox ("hdr chunk not found " + f): GoTo badavi
fr = fgw(fp + &H14) ' frame rate in microsecs

avi_frames = fgw(fp + &H24) ' frames in file

ox = 240: oy = 240 ' desired size for error check
obpp = 2

X = fgw(fp + &H34)
Y = fgw(fp + &H38)
Do
fp = fp + cl + 8 ' -> next chunk
cn = fgw(fp) ' name of chunk
cl = fgw(fp + 4) ' length

Loop Until (cn = &H5453494C) Or fp > LOF(1)
If cn <> &H5453494C Then MsgBox ("Stream LIST not found " + f): GoTo badavi 'hdrl

If fgw(fp + 8) <> &H69766F6D Then MsgBox ("movi chunk not found " + f): GoTo badavi
fp = fp + 12

If fgw(fp) <> &H63643030 And fgw(fp) <> &H62643030 Then MsgBox "00dc marker not found " + f: GoTo badavi
flen = fgw(fp + 4)
bpp = flen / (X * Y) ' bytes per pixel
If X <> ox Or Y <> oy Then MsgBox ("Not correct size (Appears to be " + Format(X, "0") + " x " + Format(Y, "0") + " Pixels) * " + Format(bpp, "0") + " Bytes/pixel " + f): GoTo badavi
If bpp < obpp Then MsgBox "AVI has insufficient colour depth AVI =" + Format(bpp, "0") + " Want >= " + Format(obpp, "0"): GoTo badavi
avi_start = fp + 8 ' globals for play
avi_bpp = bpp

avi_framesize = X * Y * avi_bpp
avibad = 0
loaderror:
badavi:
If avibad <> 0 Then Close #1
openavi = avibad
End Function

 

___________________________________________________________________________________________________

C version ( Microchip C30) using Microchip filesystem library
Note this is expecting a monochrome AVI - tweak bpp value check for 16bpp - see VB code for reference if necessary

 

/=========================================================================== avi parsing stuff

unsigned long framerate,framelen,totframes,avistart,framenum;
unsigned int xpixels,ypixels;
FSFILE *fptr;


//=================================================================================
char fileerror=0;


unsigned long fgw(unsigned long offset)
{ // get word from offset in file
unsigned long d;

FSfseek(fptr,offset,SEEK_SET);
FSfread(&d,1,4,fptr);

return(d);
}

#define avihdrlen 0x80 // buffer for reading AVI header
char avibuf[avihdrlen];

unsigned long mgw(unsigned long offset) // return long at arbitary alignment from avi buffer, faster than using fgw
{
return(avibuf[offset]|((unsigned long)avibuf[offset+1]<<8)|((unsigned long)avibuf[offset+2]<<16)|((unsigned long)avibuf[offset+3]<<24));
}

//================================================================= openavi
char openavi(char fnum)//

{
char filenamebuf[13];
unsigned int xp;
unsigned long chunknum,chunklen,fileofs;

fptr=NULL;
filenamebuf[0]='F';
filenamebuf[1]=(fnum/10)+'0';
filenamebuf[2]=(fnum%10)+'0';
filenamebuf[3]='.';
filenamebuf[4]='A';
filenamebuf[5]='V';
filenamebuf[6]='I';
filenamebuf[7]=0;
fptr=FSfopen(filenamebuf,READ);
if(fptr==NULL) return(1); // file not found
FSfread(&avibuf,1,avihdrlen,fptr); // read first block to RAM buffer to avoid lots of slow seeks and short reads, saves ~250mS

if(mgw(8) != 0x20495641) return(2); // not AVI
fileofs=0x0c;
chunknum=mgw(fileofs);
chunklen=mgw(fileofs+4);
if(chunknum!=0x5453494c) return(2); // Header LIST not found
if(mgw(fileofs+8)!=0x6c726468) return(2); // hdr chunk not found
framerate=mgw(fileofs+0x14); // frame period in microseconds
totframes=mgw(fileofs+0x24); // total frames
xpixels=mgw(fileofs+0x34);
ypixels=mgw(fileofs+0x38);
do {
fileofs=fileofs+chunklen+8;
chunknum=fgw(fileofs);
chunklen=fgw(fileofs+4);
} while ((chunknum!=0x5453494c) && (!FSfeof(fptr)));
if(chunknum!=0x5453494c) return(2); //Stream LIST not found
if(fgw(fileofs+8)!=0x69766f6d) return(2); // movi chunk not found
fileofs+=12;
chunknum=fgw(fileofs);
if((chunknum&0xfeffffff)!=0x62643030) return(2); // 00dc not found
framelen=fgw(fileofs+4);
xp=xpixels;while(xp&3) xp++; // round up to 4 bytes
if(framelen!=xp*ypixels) return(3); // not 8bpp
if(framelen>dmxbufsize-8) return(4); // frame too big for buffer

if(xpixels!=linelength_avi) return(5);
if(ypixels!=height) return(6);

avistart=fileofs+8;
framenum=0;
return(0);
}