1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
5 * Copyright 1998, 1999 Eric Kohl
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * I will only improve this control once in a while.
24 * Eric <ekohl@abo.rhein-zeitung.de>
27 * - check for the 'rec ' list in some AVI files
28 * - concurrent access to infoPtr
31 #define COM_NO_WINDOWS_H
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(animate
);
49 HIC (WINAPI
*fnICOpen
)(DWORD
, DWORD
, UINT
);
50 LRESULT (WINAPI
*fnICClose
)(HIC
);
51 LRESULT (WINAPI
*fnICSendMessage
)(HIC
, UINT
, DWORD
, DWORD
);
52 DWORD (WINAPIV
*fnICDecompress
)(HIC
,DWORD
,LPBITMAPINFOHEADER
,LPVOID
,LPBITMAPINFOHEADER
,LPVOID
);
57 /* reference to input stream (file or resource) */
59 HMMIO hMMio
; /* handle to mmio stream */
62 /* information on the loaded AVI file */
65 LPBITMAPINFOHEADER inbih
;
67 /* data for the decompressor */
69 LPBITMAPINFOHEADER outbih
;
72 /* data for the background mechanism */
76 /* data for playing the file */
82 COLORREF transparentColor
;
87 #define ANIMATE_GetInfoPtr(hWnd) ((ANIMATE_INFO *)GetWindowLongA(hWnd, 0))
88 #define ANIMATE_COLOR_NONE 0xffffffff
90 static void ANIMATE_Notify(ANIMATE_INFO
* infoPtr
, UINT notif
)
92 SendMessageA(infoPtr
->hwndNotify
, WM_COMMAND
,
93 MAKEWPARAM(GetDlgCtrlID(infoPtr
->hwndSelf
), notif
),
94 (LPARAM
)infoPtr
->hwndSelf
);
97 static BOOL
ANIMATE_LoadResA(ANIMATE_INFO
*infoPtr
, HINSTANCE hInst
, LPSTR lpName
)
103 hrsrc
= FindResourceA(hInst
, lpName
, "AVI");
107 infoPtr
->hRes
= LoadResource(hInst
, hrsrc
);
111 lpAvi
= LockResource(infoPtr
->hRes
);
115 memset(&mminfo
, 0, sizeof(mminfo
));
116 mminfo
.fccIOProc
= FOURCC_MEM
;
117 mminfo
.pchBuffer
= (LPSTR
)lpAvi
;
118 mminfo
.cchBuffer
= SizeofResource(hInst
, hrsrc
);
119 infoPtr
->hMMio
= mmioOpenA(NULL
, &mminfo
, MMIO_READ
);
120 if (!infoPtr
->hMMio
) {
121 GlobalFree((HGLOBAL
)lpAvi
);
129 static BOOL
ANIMATE_LoadFileA(ANIMATE_INFO
*infoPtr
, LPSTR lpName
)
131 infoPtr
->hMMio
= mmioOpenA((LPSTR
)lpName
, NULL
,
132 MMIO_ALLOCBUF
| MMIO_READ
| MMIO_DENYWRITE
);
141 static LRESULT
ANIMATE_DoStop(ANIMATE_INFO
*infoPtr
)
143 EnterCriticalSection(&infoPtr
->cs
);
145 /* should stop playing */
146 if (infoPtr
->hThread
)
148 if (!TerminateThread(infoPtr
->hThread
,0))
149 WARN("could not destroy animation thread!\n");
150 infoPtr
->hThread
= 0;
152 if (infoPtr
->uTimer
) {
153 KillTimer(infoPtr
->hwndSelf
, infoPtr
->uTimer
);
157 LeaveCriticalSection(&infoPtr
->cs
);
159 ANIMATE_Notify(infoPtr
, ACN_STOP
);
165 static void ANIMATE_Free(ANIMATE_INFO
*infoPtr
)
167 if (infoPtr
->hMMio
) {
168 ANIMATE_DoStop(infoPtr
);
169 mmioClose(infoPtr
->hMMio
, 0);
171 FreeResource(infoPtr
->hRes
);
174 if (infoPtr
->lpIndex
) {
175 HeapFree(GetProcessHeap(), 0, infoPtr
->lpIndex
);
176 infoPtr
->lpIndex
= NULL
;
179 fnIC
.fnICClose(infoPtr
->hic
);
182 if (infoPtr
->inbih
) {
183 HeapFree(GetProcessHeap(), 0, infoPtr
->inbih
);
184 infoPtr
->inbih
= NULL
;
186 if (infoPtr
->outbih
) {
187 HeapFree(GetProcessHeap(), 0, infoPtr
->outbih
);
188 infoPtr
->outbih
= NULL
;
190 if( infoPtr
->indata
)
192 HeapFree(GetProcessHeap(), 0, infoPtr
->indata
);
193 infoPtr
->indata
= NULL
;
195 if( infoPtr
->outdata
)
197 HeapFree(GetProcessHeap(), 0, infoPtr
->outdata
);
198 infoPtr
->outdata
= NULL
;
200 if( infoPtr
->hbmPrevFrame
)
202 DeleteObject(infoPtr
->hbmPrevFrame
);
203 infoPtr
->hbmPrevFrame
= 0;
205 infoPtr
->indata
= infoPtr
->outdata
= NULL
;
206 infoPtr
->hwndSelf
= 0;
209 memset(&infoPtr
->mah
, 0, sizeof(infoPtr
->mah
));
210 memset(&infoPtr
->ash
, 0, sizeof(infoPtr
->ash
));
211 infoPtr
->nFromFrame
= infoPtr
->nToFrame
= infoPtr
->nLoop
= infoPtr
->currFrame
= 0;
213 infoPtr
->transparentColor
= ANIMATE_COLOR_NONE
;
216 static void ANIMATE_TransparentBlt(ANIMATE_INFO
* infoPtr
, HDC hdcDest
, HDC hdcSource
)
222 /* create a transparency mask */
223 hdcMask
= CreateCompatibleDC(hdcDest
);
224 hbmMask
= CreateBitmap(infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, 1,1,NULL
);
225 hbmOld
= SelectObject(hdcMask
, hbmMask
);
227 SetBkColor(hdcSource
,infoPtr
->transparentColor
);
228 BitBlt(hdcMask
,0,0,infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
,hdcSource
,0,0,SRCCOPY
);
230 /* mask the source bitmap */
231 SetBkColor(hdcSource
, RGB(0,0,0));
232 SetTextColor(hdcSource
, RGB(255,255,255));
233 BitBlt(hdcSource
, 0, 0, infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, hdcMask
, 0, 0, SRCAND
);
235 /* mask the destination bitmap */
236 SetBkColor(hdcDest
, RGB(255,255,255));
237 SetTextColor(hdcDest
, RGB(0,0,0));
238 BitBlt(hdcDest
, 0, 0, infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, hdcMask
, 0, 0, SRCAND
);
240 /* combine source and destination */
241 BitBlt(hdcDest
,0,0,infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
,hdcSource
,0,0,SRCPAINT
);
243 SelectObject(hdcMask
, hbmOld
);
244 DeleteObject(hbmMask
);
248 static LRESULT
ANIMATE_PaintFrame(ANIMATE_INFO
* infoPtr
, HDC hDC
)
250 void* pBitmapData
= NULL
;
251 LPBITMAPINFO pBitmapInfo
= NULL
;
262 if (!hDC
|| !infoPtr
->inbih
)
267 pBitmapData
= infoPtr
->outdata
;
268 pBitmapInfo
= (LPBITMAPINFO
)infoPtr
->outbih
;
270 nWidth
= infoPtr
->outbih
->biWidth
;
271 nHeight
= infoPtr
->outbih
->biHeight
;
274 pBitmapData
= infoPtr
->indata
;
275 pBitmapInfo
= (LPBITMAPINFO
)infoPtr
->inbih
;
277 nWidth
= infoPtr
->inbih
->biWidth
;
278 nHeight
= infoPtr
->inbih
->biHeight
;
281 if(!infoPtr
->hbmPrevFrame
)
283 infoPtr
->hbmPrevFrame
=CreateCompatibleBitmap(hDC
, nWidth
,nHeight
);
286 SetDIBits(hDC
, infoPtr
->hbmPrevFrame
, 0, nHeight
, pBitmapData
, (LPBITMAPINFO
)pBitmapInfo
, DIB_RGB_COLORS
);
288 hdcMem
= CreateCompatibleDC(hDC
);
289 hbmOld
= SelectObject(hdcMem
, infoPtr
->hbmPrevFrame
);
292 * we need to get the transparent color even without ACS_TRANSPARENT,
293 * because the style can be changed later on and the color should always
294 * be obtained in the first frame
296 if(infoPtr
->transparentColor
== ANIMATE_COLOR_NONE
)
298 infoPtr
->transparentColor
= GetPixel(hdcMem
,0,0);
301 if(GetWindowLongA(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
303 HDC hdcFinal
= CreateCompatibleDC(hDC
);
304 HBITMAP hbmFinal
= CreateCompatibleBitmap(hDC
,nWidth
, nHeight
);
305 HBITMAP hbmOld2
= SelectObject(hdcFinal
, hbmFinal
);
311 rect
.bottom
= nHeight
;
313 if(!infoPtr
->hbrushBG
)
314 infoPtr
->hbrushBG
= GetCurrentObject(hDC
, OBJ_BRUSH
);
316 FillRect(hdcFinal
, &rect
, infoPtr
->hbrushBG
);
317 ANIMATE_TransparentBlt(infoPtr
, hdcFinal
, hdcMem
);
319 SelectObject(hdcFinal
, hbmOld2
);
320 SelectObject(hdcMem
, hbmFinal
);
322 DeleteObject(infoPtr
->hbmPrevFrame
);
323 infoPtr
->hbmPrevFrame
= hbmFinal
;
326 if (GetWindowLongA(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_CENTER
)
330 GetWindowRect(infoPtr
->hwndSelf
, &rect
);
331 nOffsetX
= ((rect
.right
- rect
.left
) - nWidth
)/2;
332 nOffsetY
= ((rect
.bottom
- rect
.top
) - nHeight
)/2;
334 BitBlt(hDC
, nOffsetX
, nOffsetY
, nWidth
, nHeight
, hdcMem
, 0, 0, SRCCOPY
);
336 SelectObject(hdcMem
, hbmOld
);
341 static LRESULT
ANIMATE_DrawFrame(ANIMATE_INFO
* infoPtr
)
345 TRACE("Drawing frame %d (loop %d)\n", infoPtr
->currFrame
, infoPtr
->nLoop
);
347 EnterCriticalSection(&infoPtr
->cs
);
349 mmioSeek(infoPtr
->hMMio
, infoPtr
->lpIndex
[infoPtr
->currFrame
], SEEK_SET
);
350 mmioRead(infoPtr
->hMMio
, infoPtr
->indata
, infoPtr
->ash
.dwSuggestedBufferSize
);
353 fnIC
.fnICDecompress(infoPtr
->hic
, 0, infoPtr
->inbih
, infoPtr
->indata
,
354 infoPtr
->outbih
, infoPtr
->outdata
) != ICERR_OK
) {
355 LeaveCriticalSection(&infoPtr
->cs
);
356 WARN("Decompression error\n");
360 if ((hDC
= GetDC(infoPtr
->hwndSelf
)) != 0) {
361 ANIMATE_PaintFrame(infoPtr
, hDC
);
362 ReleaseDC(infoPtr
->hwndSelf
, hDC
);
365 if (infoPtr
->currFrame
++ >= infoPtr
->nToFrame
) {
366 infoPtr
->currFrame
= infoPtr
->nFromFrame
;
367 if (infoPtr
->nLoop
!= -1) {
368 if (--infoPtr
->nLoop
== 0) {
369 ANIMATE_DoStop(infoPtr
);
373 LeaveCriticalSection(&infoPtr
->cs
);
378 static DWORD CALLBACK
ANIMATE_AnimationThread(LPVOID ptr_
)
380 ANIMATE_INFO
* infoPtr
= (ANIMATE_INFO
*)ptr_
;
385 WARN("animation structure undefined!\n");
391 if(GetWindowLongA(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
393 hDC
= GetDC(infoPtr
->hwndSelf
);
394 /* sometimes the animation window will be destroyed in between
395 * by the main program, so a ReleaseDC() error msg is possible */
396 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageA(infoPtr
->hwndNotify
,
397 WM_CTLCOLORSTATIC
, (WPARAM
)hDC
,
398 (LPARAM
)infoPtr
->hwndSelf
);
399 ReleaseDC(infoPtr
->hwndSelf
,hDC
);
402 EnterCriticalSection(&infoPtr
->cs
);
403 ANIMATE_DrawFrame(infoPtr
);
404 LeaveCriticalSection(&infoPtr
->cs
);
406 /* time is in microseconds, we should convert it to milliseconds */
407 Sleep((infoPtr
->mah
.dwMicroSecPerFrame
+500)/1000);
412 static LRESULT
ANIMATE_Play(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
414 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
420 if (infoPtr
->hThread
|| infoPtr
->uTimer
) {
421 FIXME("Already playing ? what should I do ??\n");
422 ANIMATE_DoStop(infoPtr
);
425 infoPtr
->nFromFrame
= (INT
)LOWORD(lParam
);
426 infoPtr
->nToFrame
= (INT
)HIWORD(lParam
);
427 infoPtr
->nLoop
= (INT
)wParam
;
429 if (infoPtr
->nToFrame
== 0xFFFF)
430 infoPtr
->nToFrame
= infoPtr
->mah
.dwTotalFrames
- 1;
432 TRACE("(repeat=%d from=%d to=%d);\n",
433 infoPtr
->nLoop
, infoPtr
->nFromFrame
, infoPtr
->nToFrame
);
435 if (infoPtr
->nFromFrame
>= infoPtr
->nToFrame
||
436 infoPtr
->nToFrame
>= infoPtr
->mah
.dwTotalFrames
)
439 infoPtr
->currFrame
= infoPtr
->nFromFrame
;
441 if (GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_TIMER
) {
442 TRACE("Using a timer\n");
443 /* create a timer to display AVI */
444 infoPtr
->uTimer
= SetTimer(hWnd
, 1, infoPtr
->mah
.dwMicroSecPerFrame
/ 1000, NULL
);
448 TRACE("Using an animation thread\n");
449 infoPtr
->hThread
= CreateThread(0,0,ANIMATE_AnimationThread
,(LPVOID
)infoPtr
, 0, &threadID
);
450 if(!infoPtr
->hThread
)
452 ERR("Could not create animation thread!\n");
458 ANIMATE_Notify(infoPtr
, ACN_START
);
464 static BOOL
ANIMATE_GetAviInfo(ANIMATE_INFO
*infoPtr
)
473 if (mmioDescend(infoPtr
->hMMio
, &ckMainRIFF
, NULL
, 0) != 0) {
474 WARN("Can't find 'RIFF' chunk\n");
478 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
479 (ckMainRIFF
.fccType
!= mmioFOURCC('A', 'V', 'I', ' '))) {
480 WARN("Can't find 'AVI ' chunk\n");
484 mmckHead
.fccType
= mmioFOURCC('h', 'd', 'r', 'l');
485 if (mmioDescend(infoPtr
->hMMio
, &mmckHead
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
486 WARN("Can't find 'hdrl' list\n");
490 mmckInfo
.ckid
= mmioFOURCC('a', 'v', 'i', 'h');
491 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckHead
, MMIO_FINDCHUNK
) != 0) {
492 WARN("Can't find 'avih' chunk\n");
496 mmioRead(infoPtr
->hMMio
, (LPSTR
)&infoPtr
->mah
, sizeof(infoPtr
->mah
));
498 TRACE("mah.dwMicroSecPerFrame=%ld\n", infoPtr
->mah
.dwMicroSecPerFrame
);
499 TRACE("mah.dwMaxBytesPerSec=%ld\n", infoPtr
->mah
.dwMaxBytesPerSec
);
500 TRACE("mah.dwPaddingGranularity=%ld\n", infoPtr
->mah
.dwPaddingGranularity
);
501 TRACE("mah.dwFlags=%ld\n", infoPtr
->mah
.dwFlags
);
502 TRACE("mah.dwTotalFrames=%ld\n", infoPtr
->mah
.dwTotalFrames
);
503 TRACE("mah.dwInitialFrames=%ld\n", infoPtr
->mah
.dwInitialFrames
);
504 TRACE("mah.dwStreams=%ld\n", infoPtr
->mah
.dwStreams
);
505 TRACE("mah.dwSuggestedBufferSize=%ld\n", infoPtr
->mah
.dwSuggestedBufferSize
);
506 TRACE("mah.dwWidth=%ld\n", infoPtr
->mah
.dwWidth
);
507 TRACE("mah.dwHeight=%ld\n", infoPtr
->mah
.dwHeight
);
509 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
511 mmckList
.fccType
= mmioFOURCC('s', 't', 'r', 'l');
512 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) != 0) {
513 WARN("Can't find 'strl' list\n");
517 mmckInfo
.ckid
= mmioFOURCC('s', 't', 'r', 'h');
518 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, MMIO_FINDCHUNK
) != 0) {
519 WARN("Can't find 'strh' chunk\n");
523 mmioRead(infoPtr
->hMMio
, (LPSTR
)&infoPtr
->ash
, sizeof(infoPtr
->ash
));
525 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr
->ash
.fccType
)),
526 HIBYTE(LOWORD(infoPtr
->ash
.fccType
)),
527 LOBYTE(HIWORD(infoPtr
->ash
.fccType
)),
528 HIBYTE(HIWORD(infoPtr
->ash
.fccType
)));
529 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr
->ash
.fccHandler
)),
530 HIBYTE(LOWORD(infoPtr
->ash
.fccHandler
)),
531 LOBYTE(HIWORD(infoPtr
->ash
.fccHandler
)),
532 HIBYTE(HIWORD(infoPtr
->ash
.fccHandler
)));
533 TRACE("ash.dwFlags=%ld\n", infoPtr
->ash
.dwFlags
);
534 TRACE("ash.wPriority=%d\n", infoPtr
->ash
.wPriority
);
535 TRACE("ash.wLanguage=%d\n", infoPtr
->ash
.wLanguage
);
536 TRACE("ash.dwInitialFrames=%ld\n", infoPtr
->ash
.dwInitialFrames
);
537 TRACE("ash.dwScale=%ld\n", infoPtr
->ash
.dwScale
);
538 TRACE("ash.dwRate=%ld\n", infoPtr
->ash
.dwRate
);
539 TRACE("ash.dwStart=%ld\n", infoPtr
->ash
.dwStart
);
540 TRACE("ash.dwLength=%ld\n", infoPtr
->ash
.dwLength
);
541 TRACE("ash.dwSuggestedBufferSize=%ld\n", infoPtr
->ash
.dwSuggestedBufferSize
);
542 TRACE("ash.dwQuality=%ld\n", infoPtr
->ash
.dwQuality
);
543 TRACE("ash.dwSampleSize=%ld\n", infoPtr
->ash
.dwSampleSize
);
544 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr
->ash
.rcFrame
.top
, infoPtr
->ash
.rcFrame
.left
,
545 infoPtr
->ash
.rcFrame
.bottom
, infoPtr
->ash
.rcFrame
.right
);
547 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
549 mmckInfo
.ckid
= mmioFOURCC('s', 't', 'r', 'f');
550 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, MMIO_FINDCHUNK
) != 0) {
551 WARN("Can't find 'strh' chunk\n");
555 infoPtr
->inbih
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
556 if (!infoPtr
->inbih
) {
557 WARN("Can't alloc input BIH\n");
561 mmioRead(infoPtr
->hMMio
, (LPSTR
)infoPtr
->inbih
, mmckInfo
.cksize
);
563 TRACE("bih.biSize=%ld\n", infoPtr
->inbih
->biSize
);
564 TRACE("bih.biWidth=%ld\n", infoPtr
->inbih
->biWidth
);
565 TRACE("bih.biHeight=%ld\n", infoPtr
->inbih
->biHeight
);
566 TRACE("bih.biPlanes=%d\n", infoPtr
->inbih
->biPlanes
);
567 TRACE("bih.biBitCount=%d\n", infoPtr
->inbih
->biBitCount
);
568 TRACE("bih.biCompression=%ld\n", infoPtr
->inbih
->biCompression
);
569 TRACE("bih.biSizeImage=%ld\n", infoPtr
->inbih
->biSizeImage
);
570 TRACE("bih.biXPelsPerMeter=%ld\n", infoPtr
->inbih
->biXPelsPerMeter
);
571 TRACE("bih.biYPelsPerMeter=%ld\n", infoPtr
->inbih
->biYPelsPerMeter
);
572 TRACE("bih.biClrUsed=%ld\n", infoPtr
->inbih
->biClrUsed
);
573 TRACE("bih.biClrImportant=%ld\n", infoPtr
->inbih
->biClrImportant
);
575 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
577 mmioAscend(infoPtr
->hMMio
, &mmckList
, 0);
580 /* an AVI has 0 or 1 video stream, and to be animated should not contain
581 * an audio stream, so only one strl is allowed
583 mmckList
.fccType
= mmioFOURCC('s', 't', 'r', 'l');
584 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) == 0) {
585 WARN("There should be a single 'strl' list\n");
590 mmioAscend(infoPtr
->hMMio
, &mmckHead
, 0);
592 /* no need to read optional JUNK chunk */
594 mmckList
.fccType
= mmioFOURCC('m', 'o', 'v', 'i');
595 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
596 WARN("Can't find 'movi' list\n");
600 /* FIXME: should handle the 'rec ' LIST when present */
602 infoPtr
->lpIndex
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
603 infoPtr
->mah
.dwTotalFrames
* sizeof(DWORD
));
604 if (!infoPtr
->lpIndex
) {
605 WARN("Can't alloc index array\n");
609 numFrame
= insize
= 0;
610 while (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, 0) == 0 &&
611 numFrame
< infoPtr
->mah
.dwTotalFrames
) {
612 infoPtr
->lpIndex
[numFrame
] = mmckInfo
.dwDataOffset
;
613 if (insize
< mmckInfo
.cksize
)
614 insize
= mmckInfo
.cksize
;
616 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
618 if (numFrame
!= infoPtr
->mah
.dwTotalFrames
) {
619 WARN("Found %ld frames (/%ld)\n", numFrame
, infoPtr
->mah
.dwTotalFrames
);
622 if (insize
> infoPtr
->ash
.dwSuggestedBufferSize
) {
623 WARN("insize=%ld suggestedSize=%ld\n", insize
, infoPtr
->ash
.dwSuggestedBufferSize
);
624 infoPtr
->ash
.dwSuggestedBufferSize
= insize
;
627 infoPtr
->indata
= HeapAlloc(GetProcessHeap(), 0, infoPtr
->ash
.dwSuggestedBufferSize
);
628 if (!infoPtr
->indata
) {
629 WARN("Can't alloc input buffer\n");
637 static BOOL
ANIMATE_GetAviCodec(ANIMATE_INFO
*infoPtr
)
641 /* check uncompressed AVI */
642 if ((infoPtr
->ash
.fccHandler
== mmioFOURCC('D', 'I', 'B', ' ')) ||
643 (infoPtr
->ash
.fccHandler
== mmioFOURCC('R', 'L', 'E', ' ')) ||
644 (infoPtr
->ash
.fccHandler
== mmioFOURCC(0, 0, 0, 0)))
650 /* try to get a decompressor for that type */
651 infoPtr
->hic
= fnIC
.fnICOpen(ICTYPE_VIDEO
, infoPtr
->ash
.fccHandler
, ICMODE_DECOMPRESS
);
653 WARN("Can't load codec for the file\n");
657 outSize
= fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_GET_FORMAT
,
658 (DWORD
)infoPtr
->inbih
, 0L);
660 infoPtr
->outbih
= HeapAlloc(GetProcessHeap(), 0, outSize
);
661 if (!infoPtr
->outbih
) {
662 WARN("Can't alloc output BIH\n");
666 if (fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_GET_FORMAT
,
667 (DWORD
)infoPtr
->inbih
, (DWORD
)infoPtr
->outbih
) != outSize
) {
668 WARN("Can't get output BIH\n");
672 infoPtr
->outdata
= HeapAlloc(GetProcessHeap(), 0, infoPtr
->outbih
->biSizeImage
);
673 if (!infoPtr
->outdata
) {
674 WARN("Can't alloc output buffer\n");
678 if (fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_BEGIN
,
679 (DWORD
)infoPtr
->inbih
, (DWORD
)infoPtr
->outbih
) != ICERR_OK
) {
680 WARN("Can't begin decompression\n");
687 static LRESULT
ANIMATE_OpenA(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
689 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
690 HINSTANCE hInstance
= (HINSTANCE
)wParam
;
692 ANIMATE_Free(infoPtr
);
693 infoPtr
->hwndSelf
= hWnd
;
696 TRACE("Closing avi!\n");
697 /* installer of thebat! v1.62 requires FALSE here */
698 return (infoPtr
->hMMio
!= 0);
702 hInstance
= (HINSTANCE
)GetWindowLongA(hWnd
, GWL_HINSTANCE
);
704 if (HIWORD(lParam
)) {
705 TRACE("(\"%s\");\n", (LPSTR
)lParam
);
707 if (!ANIMATE_LoadResA(infoPtr
, hInstance
, (LPSTR
)lParam
)) {
708 TRACE("No AVI resource found!\n");
709 if (!ANIMATE_LoadFileA(infoPtr
, (LPSTR
)lParam
)) {
710 WARN("No AVI file found!\n");
715 TRACE("(%u);\n", (WORD
)LOWORD(lParam
));
717 if (!ANIMATE_LoadResA(infoPtr
, hInstance
,
718 MAKEINTRESOURCEA((INT
)lParam
))) {
719 WARN("No AVI resource found!\n");
724 if (!ANIMATE_GetAviInfo(infoPtr
)) {
725 WARN("Can't get AVI information\n");
726 ANIMATE_Free(infoPtr
);
730 if (!ANIMATE_GetAviCodec(infoPtr
)) {
731 WARN("Can't get AVI Codec\n");
732 ANIMATE_Free(infoPtr
);
736 if (!GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_CENTER
) {
737 SetWindowPos(hWnd
, 0, 0, 0, infoPtr
->mah
.dwWidth
, infoPtr
->mah
.dwHeight
,
738 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
741 if (GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_AUTOPLAY
) {
742 return ANIMATE_Play(hWnd
, -1, (LPARAM
)MAKELONG(0, infoPtr
->mah
.dwTotalFrames
-1));
749 /* << ANIMATE_Open32W >> */
751 static LRESULT
ANIMATE_Stop(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
753 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
759 ANIMATE_DoStop(infoPtr
);
764 static LRESULT
ANIMATE_Create(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
766 ANIMATE_INFO
* infoPtr
;
768 if (!fnIC
.hModule
) /* FIXME: not thread safe */
770 /* since there's a circular dep between msvfw32 and comctl32, we could either:
771 * - fix the build chain to allow this circular dep
772 * - handle it by hand
773 * AJ wants the latter :-(
775 fnIC
.hModule
= LoadLibraryA("msvfw32.dll");
776 if (!fnIC
.hModule
) return FALSE
;
778 fnIC
.fnICOpen
= (void*)GetProcAddress(fnIC
.hModule
, "ICOpen");
779 fnIC
.fnICClose
= (void*)GetProcAddress(fnIC
.hModule
, "ICClose");
780 fnIC
.fnICSendMessage
= (void*)GetProcAddress(fnIC
.hModule
, "ICSendMessage");
781 fnIC
.fnICDecompress
= (void*)GetProcAddress(fnIC
.hModule
, "ICDecompress");
784 /* allocate memory for info structure */
785 infoPtr
= (ANIMATE_INFO
*)Alloc(sizeof(ANIMATE_INFO
));
787 ERR("could not allocate info memory!\n");
791 /* store crossref hWnd <-> info structure */
792 SetWindowLongA(hWnd
, 0, (DWORD
)infoPtr
);
793 infoPtr
->hwndSelf
= hWnd
;
794 infoPtr
->hwndNotify
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
795 infoPtr
->transparentColor
= ANIMATE_COLOR_NONE
;
796 infoPtr
->hbmPrevFrame
= 0;
798 TRACE("Animate style=0x%08lx, parent=%08lx\n", GetWindowLongA(hWnd
, GWL_STYLE
), (DWORD
)infoPtr
->hwndNotify
);
800 InitializeCriticalSection(&infoPtr
->cs
);
806 static LRESULT
ANIMATE_Destroy(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
808 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
812 ANIMATE_Free(infoPtr
);
814 /* free animate info data */
816 SetWindowLongA(hWnd
, 0, 0);
822 static LRESULT
ANIMATE_EraseBackground(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
824 ANIMATE_INFO
*infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
828 if(GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_TRANSPARENT
)
830 hBrush
= (HBRUSH
)SendMessageA(infoPtr
->hwndNotify
,WM_CTLCOLORSTATIC
,
831 wParam
, (LPARAM
)hWnd
);
834 GetClientRect(hWnd
, &rect
);
835 FillRect((HDC
)wParam
, &rect
, hBrush
? hBrush
: GetCurrentObject((HDC
)wParam
, OBJ_BRUSH
));
840 static LRESULT WINAPI
ANIMATE_Size(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
842 if (GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_CENTER
) {
843 InvalidateRect(hWnd
, NULL
, TRUE
);
848 static LRESULT WINAPI
ANIMATE_WindowProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
850 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hWnd
, uMsg
, wParam
, lParam
);
851 if (!ANIMATE_GetInfoPtr(hWnd
) && (uMsg
!= WM_NCCREATE
))
852 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
856 return ANIMATE_OpenA(hWnd
, wParam
, lParam
);
858 /* case ACM_OPEN32W: FIXME!! */
859 /* return ANIMATE_Open32W(hWnd, wParam, lParam); */
862 return ANIMATE_Play(hWnd
, wParam
, lParam
);
865 return ANIMATE_Stop(hWnd
, wParam
, lParam
);
868 ANIMATE_Create(hWnd
, wParam
, lParam
);
869 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
872 return HTTRANSPARENT
;
875 ANIMATE_Destroy(hWnd
, wParam
, lParam
);
876 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
879 ANIMATE_EraseBackground(hWnd
, wParam
, lParam
);
882 /* case WM_STYLECHANGED: FIXME shall we do something ?? */
885 if (GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_TRANSPARENT
)
887 ANIMATE_INFO
* infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
888 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageA(infoPtr
->hwndNotify
,
890 wParam
, (LPARAM
)hWnd
);
892 return ANIMATE_DrawFrame(ANIMATE_GetInfoPtr(hWnd
));
895 ANIMATE_Free(ANIMATE_GetInfoPtr(hWnd
));
900 ANIMATE_INFO
* infoPtr
= ANIMATE_GetInfoPtr(hWnd
);
902 /* the animation isn't playing, or has not decompressed
903 * (and displayed) the first frame yet, don't paint
905 if ((!infoPtr
->uTimer
&& !infoPtr
->hThread
) ||
906 !infoPtr
->hbmPrevFrame
)
908 /* default paint handling */
909 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
912 if (GetWindowLongA(hWnd
, GWL_STYLE
) & ACS_TRANSPARENT
)
913 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageA(infoPtr
->hwndNotify
,
915 wParam
, (LPARAM
)hWnd
);
919 EnterCriticalSection(&infoPtr
->cs
);
920 ANIMATE_PaintFrame(infoPtr
, (HDC
)wParam
);
921 LeaveCriticalSection(&infoPtr
->cs
);
926 HDC hDC
= BeginPaint(hWnd
, &ps
);
928 EnterCriticalSection(&infoPtr
->cs
);
929 ANIMATE_PaintFrame(infoPtr
, hDC
);
930 LeaveCriticalSection(&infoPtr
->cs
);
938 ANIMATE_Size(hWnd
, wParam
, lParam
);
939 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
942 if ((uMsg
>= WM_USER
) && (uMsg
< WM_APP
))
943 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
, lParam
);
945 return DefWindowProcA(hWnd
, uMsg
, wParam
, lParam
);
950 void ANIMATE_Register(void)
954 ZeroMemory(&wndClass
, sizeof(WNDCLASSA
));
955 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
956 wndClass
.lpfnWndProc
= (WNDPROC
)ANIMATE_WindowProc
;
957 wndClass
.cbClsExtra
= 0;
958 wndClass
.cbWndExtra
= sizeof(ANIMATE_INFO
*);
959 wndClass
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
960 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
961 wndClass
.lpszClassName
= ANIMATE_CLASSA
;
963 RegisterClassA(&wndClass
);
967 void ANIMATE_Unregister(void)
969 UnregisterClassA(ANIMATE_CLASSA
, NULL
);