- Make MTA dynamically allocated so that proxies and other resources
[wine] / programs / avitools / aviplay.c
1 /*
2  * Very simple AVIPLAYER
3  *
4  * Copyright 1999 Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Status:
21  *      - plays .avi streams, video only
22  *      - requires Microsoft avifil32.dll and builtin msvfw32.dll.
23  *
24  * Todo:
25  *      - audio support (including synchronization etc)
26  *      - replace DirectDraw by a 'normal' window, including dithering, controls
27  *        etc.
28  *
29  * Bugs:
30  *      - no time scheduling, video plays too fast using DirectDraw/XF86DGA
31  *      - requires DirectDraw with all disadvantages.
32  */
33
34 #include <stdio.h>
35 #include <time.h>
36 #include <assert.h>
37 #include <string.h>
38
39 #define NONAMELESSUNION
40 #define NONAMELESSSTRUCT
41 #include "windows.h"
42 #include "wingdi.h"
43 #include "mmsystem.h"
44 #include "ddraw.h"
45 #include "vfw.h"
46
47
48 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
49 {
50     int                 bytesline,i,n,pos;
51     time_t              tstart,tend;
52     LONG                cnt;
53     BITMAPINFOHEADER    *bmi;
54     HRESULT             hres;
55     PAVIFILE            avif;
56     PAVISTREAM          vids=NULL,auds=NULL;
57     AVIFILEINFO         afi;
58     AVISTREAMINFO       asi;
59     PGETFRAME           vidgetframe=NULL;
60     LPDIRECTDRAW        ddraw;
61     DDSURFACEDESC       dsdesc;
62     LPDIRECTDRAWSURFACE dsurf;
63     LPDIRECTDRAWPALETTE dpal;
64     PALETTEENTRY        palent[256];
65
66     AVIFileInit();
67     if (GetFileAttributes(cmdline) == INVALID_FILE_ATTRIBUTES) {
68         fprintf(stderr,"Usage: aviplay <avifilename>\n");
69         exit(1);
70     }
71     hres = AVIFileOpen(&avif,cmdline,OF_READ,NULL);
72     if (hres) {
73         fprintf(stderr,"AVIFileOpen: 0x%08lx\n",hres);
74         exit(1);
75     }
76     hres = AVIFileInfo(avif,&afi,sizeof(afi));
77     if (hres) {
78         fprintf(stderr,"AVIFileInfo: 0x%08lx\n",hres);
79         exit(1);
80     }
81     for (n=0;n<afi.dwStreams;n++) {
82             char buf[5];
83             PAVISTREAM  ast;
84
85             hres = AVIFileGetStream(avif,&ast,0,n);
86             if (hres) {
87                 fprintf(stderr,"AVIFileGetStream %d: 0x%08lx\n",n,hres);
88                 exit(1);
89             }
90             hres = AVIStreamInfo(ast,&asi,sizeof(asi));
91             if (hres) {
92                 fprintf(stderr,"AVIStreamInfo %d: 0x%08lx\n",n,hres);
93                 exit(1);
94             }
95             fprintf(stderr,"[Stream %d: ",n);
96             buf[4]='\0';memcpy(buf,&(asi.fccType),4);
97             fprintf(stderr,"%s.",buf);
98             buf[4]='\0';memcpy(buf,&(asi.fccHandler),4);
99             fprintf(stderr,"%s, %s]\n",buf,asi.szName);
100             switch (asi.fccType) {
101             case streamtypeVIDEO:
102                 vids = ast;
103                 break;
104             case streamtypeAUDIO:
105                 auds = ast;
106                 break;
107             default:  {
108                 char type[5];
109                 type[4]='\0';memcpy(type,&(asi.fccType),4);
110
111                 fprintf(stderr,"Unhandled streamtype %s\n",type);
112                 AVIStreamRelease(ast);
113                 break;
114             }
115             }
116     }
117 /********************* begin video setup ***********************************/
118     if (!vids) {
119         fprintf(stderr,"No video stream found. Good Bye.\n");
120         exit(0);
121     }
122     cnt = sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
123     bmi = HeapAlloc(GetProcessHeap(),0,cnt);
124     hres = AVIStreamReadFormat(vids,0,bmi,&cnt);
125     if (hres) {
126         fprintf(stderr,"AVIStreamReadFormat vids: 0x%08lx\n",hres);
127         exit(1);
128     }
129     vidgetframe = NULL;
130     bmi->biCompression = 0; /* we want it in raw form, uncompressed */
131     /* recalculate the image size */
132     bmi->biSizeImage = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes*bmi->biHeight/8;
133     bytesline = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes/8;
134     vidgetframe = AVIStreamGetFrameOpen(vids,bmi);
135     if (!vidgetframe) {
136         fprintf(stderr,"AVIStreamGetFrameOpen: failed\n");
137         exit(1);
138     }
139 /********************* end video setup ***********************************/
140
141 /********************* begin display setup *******************************/
142     hres = DirectDrawCreate(NULL,&ddraw,NULL);
143     if (hres) {
144         fprintf(stderr,"DirectDrawCreate: 0x%08lx\n",hres);
145         exit(1);
146     }
147     hres = IDirectDraw_SetDisplayMode(ddraw,bmi->biWidth,bmi->biHeight,bmi->biBitCount);
148     if (hres) {
149         fprintf(stderr,"ddraw.SetDisplayMode: 0x%08lx (change resolution!)\n",hres);
150         exit(1);
151     }
152     dsdesc.dwSize=sizeof(dsdesc);
153     dsdesc.dwFlags = DDSD_CAPS;
154     dsdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
155     hres = IDirectDraw_CreateSurface(ddraw,&dsdesc,&dsurf,NULL);
156     if (hres) {
157         fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres);
158         exit(1);
159     }
160     if (bmi->biBitCount==8) {
161         RGBQUAD         *rgb = (RGBQUAD*)(bmi+1);
162         int             i;
163
164         hres = IDirectDraw_CreatePalette(ddraw,DDPCAPS_8BIT,NULL,&dpal,NULL);
165         if (hres) {
166             fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres);
167             exit(1);
168         }
169         IDirectDrawSurface_SetPalette(dsurf,dpal);
170         for (i=0;i<bmi->biClrUsed;i++) {
171             palent[i].peRed = rgb[i].rgbRed;
172             palent[i].peBlue = rgb[i].rgbBlue;
173             palent[i].peGreen = rgb[i].rgbGreen;
174         }
175         IDirectDrawPalette_SetEntries(dpal,0,0,bmi->biClrUsed,palent);
176     } else
177         dpal = NULL;
178 /********************* end display setup *******************************/
179
180     tstart = time(NULL);
181     pos = 0;
182     while (1) {
183         LPVOID          decodedframe;
184         LPBITMAPINFOHEADER lpbmi;
185         LPVOID          decodedbits;
186
187 /* video stuff */
188         if (!(decodedframe=AVIStreamGetFrame(vidgetframe,pos++)))
189             break;
190         lpbmi = (LPBITMAPINFOHEADER)decodedframe;
191         decodedbits = (LPVOID)(((DWORD)decodedframe)+lpbmi->biSize);
192         if (lpbmi->biBitCount == 8) {
193         /* can't detect palette change that way I think */
194             RGBQUAD     *rgb = (RGBQUAD*)(lpbmi+1);
195             int         i,palchanged;
196
197             /* skip used colorentries. */
198             decodedbits=(char*)decodedbits+bmi->biClrUsed*sizeof(RGBQUAD);
199             palchanged = 0;
200             for (i=0;i<bmi->biClrUsed;i++) {
201                 if (    (palent[i].peRed != rgb[i].rgbRed) ||
202                         (palent[i].peBlue != rgb[i].rgbBlue) ||
203                         (palent[i].peGreen != rgb[i].rgbGreen)
204                 ) {
205                         palchanged = 1;
206                         break;
207                 }
208             }
209             if (palchanged) {
210                 for (i=0;i<bmi->biClrUsed;i++) {
211                     palent[i].peRed = rgb[i].rgbRed;
212                     palent[i].peBlue = rgb[i].rgbBlue;
213                     palent[i].peGreen = rgb[i].rgbGreen;
214                 }
215                 IDirectDrawPalette_SetEntries(dpal,0,0,bmi->biClrUsed,palent);
216             }
217         }
218         dsdesc.dwSize = sizeof(dsdesc);
219         hres = IDirectDrawSurface_Lock(dsurf,NULL,&dsdesc,DDLOCK_WRITEONLY,0);
220         if (hres) {
221             fprintf(stderr,"dsurf.Lock: 0x%08lx\n",hres);
222             exit(1);
223         }
224         /* Argh. AVIs are upside down. */
225         for (i=0;i<dsdesc.dwHeight;i++) {
226             memcpy( (char *)dsdesc.lpSurface+(i*dsdesc.u1.lPitch),
227                     (char *)decodedbits+bytesline*(dsdesc.dwHeight-i-1),
228                     bytesline
229             );
230         }
231         IDirectDrawSurface_Unlock(dsurf,dsdesc.lpSurface);
232     }
233     tend = time(NULL);
234     AVIStreamGetFrameClose(vidgetframe);
235
236     IDirectDrawSurface_Release(dsurf);
237     IDirectDraw_RestoreDisplayMode(ddraw);
238     IDirectDraw_Release(ddraw);
239     if (vids) AVIStreamRelease(vids);
240     if (auds) AVIStreamRelease(auds);
241     fprintf(stderr,"%d frames at %g frames/s\n",pos,pos*1.0/(tend-tstart));
242     AVIFileRelease(avif);
243     AVIFileExit();
244     return 0;
245 }