1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
5 * Copyright 1998, 1999 Eric Kohl
9 * I will only improve this control once in a while.
10 * Eric <ekohl@abo.rhein-zeitung.de>
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
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(animate
);
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) */
51 HMMIO hMMio
; /* handle to mmio stream */
53 /* information on the loaded AVI file */
56 LPBITMAPINFOHEADER inbih
;
58 /* data for the decompressor */
60 LPBITMAPINFOHEADER outbih
;
63 /* data for the background mechanism */
67 /* data for playing the file */
72 /* Background frame info*/
77 #define ANIMATE_GetInfoPtr(hWnd) ((ANIMATE_INFO *)GetWindowLongA(hWnd, 0))
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
)
94 hrsrc
= FindResourceA(hInst
, lpName
, "AVI");
98 infoPtr
->hRes
= LoadResource(hInst
, hrsrc
);
102 lpAvi
= LockResource(infoPtr
->hRes
);
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
);
117 infoPtr
->bkgFrameb
=(HBITMAP
)NULL
;
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
);
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
);
149 LeaveCriticalSection(&infoPtr
->cs
);
151 ANIMATE_Notify(infoPtr
, ACN_STOP
);
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
;
168 FreeResource(infoPtr
->hRes
);
171 if (infoPtr
->lpIndex
) {
172 HeapFree(GetProcessHeap(), 0, infoPtr
->lpIndex
);
173 infoPtr
->lpIndex
= NULL
;
176 (infoPtr
->fnICClose
)(infoPtr
->hic
);
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
;
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
)
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
,
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
,
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
) {
242 /*FIXME: Not supported Yet.*/
245 infoPtr
->bkColor
= (LPVOID
)((LPSTR
)infoPtr
->inbih
+ (WORD
)(((LPBITMAPINFO
)infoPtr
->inbih
)->bmiHeader
.biSize
));
250 infoPtr
->bkColor
= (LPVOID
)GetPixel(hdcSrc
, 0, 0);
251 /*FIXME:Has not been test with more than 8bpp, errors are possible*/
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
) {
272 /*FIXME: Not supported Yet.*/
275 SetBkColor(hdcSrc
, infoPtr
->bkColor
[(((BYTE
*)infoPtr
->indata
)[0])]);
280 SetBkColor(hdcSrc
, (COLORREF
)infoPtr
->bkColor
);
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
);
309 DeleteObject(hbmMem
);
310 DeleteObject(hbmMem2
);
311 DeleteObject(hbmMem3
);
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
,
325 static LRESULT
ANIMATE_DrawFrame(ANIMATE_INFO
* infoPtr
)
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
);
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");
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
);
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
);
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
)
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
);
405 TRACE("Using the service thread\n");
407 infoPtr
->hService
= SERVICE_AddTimer(infoPtr
->mah
.dwMicroSecPerFrame
/ 1000,
408 ANIMATE_ServiceCallback
, (DWORD
)infoPtr
);
411 ANIMATE_Notify(infoPtr
, ACN_START
);
417 static BOOL
ANIMATE_GetAviInfo(ANIMATE_INFO
*infoPtr
)
426 if (infoPtr
->fnmmioDescend(infoPtr
->hMMio
, &ckMainRIFF
, NULL
, 0) != 0) {
427 WARN("Can't find 'RIFF' chunk\n");
431 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
432 (ckMainRIFF
.fccType
!= mmioFOURCC('A', 'V', 'I', ' '))) {
433 WARN("Can't find 'AVI ' chunk\n");
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");
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");
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");
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");
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");
504 infoPtr
->inbih
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
505 if (!infoPtr
->inbih
) {
506 WARN("Can't alloc input BIH\n");
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);
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");
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");
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");
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
;
563 infoPtr
->fnmmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
565 if (numFrame
!= infoPtr
->mah
.dwTotalFrames
) {
566 WARN("Found %ld frames (/%ld)\n", numFrame
, infoPtr
->mah
.dwTotalFrames
);
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");
584 static BOOL
ANIMATE_GetAviCodec(ANIMATE_INFO
*infoPtr
)
588 /* check uncompressed AVI */
589 if (infoPtr
->ash
.fccHandler
== mmioFOURCC('D', 'I', 'B', ' ') ||
590 infoPtr
->ash
.fccHandler
== mmioFOURCC('R', 'L', 'E', ' ')) {
595 /* try to get a decompressor for that type */
596 infoPtr
->hic
= (infoPtr
->fnICOpen
)(ICTYPE_VIDEO
,
597 infoPtr
->ash
.fccHandler
,
600 WARN("Can't load codec for the file\n");
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");
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");
620 infoPtr
->outdata
= HeapAlloc(GetProcessHeap(), 0, infoPtr
->outbih
->biSizeImage
);
621 if (!infoPtr
->outdata
) {
622 WARN("Can't alloc output buffer\n");
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");
636 static void ANIMATE_Center(ANIMATE_INFO
*infoPtr
)
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
);
661 TRACE("Closing avi!\n");
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");
679 TRACE("(%u);\n", (WORD
)LOWORD(lParam
));
681 if (!ANIMATE_LoadResA(infoPtr
, hInstance
,
682 MAKEINTRESOURCEA((INT
)lParam
))) {
683 WARN("No AVI resource found!\n");
688 if (!ANIMATE_GetAviInfo(infoPtr
)) {
689 WARN("Can't get AVI information\n");
690 ANIMATE_Free(infoPtr
);
694 if (!ANIMATE_GetAviCodec(infoPtr
)) {
695 WARN("Can't get AVI Codec\n");
696 ANIMATE_Free(infoPtr
);
700 if (GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_CENTER
) {
702 ANIMATE_Center(infoPtr
);
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));
722 /* << ANIMATE_Open32W >> */
724 static LRESULT
ANIMATE_Stop(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
726 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
732 ANIMATE_DoStop(infoPtr
);
737 static LRESULT
ANIMATE_Create(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
739 ANIMATE_INFO
* infoPtr
;
740 HMODULE hModule
= LoadLibraryA("msvfw32.dll");
745 /* allocate memory for info structure */
746 infoPtr
= (ANIMATE_INFO
*)COMCTL32_Alloc(sizeof(ANIMATE_INFO
));
748 ERR("could not allocate info memory!\n");
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
);
779 static LRESULT
ANIMATE_Destroy(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
781 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
785 ANIMATE_Free(infoPtr
);
787 /* free animate info data */
788 COMCTL32_Free(infoPtr
);
789 SetWindowLongA(hWnd
, 0, 0);
791 FreeLibrary(hModWinmm
);
796 static LRESULT
ANIMATE_EraseBackground(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
800 GetClientRect(hWnd
, &rect
);
802 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
804 FillRect((HDC
)wParam
, &rect
, hBrush
);
805 DeleteObject(hBrush
);
807 FillRect((HDC
)wParam
, &rect
, GetSysColorBrush(COLOR_WINDOW
));
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
);
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
);
835 return ANIMATE_OpenA(hWnd
, wParam
, lParam
);
837 /* case ACM_OPEN32W: FIXME!! */
838 /* return ANIMATE_Open32W(hWnd, wParam, lParam); */
841 return ANIMATE_Play(hWnd
, wParam
, lParam
);
844 return ANIMATE_Stop(hWnd
, wParam
, lParam
);
847 ANIMATE_Create(hWnd
, wParam
, lParam
);
848 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
851 return HTTRANSPARENT
;
854 ANIMATE_Destroy(hWnd
, wParam
, lParam
);
855 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
858 ANIMATE_EraseBackground(hWnd
, wParam
, lParam
);
861 /* case WM_STYLECHANGED: FIXME shall we do something ?? */
864 return ANIMATE_DrawFrame(ANIMATE_GetInfoPtr(hWnd
));
867 ANIMATE_Free(ANIMATE_GetInfoPtr(hWnd
));
872 ANIMATE_PaintFrame(ANIMATE_GetInfoPtr(hWnd
), (HDC
)wParam
);
875 HDC hDC
= BeginPaint(hWnd
, &ps
);
876 ANIMATE_PaintFrame(ANIMATE_GetInfoPtr(hWnd
), hDC
);
882 ANIMATE_Size(hWnd
, wParam
, lParam
);
883 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
887 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
, lParam
);
889 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
895 void ANIMATE_Register(void)
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
);