1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
5 * Copyright 1998, 1999 Eric Kohl
6 * Copyright 1999 Eric Pouech
7 * Copyright 2005 Dimitrie O. Paun
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * I will only improve this control once in a while.
25 * Eric <ekohl@abo.rhein-zeitung.de>
28 * - check for the 'rec ' list in some AVI files
29 * - concurrent access to infoPtr
32 #define COM_NO_WINDOWS_H
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(animate
);
50 HIC (WINAPI
*fnICOpen
)(DWORD
, DWORD
, UINT
);
51 LRESULT (WINAPI
*fnICClose
)(HIC
);
52 LRESULT (WINAPI
*fnICSendMessage
)(HIC
, UINT
, DWORD
, DWORD
);
53 DWORD (WINAPIV
*fnICDecompress
)(HIC
,DWORD
,LPBITMAPINFOHEADER
,LPVOID
,LPBITMAPINFOHEADER
,LPVOID
);
58 /* reference to input stream (file or resource) */
60 HMMIO hMMio
; /* handle to mmio stream */
63 /* information on the loaded AVI file */
66 LPBITMAPINFOHEADER inbih
;
68 /* data for the decompressor */
70 LPBITMAPINFOHEADER outbih
;
73 /* data for the background mechanism */
79 /* data for playing the file */
85 COLORREF transparentColor
;
90 #define ANIMATE_COLOR_NONE 0xffffffff
92 static void ANIMATE_Notify(ANIMATE_INFO
*infoPtr
, UINT notif
)
94 SendMessageW(infoPtr
->hwndNotify
, WM_COMMAND
,
95 MAKEWPARAM(GetDlgCtrlID(infoPtr
->hwndSelf
), notif
),
96 (LPARAM
)infoPtr
->hwndSelf
);
99 static BOOL
ANIMATE_LoadResW(ANIMATE_INFO
*infoPtr
, HINSTANCE hInst
, LPWSTR lpName
)
101 static const WCHAR aviW
[] = { 'A', 'V', 'I', 0 };
106 hrsrc
= FindResourceW(hInst
, lpName
, aviW
);
110 infoPtr
->hRes
= LoadResource(hInst
, hrsrc
);
114 lpAvi
= LockResource(infoPtr
->hRes
);
118 memset(&mminfo
, 0, sizeof(mminfo
));
119 mminfo
.fccIOProc
= FOURCC_MEM
;
120 mminfo
.pchBuffer
= (LPSTR
)lpAvi
;
121 mminfo
.cchBuffer
= SizeofResource(hInst
, hrsrc
);
122 infoPtr
->hMMio
= mmioOpenW(NULL
, &mminfo
, MMIO_READ
);
125 FreeResource(infoPtr
->hRes
);
133 static BOOL
ANIMATE_LoadFileW(ANIMATE_INFO
*infoPtr
, LPWSTR lpName
)
135 infoPtr
->hMMio
= mmioOpenW(lpName
, 0, MMIO_ALLOCBUF
| MMIO_READ
| MMIO_DENYWRITE
);
137 return (BOOL
)infoPtr
->hMMio
;
141 static BOOL
ANIMATE_DoStop(ANIMATE_INFO
*infoPtr
)
143 EnterCriticalSection(&infoPtr
->cs
);
145 /* should stop playing */
146 if (infoPtr
->hThread
)
148 HANDLE handle
= infoPtr
->hThread
;
150 TRACE("stopping animation thread\n");
151 infoPtr
->hThread
= 0;
152 SetEvent( infoPtr
->hStopEvent
);
154 if (infoPtr
->threadId
!= GetCurrentThreadId())
156 LeaveCriticalSection(&infoPtr
->cs
); /* leave it a chance to run */
157 WaitForSingleObject( handle
, INFINITE
);
158 TRACE("animation thread stopped\n");
159 EnterCriticalSection(&infoPtr
->cs
);
162 CloseHandle( handle
);
163 CloseHandle( infoPtr
->hStopEvent
);
164 infoPtr
->hStopEvent
= 0;
166 if (infoPtr
->uTimer
) {
167 KillTimer(infoPtr
->hwndSelf
, infoPtr
->uTimer
);
171 LeaveCriticalSection(&infoPtr
->cs
);
173 ANIMATE_Notify(infoPtr
, ACN_STOP
);
179 static void ANIMATE_Free(ANIMATE_INFO
*infoPtr
)
181 if (infoPtr
->hMMio
) {
182 ANIMATE_DoStop(infoPtr
);
183 mmioClose(infoPtr
->hMMio
, 0);
185 FreeResource(infoPtr
->hRes
);
188 HeapFree(GetProcessHeap(), 0, infoPtr
->lpIndex
);
189 infoPtr
->lpIndex
= NULL
;
191 fnIC
.fnICClose(infoPtr
->hic
);
194 HeapFree(GetProcessHeap(), 0, infoPtr
->inbih
);
195 infoPtr
->inbih
= NULL
;
196 HeapFree(GetProcessHeap(), 0, infoPtr
->outbih
);
197 infoPtr
->outbih
= NULL
;
198 HeapFree(GetProcessHeap(), 0, infoPtr
->indata
);
199 infoPtr
->indata
= NULL
;
200 HeapFree(GetProcessHeap(), 0, infoPtr
->outdata
);
201 infoPtr
->outdata
= NULL
;
202 if( infoPtr
->hbmPrevFrame
)
204 DeleteObject(infoPtr
->hbmPrevFrame
);
205 infoPtr
->hbmPrevFrame
= 0;
208 memset(&infoPtr
->mah
, 0, sizeof(infoPtr
->mah
));
209 memset(&infoPtr
->ash
, 0, sizeof(infoPtr
->ash
));
210 infoPtr
->nFromFrame
= infoPtr
->nToFrame
= infoPtr
->nLoop
= infoPtr
->currFrame
= 0;
212 infoPtr
->transparentColor
= ANIMATE_COLOR_NONE
;
215 static void ANIMATE_TransparentBlt(ANIMATE_INFO
*infoPtr
, HDC hdcDest
, HDC hdcSource
)
221 /* create a transparency mask */
222 hdcMask
= CreateCompatibleDC(hdcDest
);
223 hbmMask
= CreateBitmap(infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, 1,1,NULL
);
224 hbmOld
= SelectObject(hdcMask
, hbmMask
);
226 SetBkColor(hdcSource
,infoPtr
->transparentColor
);
227 BitBlt(hdcMask
,0,0,infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
,hdcSource
,0,0,SRCCOPY
);
229 /* mask the source bitmap */
230 SetBkColor(hdcSource
, RGB(0,0,0));
231 SetTextColor(hdcSource
, RGB(255,255,255));
232 BitBlt(hdcSource
, 0, 0, infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, hdcMask
, 0, 0, SRCAND
);
234 /* mask the destination bitmap */
235 SetBkColor(hdcDest
, RGB(255,255,255));
236 SetTextColor(hdcDest
, RGB(0,0,0));
237 BitBlt(hdcDest
, 0, 0, infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, hdcMask
, 0, 0, SRCAND
);
239 /* combine source and destination */
240 BitBlt(hdcDest
,0,0,infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
,hdcSource
,0,0,SRCPAINT
);
242 SelectObject(hdcMask
, hbmOld
);
243 DeleteObject(hbmMask
);
247 static BOOL
ANIMATE_PaintFrame(ANIMATE_INFO
* infoPtr
, HDC hDC
)
249 void* pBitmapData
= NULL
;
250 LPBITMAPINFO pBitmapInfo
= NULL
;
261 if (!hDC
|| !infoPtr
->inbih
)
266 pBitmapData
= infoPtr
->outdata
;
267 pBitmapInfo
= (LPBITMAPINFO
)infoPtr
->outbih
;
269 nWidth
= infoPtr
->outbih
->biWidth
;
270 nHeight
= infoPtr
->outbih
->biHeight
;
273 pBitmapData
= infoPtr
->indata
;
274 pBitmapInfo
= (LPBITMAPINFO
)infoPtr
->inbih
;
276 nWidth
= infoPtr
->inbih
->biWidth
;
277 nHeight
= infoPtr
->inbih
->biHeight
;
280 if(!infoPtr
->hbmPrevFrame
)
282 infoPtr
->hbmPrevFrame
=CreateCompatibleBitmap(hDC
, nWidth
,nHeight
);
285 SetDIBits(hDC
, infoPtr
->hbmPrevFrame
, 0, nHeight
, pBitmapData
, (LPBITMAPINFO
)pBitmapInfo
, DIB_RGB_COLORS
);
287 hdcMem
= CreateCompatibleDC(hDC
);
288 hbmOld
= SelectObject(hdcMem
, infoPtr
->hbmPrevFrame
);
291 * we need to get the transparent color even without ACS_TRANSPARENT,
292 * because the style can be changed later on and the color should always
293 * be obtained in the first frame
295 if(infoPtr
->transparentColor
== ANIMATE_COLOR_NONE
)
297 infoPtr
->transparentColor
= GetPixel(hdcMem
,0,0);
300 if(GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
302 HDC hdcFinal
= CreateCompatibleDC(hDC
);
303 HBITMAP hbmFinal
= CreateCompatibleBitmap(hDC
,nWidth
, nHeight
);
304 HBITMAP hbmOld2
= SelectObject(hdcFinal
, hbmFinal
);
310 rect
.bottom
= nHeight
;
312 if(!infoPtr
->hbrushBG
)
313 infoPtr
->hbrushBG
= GetCurrentObject(hDC
, OBJ_BRUSH
);
315 FillRect(hdcFinal
, &rect
, infoPtr
->hbrushBG
);
316 ANIMATE_TransparentBlt(infoPtr
, hdcFinal
, hdcMem
);
318 SelectObject(hdcFinal
, hbmOld2
);
319 SelectObject(hdcMem
, hbmFinal
);
321 DeleteObject(infoPtr
->hbmPrevFrame
);
322 infoPtr
->hbmPrevFrame
= hbmFinal
;
325 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_CENTER
)
329 GetWindowRect(infoPtr
->hwndSelf
, &rect
);
330 nOffsetX
= ((rect
.right
- rect
.left
) - nWidth
)/2;
331 nOffsetY
= ((rect
.bottom
- rect
.top
) - nHeight
)/2;
333 BitBlt(hDC
, nOffsetX
, nOffsetY
, nWidth
, nHeight
, hdcMem
, 0, 0, SRCCOPY
);
335 SelectObject(hdcMem
, hbmOld
);
340 static BOOL
ANIMATE_DrawFrame(ANIMATE_INFO
*infoPtr
)
344 TRACE("Drawing frame %d (loop %d)\n", infoPtr
->currFrame
, infoPtr
->nLoop
);
346 EnterCriticalSection(&infoPtr
->cs
);
348 mmioSeek(infoPtr
->hMMio
, infoPtr
->lpIndex
[infoPtr
->currFrame
], SEEK_SET
);
349 mmioRead(infoPtr
->hMMio
, infoPtr
->indata
, infoPtr
->ash
.dwSuggestedBufferSize
);
352 fnIC
.fnICDecompress(infoPtr
->hic
, 0, infoPtr
->inbih
, infoPtr
->indata
,
353 infoPtr
->outbih
, infoPtr
->outdata
) != ICERR_OK
) {
354 LeaveCriticalSection(&infoPtr
->cs
);
355 WARN("Decompression error\n");
359 if ((hDC
= GetDC(infoPtr
->hwndSelf
)) != 0) {
360 ANIMATE_PaintFrame(infoPtr
, hDC
);
361 ReleaseDC(infoPtr
->hwndSelf
, hDC
);
364 if (infoPtr
->currFrame
++ >= infoPtr
->nToFrame
) {
365 infoPtr
->currFrame
= infoPtr
->nFromFrame
;
366 if (infoPtr
->nLoop
!= -1) {
367 if (--infoPtr
->nLoop
== 0) {
368 ANIMATE_DoStop(infoPtr
);
372 LeaveCriticalSection(&infoPtr
->cs
);
377 static DWORD CALLBACK
ANIMATE_AnimationThread(LPVOID ptr_
)
379 ANIMATE_INFO
*infoPtr
= (ANIMATE_INFO
*)ptr_
;
385 EnterCriticalSection(&infoPtr
->cs
);
386 ANIMATE_DrawFrame(infoPtr
);
387 timeout
= infoPtr
->mah
.dwMicroSecPerFrame
;
388 event
= infoPtr
->hStopEvent
;
389 LeaveCriticalSection(&infoPtr
->cs
);
391 /* time is in microseconds, we should convert it to milliseconds */
392 if ((event
== 0) || WaitForSingleObject( event
, (timeout
+500)/1000) == WAIT_OBJECT_0
)
398 static LRESULT
ANIMATE_Play(ANIMATE_INFO
*infoPtr
, UINT cRepeat
, WORD wFrom
, WORD wTo
)
404 if (infoPtr
->hThread
|| infoPtr
->uTimer
) {
405 TRACE("Already playing\n");
409 infoPtr
->nFromFrame
= wFrom
;
410 infoPtr
->nToFrame
= wTo
;
411 infoPtr
->nLoop
= cRepeat
;
413 if (infoPtr
->nToFrame
== 0xFFFF)
414 infoPtr
->nToFrame
= infoPtr
->mah
.dwTotalFrames
- 1;
416 TRACE("(repeat=%d from=%d to=%d);\n",
417 infoPtr
->nLoop
, infoPtr
->nFromFrame
, infoPtr
->nToFrame
);
419 if (infoPtr
->nFromFrame
>= infoPtr
->nToFrame
||
420 infoPtr
->nToFrame
>= infoPtr
->mah
.dwTotalFrames
)
423 infoPtr
->currFrame
= infoPtr
->nFromFrame
;
425 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TIMER
)
427 TRACE("Using a timer\n");
428 /* create a timer to display AVI */
429 infoPtr
->uTimer
= SetTimer(infoPtr
->hwndSelf
, 1,
430 infoPtr
->mah
.dwMicroSecPerFrame
/ 1000, NULL
);
434 if(GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
436 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageW(infoPtr
->hwndNotify
,
437 WM_CTLCOLORSTATIC
, 0,
438 (LPARAM
)infoPtr
->hwndSelf
);
441 TRACE("Using an animation thread\n");
442 infoPtr
->hStopEvent
= CreateEventW( NULL
, TRUE
, FALSE
, NULL
);
443 infoPtr
->hThread
= CreateThread(0, 0, ANIMATE_AnimationThread
,
444 (LPVOID
)infoPtr
, 0, &infoPtr
->threadId
);
445 if(!infoPtr
->hThread
)
447 ERR("Could not create animation thread!\n");
453 ANIMATE_Notify(infoPtr
, ACN_START
);
459 static BOOL
ANIMATE_GetAviInfo(ANIMATE_INFO
*infoPtr
)
468 if (mmioDescend(infoPtr
->hMMio
, &ckMainRIFF
, NULL
, 0) != 0) {
469 WARN("Can't find 'RIFF' chunk\n");
473 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
474 (ckMainRIFF
.fccType
!= mmioFOURCC('A', 'V', 'I', ' '))) {
475 WARN("Can't find 'AVI ' chunk\n");
479 mmckHead
.fccType
= mmioFOURCC('h', 'd', 'r', 'l');
480 if (mmioDescend(infoPtr
->hMMio
, &mmckHead
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
481 WARN("Can't find 'hdrl' list\n");
485 mmckInfo
.ckid
= mmioFOURCC('a', 'v', 'i', 'h');
486 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckHead
, MMIO_FINDCHUNK
) != 0) {
487 WARN("Can't find 'avih' chunk\n");
491 mmioRead(infoPtr
->hMMio
, (LPSTR
)&infoPtr
->mah
, sizeof(infoPtr
->mah
));
493 TRACE("mah.dwMicroSecPerFrame=%ld\n", infoPtr
->mah
.dwMicroSecPerFrame
);
494 TRACE("mah.dwMaxBytesPerSec=%ld\n", infoPtr
->mah
.dwMaxBytesPerSec
);
495 TRACE("mah.dwPaddingGranularity=%ld\n", infoPtr
->mah
.dwPaddingGranularity
);
496 TRACE("mah.dwFlags=%ld\n", infoPtr
->mah
.dwFlags
);
497 TRACE("mah.dwTotalFrames=%ld\n", infoPtr
->mah
.dwTotalFrames
);
498 TRACE("mah.dwInitialFrames=%ld\n", infoPtr
->mah
.dwInitialFrames
);
499 TRACE("mah.dwStreams=%ld\n", infoPtr
->mah
.dwStreams
);
500 TRACE("mah.dwSuggestedBufferSize=%ld\n", infoPtr
->mah
.dwSuggestedBufferSize
);
501 TRACE("mah.dwWidth=%ld\n", infoPtr
->mah
.dwWidth
);
502 TRACE("mah.dwHeight=%ld\n", infoPtr
->mah
.dwHeight
);
504 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
506 mmckList
.fccType
= mmioFOURCC('s', 't', 'r', 'l');
507 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) != 0) {
508 WARN("Can't find 'strl' list\n");
512 mmckInfo
.ckid
= mmioFOURCC('s', 't', 'r', 'h');
513 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, MMIO_FINDCHUNK
) != 0) {
514 WARN("Can't find 'strh' chunk\n");
518 mmioRead(infoPtr
->hMMio
, (LPSTR
)&infoPtr
->ash
, sizeof(infoPtr
->ash
));
520 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr
->ash
.fccType
)),
521 HIBYTE(LOWORD(infoPtr
->ash
.fccType
)),
522 LOBYTE(HIWORD(infoPtr
->ash
.fccType
)),
523 HIBYTE(HIWORD(infoPtr
->ash
.fccType
)));
524 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr
->ash
.fccHandler
)),
525 HIBYTE(LOWORD(infoPtr
->ash
.fccHandler
)),
526 LOBYTE(HIWORD(infoPtr
->ash
.fccHandler
)),
527 HIBYTE(HIWORD(infoPtr
->ash
.fccHandler
)));
528 TRACE("ash.dwFlags=%ld\n", infoPtr
->ash
.dwFlags
);
529 TRACE("ash.wPriority=%d\n", infoPtr
->ash
.wPriority
);
530 TRACE("ash.wLanguage=%d\n", infoPtr
->ash
.wLanguage
);
531 TRACE("ash.dwInitialFrames=%ld\n", infoPtr
->ash
.dwInitialFrames
);
532 TRACE("ash.dwScale=%ld\n", infoPtr
->ash
.dwScale
);
533 TRACE("ash.dwRate=%ld\n", infoPtr
->ash
.dwRate
);
534 TRACE("ash.dwStart=%ld\n", infoPtr
->ash
.dwStart
);
535 TRACE("ash.dwLength=%ld\n", infoPtr
->ash
.dwLength
);
536 TRACE("ash.dwSuggestedBufferSize=%ld\n", infoPtr
->ash
.dwSuggestedBufferSize
);
537 TRACE("ash.dwQuality=%ld\n", infoPtr
->ash
.dwQuality
);
538 TRACE("ash.dwSampleSize=%ld\n", infoPtr
->ash
.dwSampleSize
);
539 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr
->ash
.rcFrame
.top
, infoPtr
->ash
.rcFrame
.left
,
540 infoPtr
->ash
.rcFrame
.bottom
, infoPtr
->ash
.rcFrame
.right
);
542 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
544 mmckInfo
.ckid
= mmioFOURCC('s', 't', 'r', 'f');
545 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, MMIO_FINDCHUNK
) != 0) {
546 WARN("Can't find 'strh' chunk\n");
550 infoPtr
->inbih
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
551 if (!infoPtr
->inbih
) {
552 WARN("Can't alloc input BIH\n");
556 mmioRead(infoPtr
->hMMio
, (LPSTR
)infoPtr
->inbih
, mmckInfo
.cksize
);
558 TRACE("bih.biSize=%ld\n", infoPtr
->inbih
->biSize
);
559 TRACE("bih.biWidth=%ld\n", infoPtr
->inbih
->biWidth
);
560 TRACE("bih.biHeight=%ld\n", infoPtr
->inbih
->biHeight
);
561 TRACE("bih.biPlanes=%d\n", infoPtr
->inbih
->biPlanes
);
562 TRACE("bih.biBitCount=%d\n", infoPtr
->inbih
->biBitCount
);
563 TRACE("bih.biCompression=%ld\n", infoPtr
->inbih
->biCompression
);
564 TRACE("bih.biSizeImage=%ld\n", infoPtr
->inbih
->biSizeImage
);
565 TRACE("bih.biXPelsPerMeter=%ld\n", infoPtr
->inbih
->biXPelsPerMeter
);
566 TRACE("bih.biYPelsPerMeter=%ld\n", infoPtr
->inbih
->biYPelsPerMeter
);
567 TRACE("bih.biClrUsed=%ld\n", infoPtr
->inbih
->biClrUsed
);
568 TRACE("bih.biClrImportant=%ld\n", infoPtr
->inbih
->biClrImportant
);
570 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
572 mmioAscend(infoPtr
->hMMio
, &mmckList
, 0);
575 /* an AVI has 0 or 1 video stream, and to be animated should not contain
576 * an audio stream, so only one strl is allowed
578 mmckList
.fccType
= mmioFOURCC('s', 't', 'r', 'l');
579 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) == 0) {
580 WARN("There should be a single 'strl' list\n");
585 mmioAscend(infoPtr
->hMMio
, &mmckHead
, 0);
587 /* no need to read optional JUNK chunk */
589 mmckList
.fccType
= mmioFOURCC('m', 'o', 'v', 'i');
590 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
591 WARN("Can't find 'movi' list\n");
595 /* FIXME: should handle the 'rec ' LIST when present */
597 infoPtr
->lpIndex
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
598 infoPtr
->mah
.dwTotalFrames
* sizeof(DWORD
));
599 if (!infoPtr
->lpIndex
)
602 numFrame
= insize
= 0;
603 while (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, 0) == 0 &&
604 numFrame
< infoPtr
->mah
.dwTotalFrames
) {
605 infoPtr
->lpIndex
[numFrame
] = mmckInfo
.dwDataOffset
;
606 if (insize
< mmckInfo
.cksize
)
607 insize
= mmckInfo
.cksize
;
609 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
611 if (numFrame
!= infoPtr
->mah
.dwTotalFrames
) {
612 WARN("Found %ld frames (/%ld)\n", numFrame
, infoPtr
->mah
.dwTotalFrames
);
615 if (insize
> infoPtr
->ash
.dwSuggestedBufferSize
) {
616 WARN("insize=%ld suggestedSize=%ld\n", insize
, infoPtr
->ash
.dwSuggestedBufferSize
);
617 infoPtr
->ash
.dwSuggestedBufferSize
= insize
;
620 infoPtr
->indata
= HeapAlloc(GetProcessHeap(), 0, infoPtr
->ash
.dwSuggestedBufferSize
);
621 if (!infoPtr
->indata
)
628 static BOOL
ANIMATE_GetAviCodec(ANIMATE_INFO
*infoPtr
)
632 /* check uncompressed AVI */
633 if ((infoPtr
->ash
.fccHandler
== mmioFOURCC('D', 'I', 'B', ' ')) ||
634 (infoPtr
->ash
.fccHandler
== mmioFOURCC('R', 'L', 'E', ' ')) ||
635 (infoPtr
->ash
.fccHandler
== mmioFOURCC(0, 0, 0, 0)))
641 /* try to get a decompressor for that type */
642 infoPtr
->hic
= fnIC
.fnICOpen(ICTYPE_VIDEO
, infoPtr
->ash
.fccHandler
, ICMODE_DECOMPRESS
);
644 WARN("Can't load codec for the file\n");
648 outSize
= fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_GET_FORMAT
,
649 (DWORD
)infoPtr
->inbih
, 0L);
651 infoPtr
->outbih
= HeapAlloc(GetProcessHeap(), 0, outSize
);
652 if (!infoPtr
->outbih
)
655 if (fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_GET_FORMAT
,
656 (DWORD
)infoPtr
->inbih
, (DWORD
)infoPtr
->outbih
) != outSize
)
658 WARN("Can't get output BIH\n");
662 infoPtr
->outdata
= HeapAlloc(GetProcessHeap(), 0, infoPtr
->outbih
->biSizeImage
);
663 if (!infoPtr
->outdata
)
666 if (fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_BEGIN
,
667 (DWORD
)infoPtr
->inbih
, (DWORD
)infoPtr
->outbih
) != ICERR_OK
) {
668 WARN("Can't begin decompression\n");
675 static BOOL
ANIMATE_OpenW(ANIMATE_INFO
*infoPtr
, HINSTANCE hInstance
, LPWSTR lpszName
)
677 ANIMATE_Free(infoPtr
);
681 TRACE("Closing avi!\n");
682 /* installer of thebat! v1.62 requires FALSE here */
683 return (infoPtr
->hMMio
!= 0);
687 hInstance
= (HINSTANCE
)GetWindowLongPtrW(infoPtr
->hwndSelf
, GWLP_HINSTANCE
);
689 if (HIWORD(lpszName
))
691 TRACE("(\"%s\");\n", debugstr_w(lpszName
));
693 if (!ANIMATE_LoadResW(infoPtr
, hInstance
, lpszName
))
695 TRACE("No AVI resource found!\n");
696 if (!ANIMATE_LoadFileW(infoPtr
, lpszName
))
698 WARN("No AVI file found!\n");
705 TRACE("(%u);\n", (WORD
)(DWORD
)lpszName
);
707 if (!ANIMATE_LoadResW(infoPtr
, hInstance
, MAKEINTRESOURCEW((INT
)lpszName
)))
709 WARN("No AVI resource found!\n");
714 if (!ANIMATE_GetAviInfo(infoPtr
))
716 WARN("Can't get AVI information\n");
717 ANIMATE_Free(infoPtr
);
721 if (!ANIMATE_GetAviCodec(infoPtr
))
723 WARN("Can't get AVI Codec\n");
724 ANIMATE_Free(infoPtr
);
728 if (!GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_CENTER
)
729 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, infoPtr
->mah
.dwWidth
, infoPtr
->mah
.dwHeight
,
730 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
732 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_AUTOPLAY
)
733 return ANIMATE_Play(infoPtr
, -1, 0, infoPtr
->mah
.dwTotalFrames
- 1);
739 static BOOL
ANIMATE_OpenA(ANIMATE_INFO
*infoPtr
, HINSTANCE hInstance
, LPSTR lpszName
)
745 if (!HIWORD(lpszName
))
746 return ANIMATE_OpenW(infoPtr
, hInstance
, (LPWSTR
)lpszName
);
748 len
= MultiByteToWideChar(CP_ACP
, 0, lpszName
, -1, NULL
, 0);
749 lpwszName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
750 if (!lpwszName
) return FALSE
;
751 MultiByteToWideChar(CP_ACP
, 0, lpszName
, -1, lpwszName
, len
);
753 result
= ANIMATE_OpenW(infoPtr
, hInstance
, lpwszName
);
754 HeapFree(GetProcessHeap(), 0, lpwszName
);
759 static BOOL
ANIMATE_Stop(ANIMATE_INFO
*infoPtr
)
765 ANIMATE_DoStop(infoPtr
);
770 static BOOL
ANIMATE_Create(HWND hWnd
, LPCREATESTRUCTW lpcs
)
772 static const WCHAR msvfw32W
[] = { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', 0 };
773 ANIMATE_INFO
*infoPtr
;
775 if (!fnIC
.hModule
) /* FIXME: not thread safe */
777 /* since there's a circular dep between msvfw32 and comctl32, we could either:
778 * - fix the build chain to allow this circular dep
779 * - handle it by hand
780 * AJ wants the latter :-(
782 fnIC
.hModule
= LoadLibraryW(msvfw32W
);
783 if (!fnIC
.hModule
) return FALSE
;
785 fnIC
.fnICOpen
= (void*)GetProcAddress(fnIC
.hModule
, "ICOpen");
786 fnIC
.fnICClose
= (void*)GetProcAddress(fnIC
.hModule
, "ICClose");
787 fnIC
.fnICSendMessage
= (void*)GetProcAddress(fnIC
.hModule
, "ICSendMessage");
788 fnIC
.fnICDecompress
= (void*)GetProcAddress(fnIC
.hModule
, "ICDecompress");
791 /* allocate memory for info structure */
792 infoPtr
= (ANIMATE_INFO
*)Alloc(sizeof(ANIMATE_INFO
));
793 if (!infoPtr
) return FALSE
;
795 /* store crossref hWnd <-> info structure */
796 SetWindowLongPtrW(hWnd
, 0, (DWORD_PTR
)infoPtr
);
797 infoPtr
->hwndSelf
= hWnd
;
798 infoPtr
->hwndNotify
= lpcs
->hwndParent
;
799 infoPtr
->transparentColor
= ANIMATE_COLOR_NONE
;
800 infoPtr
->hbmPrevFrame
= 0;
802 TRACE("Animate style=0x%08lx, parent=%p\n", GetWindowLongW(hWnd
, GWL_STYLE
), infoPtr
->hwndNotify
);
804 InitializeCriticalSection(&infoPtr
->cs
);
810 static LRESULT
ANIMATE_Destroy(ANIMATE_INFO
*infoPtr
)
813 ANIMATE_Free(infoPtr
);
815 /* free animate info data */
816 SetWindowLongPtrW(infoPtr
->hwndSelf
, 0, 0);
823 static BOOL
ANIMATE_EraseBackground(ANIMATE_INFO
*infoPtr
, HDC hdc
)
828 if(GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
830 hBrush
= (HBRUSH
)SendMessageW(infoPtr
->hwndNotify
, WM_CTLCOLORSTATIC
,
831 (WPARAM
)hdc
, (LPARAM
)infoPtr
->hwndSelf
);
834 GetClientRect(infoPtr
->hwndSelf
, &rect
);
835 FillRect(hdc
, &rect
, hBrush
? hBrush
: GetCurrentObject(hdc
, OBJ_BRUSH
));
840 static LRESULT WINAPI
ANIMATE_Size(ANIMATE_INFO
*infoPtr
, INT flags
, WORD width
, WORD height
)
842 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_CENTER
)
844 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
849 static LRESULT WINAPI
ANIMATE_WindowProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
851 ANIMATE_INFO
*infoPtr
= (ANIMATE_INFO
*)GetWindowLongPtrW(hWnd
, 0);
853 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hWnd
, uMsg
, wParam
, lParam
);
854 if (!infoPtr
&& (uMsg
!= WM_NCCREATE
))
855 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
859 return ANIMATE_OpenA(infoPtr
, (HINSTANCE
)wParam
, (LPSTR
)lParam
);
862 return ANIMATE_OpenW(infoPtr
, (HINSTANCE
)wParam
, (LPWSTR
)lParam
);
865 return ANIMATE_Play(infoPtr
, (INT
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
868 return ANIMATE_Stop(infoPtr
);
871 return ANIMATE_Create(hWnd
, (LPCREATESTRUCTW
)lParam
);
874 return HTTRANSPARENT
;
877 return ANIMATE_Destroy(infoPtr
);
880 return ANIMATE_EraseBackground(infoPtr
, (HDC
)wParam
);
882 /* case WM_STYLECHANGED: FIXME shall we do something ?? */
885 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
887 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageW(infoPtr
->hwndNotify
,
889 wParam
, (LPARAM
)infoPtr
->hwndSelf
);
891 return ANIMATE_DrawFrame(infoPtr
);
895 /* the animation isn't playing, or has not decompressed
896 * (and displayed) the first frame yet, don't paint
898 if ((!infoPtr
->uTimer
&& !infoPtr
->hThread
) ||
899 !infoPtr
->hbmPrevFrame
)
901 /* default paint handling */
902 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
905 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & ACS_TRANSPARENT
)
906 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageW(infoPtr
->hwndNotify
,
908 wParam
, (LPARAM
)infoPtr
->hwndSelf
);
912 EnterCriticalSection(&infoPtr
->cs
);
913 ANIMATE_PaintFrame(infoPtr
, (HDC
)wParam
);
914 LeaveCriticalSection(&infoPtr
->cs
);
919 HDC hDC
= BeginPaint(infoPtr
->hwndSelf
, &ps
);
921 EnterCriticalSection(&infoPtr
->cs
);
922 ANIMATE_PaintFrame(infoPtr
, hDC
);
923 LeaveCriticalSection(&infoPtr
->cs
);
925 EndPaint(infoPtr
->hwndSelf
, &ps
);
931 return ANIMATE_Size(infoPtr
, (INT
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
934 if ((uMsg
>= WM_USER
) && (uMsg
< WM_APP
))
935 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
, lParam
);
937 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
942 void ANIMATE_Register(void)
946 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
947 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
948 wndClass
.lpfnWndProc
= ANIMATE_WindowProc
;
949 wndClass
.cbClsExtra
= 0;
950 wndClass
.cbWndExtra
= sizeof(ANIMATE_INFO
*);
951 wndClass
.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
952 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
953 wndClass
.lpszClassName
= ANIMATE_CLASSW
;
955 RegisterClassW(&wndClass
);
959 void ANIMATE_Unregister(void)
961 UnregisterClassW(ANIMATE_CLASSW
, NULL
);