Change the callback declarations to a safer format.
[wine] / programs / avitools / aviplay.c
1 /*
2  * Very simple AVIPLAYER
3  * 
4  * Copyright 1999 Marcus Meissner
5  * 
6  * Status:
7  *      - plays .avi streams, video only
8  *      - requires MicroSoft avifil32.dll and builtin msvfw32.dll.
9  *
10  * Todo:
11  *      - audio support (including synchronization etc)
12  *      - replace DirectDraw by a 'normal' window, including dithering, controls
13  *        etc.
14  *      
15  * Bugs:
16  *      - no time scheduling, video plays too fast using DirectDraw/XF86DGA 
17  *      - requires DirectDraw with all disadvantages.
18  */
19
20 #include <stdio.h>
21 #include <time.h>
22 #include <assert.h>
23 #include <string.h>
24 #include "windows.h"
25 #include "wingdi.h"
26 #include "mmsystem.h"
27 #include "ddraw.h"
28 #include "vfw.h"
29
30
31 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
32 {
33     int                 bytesline,i,n,pos;
34     time_t              tstart,tend;
35     LONG                cnt;
36     BITMAPINFOHEADER    *bmi;
37     HRESULT             hres;
38     HMODULE             avifil32 = LoadLibrary("avifil32.dll");
39     PAVIFILE            avif;
40     PAVISTREAM          vids=NULL,auds=NULL;
41     AVIFILEINFO         afi;
42     AVISTREAMINFO       asi;
43     PGETFRAME           vidgetframe=NULL;
44     LPDIRECTDRAW        ddraw;
45     DDSURFACEDESC       dsdesc;
46     LPDIRECTDRAWSURFACE dsurf;
47     LPDIRECTDRAWPALETTE dpal;
48     PALETTEENTRY        palent[256];
49
50
51 void    WINAPI (*fnAVIFileInit)(void);
52 void    WINAPI (*fnAVIFileExit)(void);
53 ULONG   WINAPI (*fnAVIFileRelease)(PAVIFILE);
54 ULONG   WINAPI (*fnAVIStreamRelease)(PAVISTREAM);
55 HRESULT WINAPI (*fnAVIFileOpen)(PAVIFILE * ppfile,LPCTSTR szFile,UINT uMode,LPCLSID lpHandler);
56 HRESULT WINAPI (*fnAVIFileInfo)(PAVIFILE ppfile,AVIFILEINFO *afi,LONG size);
57 HRESULT WINAPI (*fnAVIFileGetStream)(PAVIFILE ppfile,PAVISTREAM *afi,DWORD fccType,LONG lParam);
58 HRESULT WINAPI (*fnAVIStreamInfo)(PAVISTREAM iface,AVISTREAMINFO *afi,LONG size);
59 HRESULT WINAPI (*fnAVIStreamReadFormat)(PAVISTREAM iface,LONG pos,LPVOID format,LPLONG size);
60 PGETFRAME WINAPI (*fnAVIStreamGetFrameOpen)(PAVISTREAM iface,LPBITMAPINFOHEADER wanted);
61 LPVOID WINAPI (*fnAVIStreamGetFrame)(PGETFRAME pg,LONG pos);
62 HRESULT WINAPI (*fnAVIStreamGetFrameClose)(PGETFRAME pg);
63
64 #define XX(x) fn##x = (void*)GetProcAddress(avifil32,#x);assert(fn##x);
65 #ifdef UNICODE
66 # define XXT(x) fn##x = (void*)GetProcAddress(avifil32,#x##"W");assert(fn##x);
67 #else
68 # define XXT(x) fn##x = (void*)GetProcAddress(avifil32,#x##"A");assert(fn##x);
69 #endif
70         /* non character dependend routines: */
71         XX (AVIFileInit);
72         XX (AVIFileExit);
73         XX (AVIFileRelease);
74         XX (AVIFileGetStream);
75         XX (AVIStreamRelease);
76         XX (AVIStreamReadFormat);
77         XX (AVIStreamGetFrameOpen);
78         XX (AVIStreamGetFrame);
79         XX (AVIStreamGetFrameClose);
80         /* A/W routines: */
81         XXT(AVIFileOpen);
82         XXT(AVIFileInfo);
83         XXT(AVIStreamInfo);
84 #undef XX
85 #undef XXT
86
87     
88     fnAVIFileInit();
89     if (-1==GetFileAttributes(cmdline)) {
90         fprintf(stderr,"Usage: aviplay <avifilename>\n");
91         exit(1);
92     }
93     hres = fnAVIFileOpen(&avif,cmdline,OF_READ,NULL);
94     if (hres) {
95         fprintf(stderr,"AVIFileOpen: 0x%08lx\n",hres);
96         exit(1);
97     }
98     hres = fnAVIFileInfo(avif,&afi,sizeof(afi));
99     if (hres) {
100         fprintf(stderr,"AVIFileInfo: 0x%08lx\n",hres);
101         exit(1);
102     }
103     for (n=0;n<afi.dwStreams;n++) {
104             char buf[5];
105             PAVISTREAM  ast;
106
107             hres = fnAVIFileGetStream(avif,&ast,0,n);
108             if (hres) {
109                 fprintf(stderr,"AVIFileGetStream %d: 0x%08lx\n",n,hres);
110                 exit(1);
111             }
112             hres = fnAVIStreamInfo(ast,&asi,sizeof(asi));
113             if (hres) {
114                 fprintf(stderr,"AVIStreamInfo %d: 0x%08lx\n",n,hres);
115                 exit(1);
116             }
117             fprintf(stderr,"[Stream %d: ",n);
118             buf[4]='\0';memcpy(buf,&(asi.fccType),4);
119             fprintf(stderr,"%s.",buf);
120             buf[4]='\0';memcpy(buf,&(asi.fccHandler),4);
121             fprintf(stderr,"%s, %s]\n",buf,asi.szName);
122             switch (asi.fccType) {
123             case streamtypeVIDEO:
124                 vids = ast;
125                 break;
126             case streamtypeAUDIO: 
127                 auds = ast;
128                 break;
129             default:  {
130                 char type[5];
131                 type[4]='\0';memcpy(type,&(asi.fccType),4);
132
133                 fprintf(stderr,"Unhandled streamtype %s\n",type);
134                 fnAVIStreamRelease(ast);
135                 break;
136             }
137             }
138     }
139 /********************* begin video setup ***********************************/
140     if (!vids) {
141         fprintf(stderr,"No video stream found. Good Bye.\n");
142         exit(0);
143     }
144     cnt = sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
145     bmi = HeapAlloc(GetProcessHeap(),0,cnt);
146     hres = fnAVIStreamReadFormat(vids,0,bmi,&cnt);
147     if (hres) {
148         fprintf(stderr,"AVIStreamReadFormat vids: 0x%08lx\n",hres);
149         exit(1);
150     }
151     vidgetframe = NULL;
152     bmi->biCompression = 0; /* we want it in raw form, uncompressed */
153     /* recalculate the image size */
154     bmi->biSizeImage = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes*bmi->biHeight/8;
155     bytesline = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes/8;
156     vidgetframe = fnAVIStreamGetFrameOpen(vids,bmi);
157     if (!vidgetframe) {
158         fprintf(stderr,"AVIStreamGetFrameOpen: failed\n");
159         exit(1);
160     }
161 /********************* end video setup ***********************************/
162
163 /********************* begin display setup *******************************/
164     hres = DirectDrawCreate(NULL,&ddraw,NULL);
165     if (hres) {
166         fprintf(stderr,"DirectDrawCreate: 0x%08lx\n",hres);
167         exit(1);
168     }
169     hres = IDirectDraw_SetDisplayMode(ddraw,bmi->biWidth,bmi->biHeight,bmi->biBitCount);
170     if (hres) {
171         fprintf(stderr,"ddraw.SetDisplayMode: 0x%08lx (change resolution!)\n",hres);
172         exit(1);
173     }
174     dsdesc.dwSize=sizeof(dsdesc);
175     dsdesc.dwFlags = DDSD_CAPS;
176     dsdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
177     hres = IDirectDraw_CreateSurface(ddraw,&dsdesc,&dsurf,NULL);
178     if (hres) {
179         fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres);
180         exit(1);
181     }
182     if (bmi->biBitCount==8) {
183         RGBQUAD         *rgb = (RGBQUAD*)(bmi+1);
184         int             i;
185
186         hres = IDirectDraw_CreatePalette(ddraw,DDPCAPS_8BIT,NULL,&dpal,NULL);
187         if (hres) {
188             fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres);
189             exit(1);
190         }
191         IDirectDrawSurface_SetPalette(dsurf,dpal);
192         for (i=0;i<bmi->biClrUsed;i++) {
193             palent[i].peRed = rgb[i].rgbRed;
194             palent[i].peBlue = rgb[i].rgbBlue;
195             palent[i].peGreen = rgb[i].rgbGreen;
196         }
197         IDirectDrawPalette_SetEntries(dpal,0,0,bmi->biClrUsed,palent);
198     } else
199         dpal = NULL;
200 /********************* end display setup *******************************/
201
202     tstart = time(NULL);
203     pos = 0;
204     while (1) {
205         LPVOID          decodedframe;
206         LPBITMAPINFOHEADER lpbmi;
207         LPVOID          decodedbits;
208
209 /* video stuff */
210         if (!(decodedframe=fnAVIStreamGetFrame(vidgetframe,pos++)))
211             break;
212         lpbmi = (LPBITMAPINFOHEADER)decodedframe;
213         decodedbits = (LPVOID)(((DWORD)decodedframe)+lpbmi->biSize);
214         if (lpbmi->biBitCount == 8) {
215         /* cant detect palette change that way I think */
216             RGBQUAD     *rgb = (RGBQUAD*)(lpbmi+1);
217             int         i,palchanged;
218
219             /* skip used colorentries. */
220             decodedbits=(char*)decodedbits+bmi->biClrUsed*sizeof(RGBQUAD);
221             palchanged = 0;
222             for (i=0;i<bmi->biClrUsed;i++) {
223                 if (    (palent[i].peRed != rgb[i].rgbRed) ||
224                         (palent[i].peBlue != rgb[i].rgbBlue) ||
225                         (palent[i].peGreen != rgb[i].rgbGreen)
226                 ) {
227                         palchanged = 1;
228                         break;
229                 }
230             }
231             if (palchanged) {
232                 for (i=0;i<bmi->biClrUsed;i++) {
233                     palent[i].peRed = rgb[i].rgbRed;
234                     palent[i].peBlue = rgb[i].rgbBlue;
235                     palent[i].peGreen = rgb[i].rgbGreen;
236                 }
237                 IDirectDrawPalette_SetEntries(dpal,0,0,bmi->biClrUsed,palent);
238             }
239         }
240         dsdesc.dwSize = sizeof(dsdesc);
241         hres = IDirectDrawSurface_Lock(dsurf,NULL,&dsdesc,DDLOCK_WRITEONLY,0);
242         if (hres) {
243             fprintf(stderr,"dsurf.Lock: 0x%08lx\n",hres);
244             exit(1);
245         }
246         /* Argh. AVIs are upside down. */
247         for (i=0;i<dsdesc.dwHeight;i++) {
248             memcpy( (char *)dsdesc.lpSurface+(i*dsdesc.u1.lPitch),
249                     (char *)decodedbits+bytesline*(dsdesc.dwHeight-i-1),
250                     bytesline
251             );
252         }
253         IDirectDrawSurface_Unlock(dsurf,dsdesc.lpSurface);
254     }
255     tend = time(NULL);
256     fnAVIStreamGetFrameClose(vidgetframe);
257
258     IDirectDrawSurface_Release(dsurf);
259     IDirectDraw_RestoreDisplayMode(ddraw);
260     IDirectDraw_Release(ddraw);
261     if (vids) fnAVIStreamRelease(vids);
262     if (auds) fnAVIStreamRelease(auds);
263     fprintf(stderr,"%d frames at %g frames/s\n",pos,pos*1.0/(tend-tstart));
264     fnAVIFileRelease(avif);
265     fnAVIFileExit();
266     return 0;    
267 }