2 * Very simple AVIPLAYER
4 * Copyright 1999 Marcus Meissner
7 * - plays .avi streams, video only
8 * - requires MicroSoft avifil32.dll and builtin msvfw32.dll.
11 * - audio support (including synchronization etc)
12 * - replace DirectDraw by a 'normal' window, including dithering, controls
16 * - no time scheduling, video plays too fast using DirectDraw/XF86DGA
17 * - requires DirectDraw with all disadvantages.
32 int PASCAL WinMain (HANDLE hInstance, HANDLE prev, LPSTR cmdline, int show)
34 int bytesline,i,n,pos;
37 BITMAPINFOHEADER *bmi;
39 HMODULE avifil32 = LoadLibrary("avifil32.dll");
41 PAVISTREAM vids=NULL,auds=NULL;
44 PGETFRAME vidgetframe=NULL;
47 LPDIRECTDRAWSURFACE dsurf;
48 LPDIRECTDRAWPALETTE dpal;
49 PALETTEENTRY palent[256];
52 void (WINAPI *fnAVIFileInit)(void);
53 void (WINAPI *fnAVIFileExit)(void);
54 ULONG (WINAPI *fnAVIFileRelease)(PAVIFILE);
55 ULONG (WINAPI *fnAVIStreamRelease)(PAVISTREAM);
56 HRESULT (WINAPI *fnAVIFileOpen)(PAVIFILE * ppfile,LPCTSTR szFile,UINT uMode,LPCLSID lpHandler);
57 HRESULT (WINAPI *fnAVIFileInfo)(PAVIFILE ppfile,AVIFILEINFO *afi,LONG size);
58 HRESULT (WINAPI *fnAVIFileGetStream)(PAVIFILE ppfile,PAVISTREAM *afi,DWORD fccType,LONG lParam);
59 HRESULT (WINAPI *fnAVIStreamInfo)(PAVISTREAM iface,AVISTREAMINFO *afi,LONG size);
60 HRESULT (WINAPI *fnAVIStreamReadFormat)(PAVISTREAM iface,LONG pos,LPVOID format,LPLONG size);
61 PGETFRAME (WINAPI *fnAVIStreamGetFrameOpen)(PAVISTREAM iface,LPBITMAPINFOHEADER wanted);
62 LPVOID (WINAPI *fnAVIStreamGetFrame)(PGETFRAME pg,LONG pos);
63 HRESULT (WINAPI *fnAVIStreamGetFrameClose)(PGETFRAME pg);
65 #define XX(x) fn##x = (void*)GetProcAddress(avifil32,#x);assert(fn##x);
67 # define XXT(x) fn##x = (void*)GetProcAddress(avifil32,#x##"W");assert(fn##x);
69 # define XXT(x) fn##x = (void*)GetProcAddress(avifil32,#x##"A");assert(fn##x);
71 /* non character dependend routines: */
75 XX (AVIFileGetStream);
76 XX (AVIStreamRelease);
77 XX (AVIStreamReadFormat);
78 XX (AVIStreamGetFrameOpen);
79 XX (AVIStreamGetFrame);
80 XX (AVIStreamGetFrameClose);
90 if (-1==GetFileAttributes(cmdline)) {
91 fprintf(stderr,"Usage: aviplay <avifilename>\n");
94 hres = fnAVIFileOpen(&avif,cmdline,OF_READ,NULL);
96 fprintf(stderr,"AVIFileOpen: 0x%08lx\n",hres);
99 hres = fnAVIFileInfo(avif,&afi,sizeof(afi));
101 fprintf(stderr,"AVIFileInfo: 0x%08lx\n",hres);
104 for (n=0;n<afi.dwStreams;n++) {
108 hres = fnAVIFileGetStream(avif,&ast,0,n);
110 fprintf(stderr,"AVIFileGetStream %d: 0x%08lx\n",n,hres);
113 hres = fnAVIStreamInfo(ast,&asi,sizeof(asi));
115 fprintf(stderr,"AVIStreamInfo %d: 0x%08lx\n",n,hres);
118 fprintf(stderr,"[Stream %d: ",n);
119 buf[4]='\0';memcpy(buf,&(asi.fccType),4);
120 fprintf(stderr,"%s.",buf);
121 buf[4]='\0';memcpy(buf,&(asi.fccHandler),4);
122 fprintf(stderr,"%s, %s]\n",buf,asi.szName);
123 switch (asi.fccType) {
124 case streamtypeVIDEO:
127 case streamtypeAUDIO:
132 type[4]='\0';memcpy(type,&(asi.fccType),4);
134 fprintf(stderr,"Unhandled streamtype %s\n",type);
135 fnAVIStreamRelease(ast);
140 /********************* begin video setup ***********************************/
142 fprintf(stderr,"No video stream found. Good Bye.\n");
145 cnt = sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
146 bmi = HeapAlloc(GetProcessHeap(),0,cnt);
147 hres = fnAVIStreamReadFormat(vids,0,bmi,&cnt);
149 fprintf(stderr,"AVIStreamReadFormat vids: 0x%08lx\n",hres);
153 bmi->biCompression = 0; /* we want it in raw form, uncompressed */
154 /* recalculate the image size */
155 bmi->biSizeImage = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes*bmi->biHeight/8;
156 bytesline = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes/8;
157 vidgetframe = fnAVIStreamGetFrameOpen(vids,bmi);
159 fprintf(stderr,"AVIStreamGetFrameOpen: failed\n");
162 /********************* end video setup ***********************************/
164 /********************* begin display setup *******************************/
165 hres = DirectDrawCreate(NULL,&ddraw,NULL);
167 fprintf(stderr,"DirectDrawCreate: 0x%08lx\n",hres);
170 hres = ddraw->lpvtbl->fnSetDisplayMode(ddraw,bmi->biWidth,bmi->biHeight,bmi->biBitCount);
172 fprintf(stderr,"ddraw.SetDisplayMode: 0x%08lx (change resolution!)\n",hres);
175 dsdesc.dwSize=sizeof(dsdesc);
176 dsdesc.dwFlags = DDSD_CAPS;
177 dsdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
178 hres = ddraw->lpvtbl->fnCreateSurface(ddraw,&dsdesc,&dsurf,NULL);
180 fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres);
183 if (bmi->biBitCount==8) {
184 RGBQUAD *rgb = (RGBQUAD*)(bmi+1);
187 hres = ddraw->lpvtbl->fnCreatePalette(ddraw,DDPCAPS_8BIT,NULL,&dpal,NULL);
189 fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres);
192 dsurf->lpvtbl->fnSetPalette(dsurf,dpal);
193 for (i=0;i<bmi->biClrUsed;i++) {
194 palent[i].peRed = rgb[i].rgbRed;
195 palent[i].peBlue = rgb[i].rgbBlue;
196 palent[i].peGreen = rgb[i].rgbGreen;
198 dpal->lpvtbl->fnSetEntries(dpal,0,0,bmi->biClrUsed,palent);
201 /********************* end display setup *******************************/
207 LPBITMAPINFOHEADER lpbmi;
211 if (!(decodedframe=fnAVIStreamGetFrame(vidgetframe,pos++)))
213 lpbmi = (LPBITMAPINFOHEADER)decodedframe;
214 decodedbits = (LPVOID)(((DWORD)decodedframe)+lpbmi->biSize);
215 if (lpbmi->biBitCount == 8) {
216 /* cant detect palette change that way I think */
217 RGBQUAD *rgb = (RGBQUAD*)(lpbmi+1);
220 /* skip used colorentries. */
221 decodedbits+=bmi->biClrUsed*sizeof(RGBQUAD);
223 for (i=0;i<bmi->biClrUsed;i++) {
224 if ( (palent[i].peRed != rgb[i].rgbRed) ||
225 (palent[i].peBlue != rgb[i].rgbBlue) ||
226 (palent[i].peGreen != rgb[i].rgbGreen)
233 for (i=0;i<bmi->biClrUsed;i++) {
234 palent[i].peRed = rgb[i].rgbRed;
235 palent[i].peBlue = rgb[i].rgbBlue;
236 palent[i].peGreen = rgb[i].rgbGreen;
238 dpal->lpvtbl->fnSetEntries(dpal,0,0,bmi->biClrUsed,palent);
241 dsdesc.dwSize = sizeof(dsdesc);
242 hres = dsurf->lpvtbl->fnLock(dsurf,NULL,&dsdesc,DDLOCK_WRITEONLY,0);
244 fprintf(stderr,"dsurf.Lock: 0x%08lx\n",hres);
247 /* Argh. AVIs are upside down. */
248 for (i=0;i<dsdesc.dwHeight;i++) {
249 memcpy( dsdesc.y.lpSurface+(i*dsdesc.lPitch),
250 decodedbits+bytesline*(dsdesc.dwHeight-i-1),
254 dsurf->lpvtbl->fnUnlock(dsurf,dsdesc.y.lpSurface);
257 fnAVIStreamGetFrameClose(vidgetframe);
259 ((IUnknown*)dsurf)->lpvtbl->fnRelease((IUnknown*)dsurf);
260 ddraw->lpvtbl->fnRestoreDisplayMode(ddraw);
261 ((IUnknown*)ddraw)->lpvtbl->fnRelease((IUnknown*)ddraw);
262 if (vids) fnAVIStreamRelease(vids);
263 if (auds) fnAVIStreamRelease(auds);
264 fprintf(stderr,"%d frames at %g frames/s\n",pos,pos*1.0/(tend-tstart));
265 fnAVIFileRelease(avif);