For the transparency issue, implemented a switch-case for the bitcount
[wine.git] / dlls / comctl32 / animate.c
blob25bafe1c7607c728413558eaf2df593ef550c92f
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Animation control
5 * Copyright 1998, 1999 Eric Kohl
6 * 1999 Eric Pouech
8 * NOTES
9 * I will only improve this control once in a while.
10 * Eric <ekohl@abo.rhein-zeitung.de>
12 * TODO:
13 * - check for the 'rec ' list in some AVI files
14 * - implement some missing flags (ACS_TRANSPARENT)
15 * - protection between service thread and wndproc messages handling
16 * concurrent access to infoPtr
20 #include "winbase.h"
21 #include "commctrl.h"
22 #include "vfw.h"
23 #include "mmsystem.h"
24 #include "services.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(animate);
29 typedef struct
31 /* pointer to msvideo functions. it's easier to put them here.
32 * to be correct, they should be defined on a per process basis, but
33 * this would required a per process storage. We're using a per object
34 * storage instead, which is not efficient on memory usage, but
35 * will lead to less bugs in the future
37 HIC WINAPI (*fnICOpen)(DWORD, DWORD, UINT);
38 LRESULT WINAPI (*fnICClose)(HIC);
39 LRESULT WINAPI (*fnICSendMessage)(HIC, UINT, DWORD, DWORD);
40 DWORD WINAPIV (*fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID);
42 HMMIO WINAPI (*fnmmioOpenA)(LPSTR,MMIOINFO*,DWORD);
43 MMRESULT WINAPI (*fnmmioClose)(HMMIO,UINT);
44 UINT WINAPI (*fnmmioAscend)(HMMIO,MMCKINFO*,UINT);
45 UINT WINAPI (*fnmmioDescend)(HMMIO,MMCKINFO*,const MMCKINFO*,UINT);
46 LONG WINAPI (*fnmmioSeek)(HMMIO,LONG,INT);
47 LONG WINAPI (*fnmmioRead)(HMMIO,HPSTR,LONG);
49 /* reference to input stream (file or resource) */
50 HGLOBAL hRes;
51 HMMIO hMMio; /* handle to mmio stream */
52 HWND hWnd;
53 /* information on the loaded AVI file */
54 MainAVIHeader mah;
55 AVIStreamHeader ash;
56 LPBITMAPINFOHEADER inbih;
57 LPDWORD lpIndex;
58 /* data for the decompressor */
59 HIC hic;
60 LPBITMAPINFOHEADER outbih;
61 LPVOID indata;
62 LPVOID outdata;
63 /* data for the background mechanism */
64 CRITICAL_SECTION cs;
65 HANDLE hService;
66 UINT uTimer;
67 /* data for playing the file */
68 int nFromFrame;
69 int nToFrame;
70 int nLoop;
71 int currFrame;
72 /* Background frame info*/
73 HBITMAP bkgFrameb;
74 LPDWORD bkColor;
75 } ANIMATE_INFO;
77 #define ANIMATE_GetInfoPtr(hWnd) ((ANIMATE_INFO *)GetWindowLongA(hWnd, 0))
79 HMODULE hModWinmm;
81 static void ANIMATE_Notify(ANIMATE_INFO* infoPtr, UINT notif)
83 SendMessageA(GetParent(infoPtr->hWnd), WM_COMMAND,
84 MAKEWPARAM(GetDlgCtrlID(infoPtr->hWnd), notif),
85 (LPARAM)infoPtr->hWnd);
88 static BOOL ANIMATE_LoadResA(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPSTR lpName)
90 HRSRC hrsrc;
91 MMIOINFO mminfo;
92 LPVOID lpAvi;
94 hrsrc = FindResourceA(hInst, lpName, "AVI");
95 if (!hrsrc)
96 return FALSE;
98 infoPtr->hRes = LoadResource(hInst, hrsrc);
99 if (!infoPtr->hRes)
100 return FALSE;
102 lpAvi = LockResource(infoPtr->hRes);
103 if (!lpAvi)
104 return FALSE;
106 memset(&mminfo, 0, sizeof(mminfo));
107 mminfo.fccIOProc = FOURCC_MEM;
108 mminfo.pchBuffer = (LPSTR)lpAvi;
109 mminfo.cchBuffer = SizeofResource(hInst, hrsrc);
110 infoPtr->hMMio = infoPtr->fnmmioOpenA(NULL, &mminfo, MMIO_READ);
112 if (!infoPtr->hMMio) {
113 GlobalFree((HGLOBAL)lpAvi);
114 return FALSE;
117 infoPtr->bkgFrameb=(HBITMAP)NULL;
119 return TRUE;
123 static BOOL ANIMATE_LoadFileA(ANIMATE_INFO *infoPtr, LPSTR lpName)
125 infoPtr->hMMio = infoPtr->fnmmioOpenA((LPSTR)lpName, NULL,
126 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
128 if (!infoPtr->hMMio)
129 return FALSE;
131 return TRUE;
135 static LRESULT ANIMATE_DoStop(ANIMATE_INFO *infoPtr)
137 EnterCriticalSection(&infoPtr->cs);
139 /* should stop playing */
140 if (infoPtr->hService) {
141 SERVICE_Delete(infoPtr->hService);
142 infoPtr->hService = 0;
144 if (infoPtr->uTimer) {
145 KillTimer(infoPtr->hWnd, infoPtr->uTimer);
146 infoPtr->uTimer = 0;
149 LeaveCriticalSection(&infoPtr->cs);
151 ANIMATE_Notify(infoPtr, ACN_STOP);
153 return TRUE;
157 static void ANIMATE_Free(ANIMATE_INFO *infoPtr)
159 if (infoPtr->hMMio) {
160 ANIMATE_DoStop(infoPtr);
161 infoPtr->fnmmioClose(infoPtr->hMMio, 0);
162 if (infoPtr->bkgFrameb) {
163 DeleteObject(infoPtr->bkgFrameb);
164 infoPtr->bkgFrameb=(HBITMAP)NULL;
165 infoPtr->bkColor=NULL;
167 if (infoPtr->hRes) {
168 FreeResource(infoPtr->hRes);
169 infoPtr->hRes = 0;
171 if (infoPtr->lpIndex) {
172 HeapFree(GetProcessHeap(), 0, infoPtr->lpIndex);
173 infoPtr->lpIndex = NULL;
175 if (infoPtr->hic) {
176 (infoPtr->fnICClose)(infoPtr->hic);
177 infoPtr->hic = 0;
179 if (infoPtr->inbih) {
180 HeapFree(GetProcessHeap(), 0, infoPtr->inbih);
181 infoPtr->inbih = NULL;
183 if (infoPtr->outbih) {
184 HeapFree(GetProcessHeap(), 0, infoPtr->outbih);
185 infoPtr->outbih = NULL;
187 HeapFree(GetProcessHeap(), 0, infoPtr->indata);
188 HeapFree(GetProcessHeap(), 0, infoPtr->outdata);
189 infoPtr->indata = infoPtr->outdata = NULL;
190 infoPtr->hWnd = 0;
191 infoPtr->hMMio = 0;
192 memset(&infoPtr->mah, 0, sizeof(infoPtr->mah));
193 memset(&infoPtr->ash, 0, sizeof(infoPtr->ash));
194 infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0;
199 static LRESULT ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC)
201 if (!hDC || !infoPtr->inbih)
202 return TRUE;
203 if (infoPtr->hic){
204 if (GetWindowLongA(infoPtr->hWnd, GWL_STYLE) & ACS_TRANSPARENT){
205 FIXME("TRANSPARENCY NOT SUPPORTED(NOT TESTED) FOR COMPRESSED IMAGE\n");
207 StretchDIBits(hDC, 0, 0, infoPtr->outbih->biWidth, infoPtr->outbih->biHeight,
208 0, 0, infoPtr->outbih->biWidth, infoPtr->outbih->biHeight,
209 infoPtr->outdata, (LPBITMAPINFO)infoPtr->outbih, DIB_RGB_COLORS,
210 SRCCOPY);
212 else{
213 if (GetWindowLongA(infoPtr->hWnd, GWL_STYLE) & ACS_TRANSPARENT){
214 HBITMAP hbmMem, hbmMem2,hbmMem3;
215 HDC hdcSrc, hdcMask, hdcMem;
217 hdcSrc = CreateCompatibleDC(hDC);
218 hdcMask = CreateCompatibleDC(hDC);
219 hdcMem = CreateCompatibleDC(hDC);
221 /* create a Black and white bitmap */
222 hbmMem = CreateCompatibleBitmap( hDC,infoPtr->inbih->biWidth,infoPtr->inbih->biHeight);
223 hbmMem2 = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1, 1, NULL);
224 hbmMem3 = CreateCompatibleBitmap( hDC,infoPtr->inbih->biWidth,infoPtr->inbih->biHeight);
226 SelectObject( hdcSrc, hbmMem);
228 StretchDIBits(hdcSrc, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,
229 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,
230 infoPtr->indata, (LPBITMAPINFO)infoPtr->inbih, DIB_RGB_COLORS,
231 SRCCOPY);
233 if (infoPtr->bkgFrameb==(HBITMAP)NULL)
235 infoPtr->bkgFrameb = CreateCompatibleBitmap( hDC,infoPtr->inbih->biWidth,infoPtr->inbih->biHeight);
236 SelectObject( hdcMem, infoPtr->bkgFrameb);
237 BitBlt(hdcMem, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hDC, 0, 0, SRCCOPY);
238 /* Get the transparent color from the first frame*/
239 switch (infoPtr->inbih->biBitCount) {
240 case 1:
241 case 4:
242 /*FIXME: Not supported Yet.*/
243 break;
244 case 8:
245 infoPtr->bkColor = (LPVOID)((LPSTR)infoPtr->inbih + (WORD)(((LPBITMAPINFO)infoPtr->inbih)->bmiHeader.biSize));
246 break;
247 case 16:
248 case 24:
249 case 32:
250 infoPtr->bkColor = (LPVOID)GetPixel(hdcSrc, 0, 0);
251 /*FIXME:Has not been test with more than 8bpp, errors are possible*/
252 break;
256 /* Need the copy of the original destination HDC*/
257 SelectObject( hdcSrc, infoPtr->bkgFrameb);
258 SelectObject( hdcMem, hbmMem3);
259 BitBlt(hdcMem, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcSrc, 0, 0, SRCCOPY);
261 SelectObject( hdcSrc, hbmMem);
262 SelectObject( hdcMask, hbmMem2);
264 /*Windows converts a color source into monochrome when the destination is
265 monochrome. In this situation, all pixels in the color bitmap that are the same color
266 as the background color become 1s, and all the other pixels are converted to 0s. */
268 /* Set the transparent color from the first frame*/
269 switch (infoPtr->inbih->biBitCount) {
270 case 1:
271 case 4:
272 /*FIXME: Not supported Yet.*/
273 break;
274 case 8:
275 SetBkColor(hdcSrc, infoPtr->bkColor[(((BYTE*)infoPtr->indata)[0])]);
276 break;
277 case 16:
278 case 24:
279 case 32:
280 SetBkColor(hdcSrc, (COLORREF)infoPtr->bkColor);
281 break;
284 BitBlt(hdcMask, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcSrc, 0, 0, SRCCOPY);
286 /*During a blt operation with a color destination, a monochrome source bitmap
287 (and/or a brush when applicable) is converted to color on the fly before the
288 actual ROP is carried out on the bits. The 0 (black) pixels in the monochrome
289 bitmap are converted to the destination's text (foreground) color, and the 1
290 (white) pixels are converted to the background color. */
292 SetBkColor(hdcSrc, RGB(0,0,0)); /* 1s --> black (0x000000)*/
293 SetTextColor(hdcSrc, RGB(255,255,255)); /* 0s --> white (0xFFFFFF)*/
295 BitBlt(hdcSrc, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND);
297 SetBkColor(hdcMem, RGB(255,255,255)); /* 0s --> white (0xFFFFFF) */
298 SetTextColor(hdcMem, RGB(0,0,0)); /* 1s --> black (0x000000) */
300 BitBlt(hdcMem, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND);
302 BitBlt(hdcMem, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcSrc, 0, 0, SRCPAINT);
304 BitBlt(hDC, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMem, 0, 0, SRCCOPY);
306 DeleteDC(hdcMem);
307 DeleteDC(hdcSrc);
308 DeleteDC(hdcMask);
309 DeleteObject(hbmMem);
310 DeleteObject(hbmMem2);
311 DeleteObject(hbmMem3);
314 else{
315 StretchDIBits(hDC, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,
316 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,
317 infoPtr->indata, (LPBITMAPINFO)infoPtr->inbih, DIB_RGB_COLORS,
318 SRCCOPY);
322 return TRUE;
325 static LRESULT ANIMATE_DrawFrame(ANIMATE_INFO* infoPtr)
327 HDC hDC;
329 TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop);
331 EnterCriticalSection(&infoPtr->cs);
333 infoPtr->fnmmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET);
334 infoPtr->fnmmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize);
336 if (infoPtr->hic &&
337 (infoPtr->fnICDecompress)(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata,
338 infoPtr->outbih, infoPtr->outdata) != ICERR_OK) {
339 LeaveCriticalSection(&infoPtr->cs);
340 WARN("Decompression error\n");
341 return FALSE;
344 if ((hDC = GetDC(infoPtr->hWnd)) != 0) {
345 ANIMATE_PaintFrame(infoPtr, hDC);
346 ReleaseDC(infoPtr->hWnd, hDC);
349 if (infoPtr->currFrame++ >= infoPtr->nToFrame) {
350 infoPtr->currFrame = infoPtr->nFromFrame;
351 if (infoPtr->nLoop != -1) {
352 if (--infoPtr->nLoop == 0) {
353 ANIMATE_DoStop(infoPtr);
357 LeaveCriticalSection(&infoPtr->cs);
359 return TRUE;
362 static void CALLBACK ANIMATE_ServiceCallback(ULONG_PTR ptr_)
364 ANIMATE_INFO* infoPtr = (ANIMATE_INFO*)ptr_;
366 EnterCriticalSection(&infoPtr->cs);
367 ANIMATE_DrawFrame(infoPtr);
368 LeaveCriticalSection(&infoPtr->cs);
371 static LRESULT ANIMATE_Play(HWND hWnd, WPARAM wParam, LPARAM lParam)
373 ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(hWnd);
375 /* nothing opened */
376 if (!infoPtr->hMMio)
377 return FALSE;
379 if (infoPtr->hService || infoPtr->uTimer) {
380 FIXME("Already playing ? what should I do ??\n");
381 ANIMATE_DoStop(infoPtr);
384 infoPtr->nFromFrame = (INT)LOWORD(lParam);
385 infoPtr->nToFrame = (INT)HIWORD(lParam);
386 infoPtr->nLoop = (INT)wParam;
388 if (infoPtr->nToFrame == 0xFFFF)
389 infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1;
391 TRACE("(repeat=%d from=%d to=%d);\n",
392 infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame);
394 if (infoPtr->nFromFrame >= infoPtr->nToFrame ||
395 infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames)
396 return FALSE;
398 infoPtr->currFrame = infoPtr->nFromFrame;
400 if (GetWindowLongA(hWnd, GWL_STYLE) & ACS_TIMER) {
401 TRACE("Using a timer\n");
402 /* create a timer to display AVI */
403 infoPtr->uTimer = SetTimer(hWnd, 1, infoPtr->mah.dwMicroSecPerFrame / 1000, NULL);
404 } else {
405 TRACE("Using the service thread\n");
406 /* time is in µs */
407 infoPtr->hService = SERVICE_AddTimer(infoPtr->mah.dwMicroSecPerFrame / 1000,
408 ANIMATE_ServiceCallback, (DWORD)infoPtr);
411 ANIMATE_Notify(infoPtr, ACN_START);
413 return TRUE;
417 static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr)
419 MMCKINFO ckMainRIFF;
420 MMCKINFO mmckHead;
421 MMCKINFO mmckList;
422 MMCKINFO mmckInfo;
423 DWORD numFrame;
424 DWORD insize;
426 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) {
427 WARN("Can't find 'RIFF' chunk\n");
428 return FALSE;
431 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
432 (ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) {
433 WARN("Can't find 'AVI ' chunk\n");
434 return FALSE;
437 mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l');
438 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) {
439 WARN("Can't find 'hdrl' list\n");
440 return FALSE;
443 mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h');
444 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) {
445 WARN("Can't find 'avih' chunk\n");
446 return FALSE;
449 infoPtr->fnmmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah));
450 TRACE("mah.dwMicroSecPerFrame=%ld\n", infoPtr->mah.dwMicroSecPerFrame);
451 TRACE("mah.dwMaxBytesPerSec=%ld\n", infoPtr->mah.dwMaxBytesPerSec);
452 TRACE("mah.dwPaddingGranularity=%ld\n", infoPtr->mah.dwPaddingGranularity);
453 TRACE("mah.dwFlags=%ld\n", infoPtr->mah.dwFlags);
454 TRACE("mah.dwTotalFrames=%ld\n", infoPtr->mah.dwTotalFrames);
455 TRACE("mah.dwInitialFrames=%ld\n", infoPtr->mah.dwInitialFrames);
456 TRACE("mah.dwStreams=%ld\n", infoPtr->mah.dwStreams);
457 TRACE("mah.dwSuggestedBufferSize=%ld\n", infoPtr->mah.dwSuggestedBufferSize);
458 TRACE("mah.dwWidth=%ld\n", infoPtr->mah.dwWidth);
459 TRACE("mah.dwHeight=%ld\n", infoPtr->mah.dwHeight);
460 infoPtr->fnmmioAscend(infoPtr->hMMio, &mmckInfo, 0);
462 mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l');
463 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) {
464 WARN("Can't find 'strl' list\n");
465 return FALSE;
468 mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h');
469 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) {
470 WARN("Can't find 'strh' chunk\n");
471 return FALSE;
474 infoPtr->fnmmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash));
475 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccType)),
476 HIBYTE(LOWORD(infoPtr->ash.fccType)),
477 LOBYTE(HIWORD(infoPtr->ash.fccType)),
478 HIBYTE(HIWORD(infoPtr->ash.fccType)));
479 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccHandler)),
480 HIBYTE(LOWORD(infoPtr->ash.fccHandler)),
481 LOBYTE(HIWORD(infoPtr->ash.fccHandler)),
482 HIBYTE(HIWORD(infoPtr->ash.fccHandler)));
483 TRACE("ash.dwFlags=%ld\n", infoPtr->ash.dwFlags);
484 TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority);
485 TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage);
486 TRACE("ash.dwInitialFrames=%ld\n", infoPtr->ash.dwInitialFrames);
487 TRACE("ash.dwScale=%ld\n", infoPtr->ash.dwScale);
488 TRACE("ash.dwRate=%ld\n", infoPtr->ash.dwRate);
489 TRACE("ash.dwStart=%ld\n", infoPtr->ash.dwStart);
490 TRACE("ash.dwLength=%ld\n", infoPtr->ash.dwLength);
491 TRACE("ash.dwSuggestedBufferSize=%ld\n", infoPtr->ash.dwSuggestedBufferSize);
492 TRACE("ash.dwQuality=%ld\n", infoPtr->ash.dwQuality);
493 TRACE("ash.dwSampleSize=%ld\n", infoPtr->ash.dwSampleSize);
494 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left,
495 infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right);
496 infoPtr->fnmmioAscend(infoPtr->hMMio, &mmckInfo, 0);
498 mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f');
499 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) {
500 WARN("Can't find 'strh' chunk\n");
501 return FALSE;
504 infoPtr->inbih = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
505 if (!infoPtr->inbih) {
506 WARN("Can't alloc input BIH\n");
507 return FALSE;
510 infoPtr->fnmmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize);
511 TRACE("bih.biSize=%ld\n", infoPtr->inbih->biSize);
512 TRACE("bih.biWidth=%ld\n", infoPtr->inbih->biWidth);
513 TRACE("bih.biHeight=%ld\n", infoPtr->inbih->biHeight);
514 TRACE("bih.biPlanes=%d\n", infoPtr->inbih->biPlanes);
515 TRACE("bih.biBitCount=%d\n", infoPtr->inbih->biBitCount);
516 TRACE("bih.biCompression=%ld\n", infoPtr->inbih->biCompression);
517 TRACE("bih.biSizeImage=%ld\n", infoPtr->inbih->biSizeImage);
518 TRACE("bih.biXPelsPerMeter=%ld\n", infoPtr->inbih->biXPelsPerMeter);
519 TRACE("bih.biYPelsPerMeter=%ld\n", infoPtr->inbih->biYPelsPerMeter);
520 TRACE("bih.biClrUsed=%ld\n", infoPtr->inbih->biClrUsed);
521 TRACE("bih.biClrImportant=%ld\n", infoPtr->inbih->biClrImportant);
522 infoPtr->fnmmioAscend(infoPtr->hMMio, &mmckInfo, 0);
524 infoPtr->fnmmioAscend(infoPtr->hMMio, &mmckList, 0);
526 #if 0
527 /* an AVI has 0 or 1 video stream, and to be animated should not contain
528 * an audio stream, so only one strl is allowed
530 mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l');
531 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) {
532 WARN("There should be a single 'strl' list\n");
533 return FALSE;
535 #endif
537 infoPtr->fnmmioAscend(infoPtr->hMMio, &mmckHead, 0);
539 /* no need to read optional JUNK chunk */
541 mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i');
542 if (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) {
543 WARN("Can't find 'movi' list\n");
544 return FALSE;
547 /* FIXME: should handle the 'rec ' LIST when present */
549 infoPtr->lpIndex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
550 infoPtr->mah.dwTotalFrames * sizeof(DWORD));
551 if (!infoPtr->lpIndex) {
552 WARN("Can't alloc index array\n");
553 return FALSE;
556 numFrame = insize = 0;
557 while (infoPtr->fnmmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 &&
558 numFrame < infoPtr->mah.dwTotalFrames) {
559 infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset;
560 if (insize < mmckInfo.cksize)
561 insize = mmckInfo.cksize;
562 numFrame++;
563 infoPtr->fnmmioAscend(infoPtr->hMMio, &mmckInfo, 0);
565 if (numFrame != infoPtr->mah.dwTotalFrames) {
566 WARN("Found %ld frames (/%ld)\n", numFrame, infoPtr->mah.dwTotalFrames);
567 return FALSE;
569 if (insize > infoPtr->ash.dwSuggestedBufferSize) {
570 WARN("insize=%ld suggestedSize=%ld\n", insize, infoPtr->ash.dwSuggestedBufferSize);
571 infoPtr->ash.dwSuggestedBufferSize = insize;
574 infoPtr->indata = HeapAlloc(GetProcessHeap(), 0, infoPtr->ash.dwSuggestedBufferSize);
575 if (!infoPtr->indata) {
576 WARN("Can't alloc input buffer\n");
577 return FALSE;
580 return TRUE;
584 static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
586 DWORD outSize;
588 /* check uncompressed AVI */
589 if (infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ') ||
590 infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) {
591 infoPtr->hic = 0;
592 return TRUE;
595 /* try to get a decompressor for that type */
596 infoPtr->hic = (infoPtr->fnICOpen)(ICTYPE_VIDEO,
597 infoPtr->ash.fccHandler,
598 ICMODE_DECOMPRESS);
599 if (!infoPtr->hic) {
600 WARN("Can't load codec for the file\n");
601 return FALSE;
604 outSize = (infoPtr->fnICSendMessage)(infoPtr->hic,
605 ICM_DECOMPRESS_GET_FORMAT,
606 (DWORD)infoPtr->inbih, 0L);
607 infoPtr->outbih = HeapAlloc(GetProcessHeap(), 0, outSize);
608 if (!infoPtr->outbih) {
609 WARN("Can't alloc output BIH\n");
610 return FALSE;
613 if ((infoPtr->fnICSendMessage)(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
614 (DWORD)infoPtr->inbih,
615 (DWORD)infoPtr->outbih) != ICERR_OK) {
616 WARN("Can't get output BIH\n");
617 return FALSE;
620 infoPtr->outdata = HeapAlloc(GetProcessHeap(), 0, infoPtr->outbih->biSizeImage);
621 if (!infoPtr->outdata) {
622 WARN("Can't alloc output buffer\n");
623 return FALSE;
626 if ((infoPtr->fnICSendMessage)(infoPtr->hic, ICM_DECOMPRESS_BEGIN,
627 (DWORD)infoPtr->inbih,
628 (DWORD)infoPtr->outbih) != ICERR_OK) {
629 WARN("Can't begin decompression\n");
630 return FALSE;
633 return TRUE;
636 static void ANIMATE_Center(ANIMATE_INFO *infoPtr)
638 int x,y,dx,dy;
639 RECT Rect;
640 HWND hWnd=infoPtr->hWnd;
641 HWND hWndParent=GetWindowLongA(hWnd, GWL_HWNDPARENT);
643 if (!hWndParent || !GetWindowRect(hWndParent, &Rect)) return;
645 dx=Rect.right-Rect.left+1;
646 dy=Rect.bottom-Rect.top+1;
647 x=infoPtr->mah.dwWidth < dx ? (dx-infoPtr->mah.dwWidth) >> 1 : 0;
648 y=infoPtr->mah.dwHeight < dy ? (dy-infoPtr->mah.dwHeight) >> 1 : 0;
650 MoveWindow(hWnd, x, y, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight, TRUE);
653 static LRESULT ANIMATE_OpenA(HWND hWnd, WPARAM wParam, LPARAM lParam)
655 ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(hWnd);
656 HINSTANCE hInstance = (HINSTANCE)wParam;
658 ANIMATE_Free(infoPtr);
660 if (!lParam) {
661 TRACE("Closing avi!\n");
662 return TRUE;
665 if (!hInstance)
666 hInstance = GetWindowLongA(hWnd, GWL_HINSTANCE);
668 if (HIWORD(lParam)) {
669 TRACE("(\"%s\");\n", (LPSTR)lParam);
671 if (!ANIMATE_LoadResA(infoPtr, hInstance, (LPSTR)lParam)) {
672 TRACE("No AVI resource found!\n");
673 if (!ANIMATE_LoadFileA(infoPtr, (LPSTR)lParam)) {
674 WARN("No AVI file found!\n");
675 return FALSE;
678 } else {
679 TRACE("(%u);\n", (WORD)LOWORD(lParam));
681 if (!ANIMATE_LoadResA(infoPtr, hInstance,
682 MAKEINTRESOURCEA((INT)lParam))) {
683 WARN("No AVI resource found!\n");
684 return FALSE;
688 if (!ANIMATE_GetAviInfo(infoPtr)) {
689 WARN("Can't get AVI information\n");
690 ANIMATE_Free(infoPtr);
691 return FALSE;
694 if (!ANIMATE_GetAviCodec(infoPtr)) {
695 WARN("Can't get AVI Codec\n");
696 ANIMATE_Free(infoPtr);
697 return FALSE;
700 if (GetWindowLongA(hWnd, GWL_STYLE) & ACS_CENTER) {
702 ANIMATE_Center(infoPtr);
704 } else {
705 /* MoveWindow(hWnd, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight, FALSE);*/
706 SetWindowPos(hWnd, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight,
707 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
710 if (GetWindowLongA(hWnd, GWL_STYLE) & ACS_TRANSPARENT) {
711 FIXME("ACS_TRANSPARENT: NIY\n");
714 if (GetWindowLongA(hWnd, GWL_STYLE) & ACS_AUTOPLAY) {
715 return ANIMATE_Play(hWnd, -1, (LPARAM)MAKELONG(0, infoPtr->mah.dwTotalFrames-1));
718 return TRUE;
722 /* << ANIMATE_Open32W >> */
724 static LRESULT ANIMATE_Stop(HWND hWnd, WPARAM wParam, LPARAM lParam)
726 ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(hWnd);
728 /* nothing opened */
729 if (!infoPtr->hMMio)
730 return FALSE;
732 ANIMATE_DoStop(infoPtr);
733 return TRUE;
737 static LRESULT ANIMATE_Create(HWND hWnd, WPARAM wParam, LPARAM lParam)
739 ANIMATE_INFO* infoPtr;
740 HMODULE hModule = LoadLibraryA("msvfw32.dll");
742 if (!hModule)
743 return FALSE;
745 /* allocate memory for info structure */
746 infoPtr = (ANIMATE_INFO *)COMCTL32_Alloc(sizeof(ANIMATE_INFO));
747 if (!infoPtr) {
748 ERR("could not allocate info memory!\n");
749 return 0;
752 /* Temporary hack until we get dllglue up and running */
753 infoPtr->fnICOpen = (void*)GetProcAddress(hModule, "ICOpen");
754 infoPtr->fnICClose = (void*)GetProcAddress(hModule, "ICClose");
755 infoPtr->fnICSendMessage = (void*)GetProcAddress(hModule, "ICSendMessage");
756 infoPtr->fnICDecompress = (void*)GetProcAddress(hModule, "ICDecompress");
758 TRACE("Animate style=0x%08lx, parent=%08lx\n", GetWindowLongA(hWnd, GWL_STYLE), (DWORD)GetParent(hWnd));
760 /* store crossref hWnd <-> info structure */
761 SetWindowLongA(hWnd, 0, (DWORD)infoPtr);
762 infoPtr->hWnd = hWnd;
764 hModWinmm = LoadLibraryA("WINMM");
766 infoPtr->fnmmioOpenA = (void*)GetProcAddress(hModWinmm, "mmioOpenA");
767 infoPtr->fnmmioClose = (void*)GetProcAddress(hModWinmm, "mmioClose");
768 infoPtr->fnmmioAscend = (void*)GetProcAddress(hModWinmm, "mmioAscend");
769 infoPtr->fnmmioDescend = (void*)GetProcAddress(hModWinmm, "mmioDescend");
770 infoPtr->fnmmioSeek = (void*)GetProcAddress(hModWinmm, "mmioSeek");
771 infoPtr->fnmmioRead = (void*)GetProcAddress(hModWinmm, "mmioRead");
773 InitializeCriticalSection(&infoPtr->cs);
775 return 0;
779 static LRESULT ANIMATE_Destroy(HWND hWnd, WPARAM wParam, LPARAM lParam)
781 ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(hWnd);
784 /* free avi data */
785 ANIMATE_Free(infoPtr);
787 /* free animate info data */
788 COMCTL32_Free(infoPtr);
789 SetWindowLongA(hWnd, 0, 0);
791 FreeLibrary(hModWinmm);
792 return 0;
796 static LRESULT ANIMATE_EraseBackground(HWND hWnd, WPARAM wParam, LPARAM lParam)
798 RECT rect;
800 GetClientRect(hWnd, &rect);
801 #if 0
802 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
804 FillRect((HDC)wParam, &rect, hBrush);
805 DeleteObject(hBrush);
806 #else
807 FillRect((HDC)wParam, &rect, GetSysColorBrush(COLOR_WINDOW));
808 #endif
809 return TRUE;
812 static LRESULT WINAPI ANIMATE_Size(HWND hWnd, WPARAM wParam, LPARAM lParam)
814 ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(hWnd);
816 if (GetWindowLongA(hWnd, GWL_STYLE) & ACS_CENTER) {
817 if (infoPtr->hMMio) {
818 /* centers the animation in the control, invalidates the control
820 ANIMATE_Center(infoPtr);
822 InvalidateRect(hWnd, NULL, TRUE);
824 return TRUE;
827 static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
829 TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hWnd, uMsg, wParam, lParam);
830 if (!ANIMATE_GetInfoPtr(hWnd) && (uMsg != WM_NCCREATE))
831 return DefWindowProcA(hWnd, uMsg, wParam, lParam);
832 switch (uMsg)
834 case ACM_OPENA:
835 return ANIMATE_OpenA(hWnd, wParam, lParam);
837 /* case ACM_OPEN32W: FIXME!! */
838 /* return ANIMATE_Open32W(hWnd, wParam, lParam); */
840 case ACM_PLAY:
841 return ANIMATE_Play(hWnd, wParam, lParam);
843 case ACM_STOP:
844 return ANIMATE_Stop(hWnd, wParam, lParam);
846 case WM_NCCREATE:
847 ANIMATE_Create(hWnd, wParam, lParam);
848 return DefWindowProcA(hWnd, uMsg, wParam, lParam);
850 case WM_NCHITTEST:
851 return HTTRANSPARENT;
853 case WM_DESTROY:
854 ANIMATE_Destroy(hWnd, wParam, lParam);
855 return DefWindowProcA(hWnd, uMsg, wParam, lParam);
857 case WM_ERASEBKGND:
858 ANIMATE_EraseBackground(hWnd, wParam, lParam);
859 break;
861 /* case WM_STYLECHANGED: FIXME shall we do something ?? */
863 case WM_TIMER:
864 return ANIMATE_DrawFrame(ANIMATE_GetInfoPtr(hWnd));
866 case WM_CLOSE:
867 ANIMATE_Free(ANIMATE_GetInfoPtr(hWnd));
868 return TRUE;
870 case WM_PAINT:
871 if (wParam) {
872 ANIMATE_PaintFrame(ANIMATE_GetInfoPtr(hWnd), (HDC)wParam);
873 } else {
874 PAINTSTRUCT ps;
875 HDC hDC = BeginPaint(hWnd, &ps);
876 ANIMATE_PaintFrame(ANIMATE_GetInfoPtr(hWnd), hDC);
877 EndPaint(hWnd, &ps);
879 break;
881 case WM_SIZE:
882 ANIMATE_Size(hWnd, wParam, lParam);
883 return DefWindowProcA(hWnd, uMsg, wParam, lParam);
885 default:
886 if (uMsg >= WM_USER)
887 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
889 return DefWindowProcA(hWnd, uMsg, wParam, lParam);
891 return 0;
895 void ANIMATE_Register(void)
897 WNDCLASSA wndClass;
899 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
900 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
901 wndClass.lpfnWndProc = (WNDPROC)ANIMATE_WindowProc;
902 wndClass.cbClsExtra = 0;
903 wndClass.cbWndExtra = sizeof(ANIMATE_INFO *);
904 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
905 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
906 wndClass.lpszClassName = ANIMATE_CLASSA;
908 RegisterClassA(&wndClass);
912 void ANIMATE_Unregister(void)
914 UnregisterClassA(ANIMATE_CLASSA, (HINSTANCE)NULL);