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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * - check for the 'rec ' list in some AVI files
38 #include "wine/debug.h"
39 #include "wine/heap.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(animate
);
45 HIC (WINAPI
*fnICOpen
)(DWORD
, DWORD
, UINT
);
46 LRESULT (WINAPI
*fnICClose
)(HIC
);
47 LRESULT (WINAPI
*fnICSendMessage
)(HIC
, UINT
, DWORD_PTR
, DWORD_PTR
);
48 DWORD (WINAPIV
*fnICDecompress
)(HIC
,DWORD
,LPBITMAPINFOHEADER
,LPVOID
,LPBITMAPINFOHEADER
,LPVOID
);
53 /* reference to input stream (file or resource) */
55 HMMIO hMMio
; /* handle to mmio stream */
59 /* information on the loaded AVI file */
62 LPBITMAPINFOHEADER inbih
;
64 /* data for the decompressor */
66 LPBITMAPINFOHEADER outbih
;
69 /* data for the background mechanism */
75 /* data for playing the file */
80 /* transparency info*/
81 COLORREF transparentColor
;
86 #define ANIMATE_COLOR_NONE 0xffffffff
88 static void ANIMATE_Notify(const ANIMATE_INFO
*infoPtr
, UINT notif
)
90 PostMessageW(infoPtr
->hwndNotify
, WM_COMMAND
,
91 MAKEWPARAM(GetDlgCtrlID(infoPtr
->hwndSelf
), notif
),
92 (LPARAM
)infoPtr
->hwndSelf
);
95 static BOOL
ANIMATE_LoadResW(ANIMATE_INFO
*infoPtr
, HINSTANCE hInst
, LPCWSTR lpName
)
101 hrsrc
= FindResourceW(hInst
, lpName
, L
"AVI");
105 infoPtr
->hRes
= LoadResource(hInst
, hrsrc
);
109 lpAvi
= LockResource(infoPtr
->hRes
);
113 memset(&mminfo
, 0, sizeof(mminfo
));
114 mminfo
.fccIOProc
= FOURCC_MEM
;
115 mminfo
.pchBuffer
= lpAvi
;
116 mminfo
.cchBuffer
= SizeofResource(hInst
, hrsrc
);
117 infoPtr
->hMMio
= mmioOpenW(NULL
, &mminfo
, MMIO_READ
);
120 FreeResource(infoPtr
->hRes
);
128 static BOOL
ANIMATE_LoadFileW(ANIMATE_INFO
*infoPtr
, LPWSTR lpName
)
130 infoPtr
->hMMio
= mmioOpenW(lpName
, 0, MMIO_ALLOCBUF
| MMIO_READ
| MMIO_DENYWRITE
);
132 if(!infoPtr
->hMMio
) return FALSE
;
137 static BOOL
ANIMATE_DoStop(ANIMATE_INFO
*infoPtr
)
139 BOOL stopped
= FALSE
;
141 EnterCriticalSection(&infoPtr
->cs
);
143 /* should stop playing */
144 if (infoPtr
->hThread
)
146 HANDLE handle
= infoPtr
->hThread
;
148 TRACE("stopping animation thread\n");
149 infoPtr
->hThread
= 0;
150 SetEvent( infoPtr
->hStopEvent
);
152 if (infoPtr
->threadId
!= GetCurrentThreadId())
154 LeaveCriticalSection(&infoPtr
->cs
); /* leave it a chance to run */
155 WaitForSingleObject( handle
, INFINITE
);
156 TRACE("animation thread stopped\n");
157 EnterCriticalSection(&infoPtr
->cs
);
160 CloseHandle( handle
);
161 CloseHandle( infoPtr
->hStopEvent
);
162 infoPtr
->hStopEvent
= 0;
165 if (infoPtr
->uTimer
) {
166 KillTimer(infoPtr
->hwndSelf
, infoPtr
->uTimer
);
171 LeaveCriticalSection(&infoPtr
->cs
);
174 ANIMATE_Notify(infoPtr
, ACN_STOP
);
180 static void ANIMATE_Free(ANIMATE_INFO
*infoPtr
)
184 ANIMATE_DoStop(infoPtr
);
185 mmioClose(infoPtr
->hMMio
, 0);
188 FreeResource(infoPtr
->hRes
);
191 heap_free (infoPtr
->lpIndex
);
192 infoPtr
->lpIndex
= NULL
;
195 fnIC
.fnICClose(infoPtr
->hic
);
198 heap_free (infoPtr
->inbih
);
199 infoPtr
->inbih
= NULL
;
200 heap_free (infoPtr
->outbih
);
201 infoPtr
->outbih
= NULL
;
202 heap_free (infoPtr
->indata
);
203 infoPtr
->indata
= NULL
;
204 heap_free (infoPtr
->outdata
);
205 infoPtr
->outdata
= NULL
;
206 if (infoPtr
->hbmPrevFrame
)
208 DeleteObject(infoPtr
->hbmPrevFrame
);
209 infoPtr
->hbmPrevFrame
= 0;
212 memset(&infoPtr
->mah
, 0, sizeof(infoPtr
->mah
));
213 memset(&infoPtr
->ash
, 0, sizeof(infoPtr
->ash
));
214 infoPtr
->nFromFrame
= infoPtr
->nToFrame
= infoPtr
->nLoop
= infoPtr
->currFrame
= 0;
216 infoPtr
->transparentColor
= ANIMATE_COLOR_NONE
;
219 static void ANIMATE_TransparentBlt(ANIMATE_INFO
const *infoPtr
, HDC hdcDest
, HDC hdcSource
)
225 /* create a transparency mask */
226 hdcMask
= CreateCompatibleDC(hdcDest
);
227 hbmMask
= CreateBitmap(infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, 1,1,NULL
);
228 hbmOld
= SelectObject(hdcMask
, hbmMask
);
230 SetBkColor(hdcSource
,infoPtr
->transparentColor
);
231 BitBlt(hdcMask
,0,0,infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
,hdcSource
,0,0,SRCCOPY
);
233 /* mask the source bitmap */
234 SetBkColor(hdcSource
, RGB(0,0,0));
235 SetTextColor(hdcSource
, RGB(255,255,255));
236 BitBlt(hdcSource
, 0, 0, infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, hdcMask
, 0, 0, SRCAND
);
238 /* mask the destination bitmap */
239 SetBkColor(hdcDest
, RGB(255,255,255));
240 SetTextColor(hdcDest
, RGB(0,0,0));
241 BitBlt(hdcDest
, 0, 0, infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
, hdcMask
, 0, 0, SRCAND
);
243 /* combine source and destination */
244 BitBlt(hdcDest
,0,0,infoPtr
->inbih
->biWidth
, infoPtr
->inbih
->biHeight
,hdcSource
,0,0,SRCPAINT
);
246 SelectObject(hdcMask
, hbmOld
);
247 DeleteObject(hbmMask
);
251 static BOOL
ANIMATE_PaintFrame(ANIMATE_INFO
* infoPtr
, HDC hDC
)
253 void const *pBitmapData
;
254 BITMAPINFO
const *pBitmapInfo
;
262 if (!hDC
|| !infoPtr
->inbih
)
267 pBitmapData
= infoPtr
->outdata
;
268 pBitmapInfo
= (LPBITMAPINFO
)infoPtr
->outbih
;
270 nWidth
= infoPtr
->outbih
->biWidth
;
271 nHeight
= infoPtr
->outbih
->biHeight
;
275 pBitmapData
= infoPtr
->indata
;
276 pBitmapInfo
= (LPBITMAPINFO
)infoPtr
->inbih
;
278 nWidth
= infoPtr
->inbih
->biWidth
;
279 nHeight
= infoPtr
->inbih
->biHeight
;
282 if(!infoPtr
->hbmPrevFrame
)
284 infoPtr
->hbmPrevFrame
=CreateCompatibleBitmap(hDC
, nWidth
,nHeight
);
287 hdcMem
= CreateCompatibleDC(hDC
);
288 hbmOld
= SelectObject(hdcMem
, infoPtr
->hbmPrevFrame
);
290 SetDIBits(hdcMem
, infoPtr
->hbmPrevFrame
, 0, nHeight
, pBitmapData
, pBitmapInfo
, DIB_RGB_COLORS
);
293 * we need to get the transparent color even without ACS_TRANSPARENT,
294 * because the style can be changed later on and the color should always
295 * be obtained in the first frame
297 if(infoPtr
->transparentColor
== ANIMATE_COLOR_NONE
)
299 infoPtr
->transparentColor
= GetPixel(hdcMem
,0,0);
302 if(infoPtr
->dwStyle
& ACS_TRANSPARENT
)
304 HDC hdcFinal
= CreateCompatibleDC(hDC
);
305 HBITMAP hbmFinal
= CreateCompatibleBitmap(hDC
,nWidth
, nHeight
);
306 HBITMAP hbmOld2
= SelectObject(hdcFinal
, hbmFinal
);
309 SetRect(&rect
, 0, 0, nWidth
, nHeight
);
311 if(!infoPtr
->hbrushBG
)
312 infoPtr
->hbrushBG
= GetCurrentObject(hDC
, OBJ_BRUSH
);
314 FillRect(hdcFinal
, &rect
, infoPtr
->hbrushBG
);
315 ANIMATE_TransparentBlt(infoPtr
, hdcFinal
, hdcMem
);
317 SelectObject(hdcFinal
, hbmOld2
);
318 SelectObject(hdcMem
, hbmFinal
);
320 DeleteObject(infoPtr
->hbmPrevFrame
);
321 infoPtr
->hbmPrevFrame
= hbmFinal
;
324 if (infoPtr
->dwStyle
& ACS_CENTER
)
328 GetWindowRect(infoPtr
->hwndSelf
, &rect
);
329 nOffsetX
= ((rect
.right
- rect
.left
) - nWidth
)/2;
330 nOffsetY
= ((rect
.bottom
- rect
.top
) - nHeight
)/2;
332 BitBlt(hDC
, nOffsetX
, nOffsetY
, nWidth
, nHeight
, hdcMem
, 0, 0, SRCCOPY
);
334 SelectObject(hdcMem
, hbmOld
);
339 static BOOL
ANIMATE_DrawFrame(ANIMATE_INFO
*infoPtr
, HDC hDC
)
341 TRACE("Drawing frame %d (loop %d)\n", infoPtr
->currFrame
, infoPtr
->nLoop
);
343 mmioSeek(infoPtr
->hMMio
, infoPtr
->lpIndex
[infoPtr
->currFrame
], SEEK_SET
);
344 mmioRead(infoPtr
->hMMio
, infoPtr
->indata
, infoPtr
->ash
.dwSuggestedBufferSize
);
347 fnIC
.fnICDecompress(infoPtr
->hic
, 0, infoPtr
->inbih
, infoPtr
->indata
,
348 infoPtr
->outbih
, infoPtr
->outdata
) != ICERR_OK
) {
349 WARN("Decompression error\n");
353 ANIMATE_PaintFrame(infoPtr
, hDC
);
355 if (infoPtr
->currFrame
++ >= infoPtr
->nToFrame
) {
356 infoPtr
->currFrame
= infoPtr
->nFromFrame
;
357 if (infoPtr
->nLoop
!= -1) {
358 if (--infoPtr
->nLoop
== 0) {
359 ANIMATE_DoStop(infoPtr
);
367 static LRESULT
ANIMATE_Timer(ANIMATE_INFO
*infoPtr
)
371 if ((hDC
= GetDC(infoPtr
->hwndSelf
)) != 0)
373 EnterCriticalSection(&infoPtr
->cs
);
374 ANIMATE_DrawFrame(infoPtr
, hDC
);
375 LeaveCriticalSection(&infoPtr
->cs
);
377 ReleaseDC(infoPtr
->hwndSelf
, hDC
);
383 static DWORD CALLBACK
ANIMATE_AnimationThread(LPVOID ptr_
)
385 ANIMATE_INFO
*infoPtr
= ptr_
;
391 HDC hDC
= GetDC(infoPtr
->hwndSelf
);
393 EnterCriticalSection(&infoPtr
->cs
);
394 ANIMATE_DrawFrame(infoPtr
, hDC
);
395 timeout
= infoPtr
->mah
.dwMicroSecPerFrame
;
396 event
= infoPtr
->hStopEvent
;
397 LeaveCriticalSection(&infoPtr
->cs
);
399 ReleaseDC(infoPtr
->hwndSelf
, hDC
);
401 /* time is in microseconds, we should convert it to milliseconds */
402 if ((event
== 0) || WaitForSingleObject( event
, (timeout
+500)/1000) == WAIT_OBJECT_0
)
408 static LRESULT
ANIMATE_Play(ANIMATE_INFO
*infoPtr
, UINT cRepeat
, WORD wFrom
, WORD wTo
)
414 if (infoPtr
->hThread
|| infoPtr
->uTimer
) {
415 TRACE("Already playing\n");
419 infoPtr
->nFromFrame
= wFrom
;
420 infoPtr
->nToFrame
= wTo
;
421 infoPtr
->nLoop
= cRepeat
;
423 if (infoPtr
->nToFrame
== 0xFFFF)
424 infoPtr
->nToFrame
= infoPtr
->mah
.dwTotalFrames
- 1;
426 TRACE("(repeat=%d from=%d to=%d);\n",
427 infoPtr
->nLoop
, infoPtr
->nFromFrame
, infoPtr
->nToFrame
);
429 if (infoPtr
->nFromFrame
>= infoPtr
->mah
.dwTotalFrames
&&
430 (SHORT
)infoPtr
->nFromFrame
< 0)
431 infoPtr
->nFromFrame
= 0;
433 if (infoPtr
->nFromFrame
> infoPtr
->nToFrame
||
434 infoPtr
->nToFrame
>= infoPtr
->mah
.dwTotalFrames
)
437 infoPtr
->currFrame
= infoPtr
->nFromFrame
;
439 /* seek - doesn't need to start a thread or set a timer and neither
440 * does it send a notification */
441 if (infoPtr
->nFromFrame
== infoPtr
->nToFrame
)
445 if ((hDC
= GetDC(infoPtr
->hwndSelf
)) != 0)
447 ANIMATE_DrawFrame(infoPtr
, hDC
);
449 ReleaseDC(infoPtr
->hwndSelf
, hDC
);
454 if (infoPtr
->dwStyle
& ACS_TIMER
)
456 TRACE("Using a timer\n");
457 /* create a timer to display AVI */
458 infoPtr
->uTimer
= SetTimer(infoPtr
->hwndSelf
, 1,
459 infoPtr
->mah
.dwMicroSecPerFrame
/ 1000, NULL
);
463 TRACE("Using an animation thread\n");
464 infoPtr
->hStopEvent
= CreateEventW( NULL
, TRUE
, FALSE
, NULL
);
465 infoPtr
->hThread
= CreateThread(0, 0, ANIMATE_AnimationThread
,
466 infoPtr
, 0, &infoPtr
->threadId
);
467 if(!infoPtr
->hThread
) return FALSE
;
471 ANIMATE_Notify(infoPtr
, ACN_START
);
477 static BOOL
ANIMATE_GetAviInfo(ANIMATE_INFO
*infoPtr
)
486 if (mmioDescend(infoPtr
->hMMio
, &ckMainRIFF
, NULL
, 0) != 0) {
487 WARN("Can't find 'RIFF' chunk\n");
491 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
492 (ckMainRIFF
.fccType
!= mmioFOURCC('A', 'V', 'I', ' '))) {
493 WARN("Can't find 'AVI ' chunk\n");
497 mmckHead
.fccType
= mmioFOURCC('h', 'd', 'r', 'l');
498 if (mmioDescend(infoPtr
->hMMio
, &mmckHead
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
499 WARN("Can't find 'hdrl' list\n");
503 mmckInfo
.ckid
= mmioFOURCC('a', 'v', 'i', 'h');
504 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckHead
, MMIO_FINDCHUNK
) != 0) {
505 WARN("Can't find 'avih' chunk\n");
509 mmioRead(infoPtr
->hMMio
, (LPSTR
)&infoPtr
->mah
, sizeof(infoPtr
->mah
));
511 TRACE("mah.dwMicroSecPerFrame=%d\n", infoPtr
->mah
.dwMicroSecPerFrame
);
512 TRACE("mah.dwMaxBytesPerSec=%d\n", infoPtr
->mah
.dwMaxBytesPerSec
);
513 TRACE("mah.dwPaddingGranularity=%d\n", infoPtr
->mah
.dwPaddingGranularity
);
514 TRACE("mah.dwFlags=%d\n", infoPtr
->mah
.dwFlags
);
515 TRACE("mah.dwTotalFrames=%d\n", infoPtr
->mah
.dwTotalFrames
);
516 TRACE("mah.dwInitialFrames=%d\n", infoPtr
->mah
.dwInitialFrames
);
517 TRACE("mah.dwStreams=%d\n", infoPtr
->mah
.dwStreams
);
518 TRACE("mah.dwSuggestedBufferSize=%d\n", infoPtr
->mah
.dwSuggestedBufferSize
);
519 TRACE("mah.dwWidth=%d\n", infoPtr
->mah
.dwWidth
);
520 TRACE("mah.dwHeight=%d\n", infoPtr
->mah
.dwHeight
);
522 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
524 mmckList
.fccType
= mmioFOURCC('s', 't', 'r', 'l');
525 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) != 0) {
526 WARN("Can't find 'strl' list\n");
530 mmckInfo
.ckid
= mmioFOURCC('s', 't', 'r', 'h');
531 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, MMIO_FINDCHUNK
) != 0) {
532 WARN("Can't find 'strh' chunk\n");
536 mmioRead(infoPtr
->hMMio
, (LPSTR
)&infoPtr
->ash
, sizeof(infoPtr
->ash
));
538 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr
->ash
.fccType
)),
539 HIBYTE(LOWORD(infoPtr
->ash
.fccType
)),
540 LOBYTE(HIWORD(infoPtr
->ash
.fccType
)),
541 HIBYTE(HIWORD(infoPtr
->ash
.fccType
)));
542 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr
->ash
.fccHandler
)),
543 HIBYTE(LOWORD(infoPtr
->ash
.fccHandler
)),
544 LOBYTE(HIWORD(infoPtr
->ash
.fccHandler
)),
545 HIBYTE(HIWORD(infoPtr
->ash
.fccHandler
)));
546 TRACE("ash.dwFlags=%d\n", infoPtr
->ash
.dwFlags
);
547 TRACE("ash.wPriority=%d\n", infoPtr
->ash
.wPriority
);
548 TRACE("ash.wLanguage=%d\n", infoPtr
->ash
.wLanguage
);
549 TRACE("ash.dwInitialFrames=%d\n", infoPtr
->ash
.dwInitialFrames
);
550 TRACE("ash.dwScale=%d\n", infoPtr
->ash
.dwScale
);
551 TRACE("ash.dwRate=%d\n", infoPtr
->ash
.dwRate
);
552 TRACE("ash.dwStart=%d\n", infoPtr
->ash
.dwStart
);
553 TRACE("ash.dwLength=%d\n", infoPtr
->ash
.dwLength
);
554 TRACE("ash.dwSuggestedBufferSize=%d\n", infoPtr
->ash
.dwSuggestedBufferSize
);
555 TRACE("ash.dwQuality=%d\n", infoPtr
->ash
.dwQuality
);
556 TRACE("ash.dwSampleSize=%d\n", infoPtr
->ash
.dwSampleSize
);
557 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr
->ash
.rcFrame
.top
, infoPtr
->ash
.rcFrame
.left
,
558 infoPtr
->ash
.rcFrame
.bottom
, infoPtr
->ash
.rcFrame
.right
);
560 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
562 mmckInfo
.ckid
= mmioFOURCC('s', 't', 'r', 'f');
563 if (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, MMIO_FINDCHUNK
) != 0) {
564 WARN("Can't find 'strh' chunk\n");
568 infoPtr
->inbih
= heap_alloc_zero(mmckInfo
.cksize
);
569 if (!infoPtr
->inbih
) {
570 WARN("Can't alloc input BIH\n");
574 mmioRead(infoPtr
->hMMio
, (LPSTR
)infoPtr
->inbih
, mmckInfo
.cksize
);
576 TRACE("bih.biSize=%d\n", infoPtr
->inbih
->biSize
);
577 TRACE("bih.biWidth=%d\n", infoPtr
->inbih
->biWidth
);
578 TRACE("bih.biHeight=%d\n", infoPtr
->inbih
->biHeight
);
579 TRACE("bih.biPlanes=%d\n", infoPtr
->inbih
->biPlanes
);
580 TRACE("bih.biBitCount=%d\n", infoPtr
->inbih
->biBitCount
);
581 TRACE("bih.biCompression=%d\n", infoPtr
->inbih
->biCompression
);
582 TRACE("bih.biSizeImage=%d\n", infoPtr
->inbih
->biSizeImage
);
583 TRACE("bih.biXPelsPerMeter=%d\n", infoPtr
->inbih
->biXPelsPerMeter
);
584 TRACE("bih.biYPelsPerMeter=%d\n", infoPtr
->inbih
->biYPelsPerMeter
);
585 TRACE("bih.biClrUsed=%d\n", infoPtr
->inbih
->biClrUsed
);
586 TRACE("bih.biClrImportant=%d\n", infoPtr
->inbih
->biClrImportant
);
588 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
590 mmioAscend(infoPtr
->hMMio
, &mmckList
, 0);
593 /* an AVI has 0 or 1 video stream, and to be animated should not contain
594 * an audio stream, so only one strl is allowed
596 mmckList
.fccType
= mmioFOURCC('s', 't', 'r', 'l');
597 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) == 0) {
598 WARN("There should be a single 'strl' list\n");
603 mmioAscend(infoPtr
->hMMio
, &mmckHead
, 0);
605 /* no need to read optional JUNK chunk */
607 mmckList
.fccType
= mmioFOURCC('m', 'o', 'v', 'i');
608 if (mmioDescend(infoPtr
->hMMio
, &mmckList
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
609 WARN("Can't find 'movi' list\n");
613 /* FIXME: should handle the 'rec ' LIST when present */
615 infoPtr
->lpIndex
= heap_alloc_zero(infoPtr
->mah
.dwTotalFrames
* sizeof(DWORD
));
616 if (!infoPtr
->lpIndex
)
619 numFrame
= insize
= 0;
620 while (mmioDescend(infoPtr
->hMMio
, &mmckInfo
, &mmckList
, 0) == 0 &&
621 numFrame
< infoPtr
->mah
.dwTotalFrames
) {
622 infoPtr
->lpIndex
[numFrame
] = mmckInfo
.dwDataOffset
;
623 if (insize
< mmckInfo
.cksize
)
624 insize
= mmckInfo
.cksize
;
626 mmioAscend(infoPtr
->hMMio
, &mmckInfo
, 0);
628 if (numFrame
!= infoPtr
->mah
.dwTotalFrames
) {
629 WARN("Found %d frames (/%d)\n", numFrame
, infoPtr
->mah
.dwTotalFrames
);
632 if (insize
> infoPtr
->ash
.dwSuggestedBufferSize
) {
633 WARN("insize=%d suggestedSize=%d\n", insize
, infoPtr
->ash
.dwSuggestedBufferSize
);
634 infoPtr
->ash
.dwSuggestedBufferSize
= insize
;
637 infoPtr
->indata
= heap_alloc_zero(infoPtr
->ash
.dwSuggestedBufferSize
);
638 if (!infoPtr
->indata
)
645 static BOOL
ANIMATE_GetAviCodec(ANIMATE_INFO
*infoPtr
)
649 /* check uncompressed AVI */
650 if ((infoPtr
->ash
.fccHandler
== mmioFOURCC('D', 'I', 'B', ' ')) ||
651 (infoPtr
->ash
.fccHandler
== mmioFOURCC('R', 'L', 'E', ' ')) ||
652 (infoPtr
->ash
.fccHandler
== mmioFOURCC(0, 0, 0, 0)))
658 /* try to get a decompressor for that type */
659 infoPtr
->hic
= fnIC
.fnICOpen(ICTYPE_VIDEO
, infoPtr
->ash
.fccHandler
, ICMODE_DECOMPRESS
);
661 WARN("Can't load codec for the file\n");
665 outSize
= fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_GET_FORMAT
,
666 (DWORD_PTR
)infoPtr
->inbih
, 0L);
668 infoPtr
->outbih
= heap_alloc_zero(outSize
);
669 if (!infoPtr
->outbih
)
672 if (fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_GET_FORMAT
,
673 (DWORD_PTR
)infoPtr
->inbih
, (DWORD_PTR
)infoPtr
->outbih
) != ICERR_OK
)
675 WARN("Can't get output BIH\n");
679 infoPtr
->outdata
= heap_alloc_zero(infoPtr
->outbih
->biSizeImage
);
680 if (!infoPtr
->outdata
)
683 if (fnIC
.fnICSendMessage(infoPtr
->hic
, ICM_DECOMPRESS_BEGIN
,
684 (DWORD_PTR
)infoPtr
->inbih
, (DWORD_PTR
)infoPtr
->outbih
) != ICERR_OK
) {
685 WARN("Can't begin decompression\n");
693 static BOOL
ANIMATE_OpenW(ANIMATE_INFO
*infoPtr
, HINSTANCE hInstance
, LPWSTR lpszName
)
697 ANIMATE_Free(infoPtr
);
701 TRACE("Closing avi.\n");
702 /* installer of thebat! v1.62 requires FALSE here */
703 return (infoPtr
->hMMio
!= 0);
707 hInstance
= (HINSTANCE
)GetWindowLongPtrW(infoPtr
->hwndSelf
, GWLP_HINSTANCE
);
709 TRACE("(%s)\n", debugstr_w(lpszName
));
711 if (!IS_INTRESOURCE(lpszName
))
713 if (!ANIMATE_LoadResW(infoPtr
, hInstance
, lpszName
))
715 TRACE("No AVI resource found.\n");
716 if (!ANIMATE_LoadFileW(infoPtr
, lpszName
))
718 WARN("No AVI file found.\n");
725 if (!ANIMATE_LoadResW(infoPtr
, hInstance
, lpszName
))
727 WARN("No AVI resource found.\n");
732 if (!ANIMATE_GetAviInfo(infoPtr
))
734 WARN("Can't get AVI information\n");
735 ANIMATE_Free(infoPtr
);
739 if (!ANIMATE_GetAviCodec(infoPtr
))
741 WARN("Can't get AVI Codec\n");
742 ANIMATE_Free(infoPtr
);
746 hdc
= GetDC(infoPtr
->hwndSelf
);
747 /* native looks at the top left pixel of the first frame here too. */
748 infoPtr
->hbrushBG
= (HBRUSH
)SendMessageW(infoPtr
->hwndNotify
, WM_CTLCOLORSTATIC
,
749 (WPARAM
)hdc
, (LPARAM
)infoPtr
->hwndSelf
);
750 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
752 if (!(infoPtr
->dwStyle
& ACS_CENTER
))
753 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, infoPtr
->mah
.dwWidth
, infoPtr
->mah
.dwHeight
,
754 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
756 if (infoPtr
->dwStyle
& ACS_AUTOPLAY
)
757 return ANIMATE_Play(infoPtr
, -1, 0, infoPtr
->mah
.dwTotalFrames
- 1);
763 static BOOL
ANIMATE_OpenA(ANIMATE_INFO
*infoPtr
, HINSTANCE hInstance
, LPSTR lpszName
)
769 if (IS_INTRESOURCE(lpszName
))
770 return ANIMATE_OpenW(infoPtr
, hInstance
, (LPWSTR
)lpszName
);
772 len
= MultiByteToWideChar(CP_ACP
, 0, lpszName
, -1, NULL
, 0);
773 lpwszName
= heap_alloc(len
* sizeof(WCHAR
));
774 if (!lpwszName
) return FALSE
;
775 MultiByteToWideChar(CP_ACP
, 0, lpszName
, -1, lpwszName
, len
);
777 result
= ANIMATE_OpenW(infoPtr
, hInstance
, lpwszName
);
778 heap_free (lpwszName
);
783 static BOOL
ANIMATE_Stop(ANIMATE_INFO
*infoPtr
)
789 ANIMATE_DoStop(infoPtr
);
794 static BOOL
ANIMATE_Create(HWND hWnd
, const CREATESTRUCTW
*lpcs
)
796 ANIMATE_INFO
*infoPtr
;
800 fnIC
.hModule
= LoadLibraryW(L
"msvfw32.dll");
801 if (!fnIC
.hModule
) return FALSE
;
803 fnIC
.fnICOpen
= (void*)GetProcAddress(fnIC
.hModule
, "ICOpen");
804 fnIC
.fnICClose
= (void*)GetProcAddress(fnIC
.hModule
, "ICClose");
805 fnIC
.fnICSendMessage
= (void*)GetProcAddress(fnIC
.hModule
, "ICSendMessage");
806 fnIC
.fnICDecompress
= (void*)GetProcAddress(fnIC
.hModule
, "ICDecompress");
809 /* allocate memory for info structure */
810 infoPtr
= heap_alloc_zero(sizeof(*infoPtr
));
811 if (!infoPtr
) return FALSE
;
813 /* store crossref hWnd <-> info structure */
814 SetWindowLongPtrW(hWnd
, 0, (DWORD_PTR
)infoPtr
);
815 infoPtr
->hwndSelf
= hWnd
;
816 infoPtr
->hwndNotify
= lpcs
->hwndParent
;
817 infoPtr
->transparentColor
= ANIMATE_COLOR_NONE
;
818 infoPtr
->hbmPrevFrame
= 0;
819 infoPtr
->dwStyle
= lpcs
->style
;
821 TRACE("Animate style=0x%08x, parent=%p\n", infoPtr
->dwStyle
, infoPtr
->hwndNotify
);
823 InitializeCriticalSection(&infoPtr
->cs
);
824 infoPtr
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": ANIMATE_INFO*->cs");
830 static LRESULT
ANIMATE_Destroy(ANIMATE_INFO
*infoPtr
)
833 ANIMATE_Free(infoPtr
);
835 /* free animate info data */
836 SetWindowLongPtrW(infoPtr
->hwndSelf
, 0, 0);
838 infoPtr
->cs
.DebugInfo
->Spare
[0] = 0;
839 DeleteCriticalSection(&infoPtr
->cs
);
846 static BOOL
ANIMATE_EraseBackground(ANIMATE_INFO
const *infoPtr
, HDC hdc
)
851 hBrush
= (HBRUSH
)SendMessageW(infoPtr
->hwndNotify
, WM_CTLCOLORSTATIC
,
852 (WPARAM
)hdc
, (LPARAM
)infoPtr
->hwndSelf
);
853 GetClientRect(infoPtr
->hwndSelf
, &rect
);
854 FillRect(hdc
, &rect
, hBrush
? hBrush
: GetCurrentObject(hdc
, OBJ_BRUSH
));
860 static LRESULT
ANIMATE_StyleChanged(ANIMATE_INFO
*infoPtr
, WPARAM wStyleType
, const STYLESTRUCT
*lpss
)
862 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
863 wStyleType
, lpss
->styleOld
, lpss
->styleNew
);
865 if (wStyleType
!= GWL_STYLE
) return 0;
867 infoPtr
->dwStyle
= lpss
->styleNew
;
869 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
874 static LRESULT WINAPI
ANIMATE_WindowProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
876 ANIMATE_INFO
*infoPtr
= (ANIMATE_INFO
*)GetWindowLongPtrW(hWnd
, 0);
878 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hWnd
, uMsg
, wParam
, lParam
);
879 if (!infoPtr
&& (uMsg
!= WM_NCCREATE
))
880 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
884 return ANIMATE_OpenA(infoPtr
, (HINSTANCE
)wParam
, (LPSTR
)lParam
);
887 return ANIMATE_OpenW(infoPtr
, (HINSTANCE
)wParam
, (LPWSTR
)lParam
);
890 return ANIMATE_Play(infoPtr
, (INT
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
893 return ANIMATE_Stop(infoPtr
);
896 ANIMATE_Free(infoPtr
);
900 return ANIMATE_Create(hWnd
, (LPCREATESTRUCTW
)lParam
);
903 return HTTRANSPARENT
;
906 return ANIMATE_Destroy(infoPtr
);
909 return ANIMATE_EraseBackground(infoPtr
, (HDC
)wParam
);
911 case WM_STYLECHANGED
:
912 return ANIMATE_StyleChanged(infoPtr
, wParam
, (LPSTYLESTRUCT
)lParam
);
915 return ANIMATE_Timer(infoPtr
);
920 /* the animation has not decompressed
921 * (and displayed) the first frame yet, don't paint
923 if (!infoPtr
->hbmPrevFrame
)
925 /* default paint handling */
926 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
931 EnterCriticalSection(&infoPtr
->cs
);
932 ANIMATE_PaintFrame(infoPtr
, (HDC
)wParam
);
933 LeaveCriticalSection(&infoPtr
->cs
);
938 HDC hDC
= BeginPaint(infoPtr
->hwndSelf
, &ps
);
940 EnterCriticalSection(&infoPtr
->cs
);
941 ANIMATE_PaintFrame(infoPtr
, hDC
);
942 LeaveCriticalSection(&infoPtr
->cs
);
944 EndPaint(infoPtr
->hwndSelf
, &ps
);
950 if (infoPtr
->dwStyle
& ACS_CENTER
)
951 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
952 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
955 if ((uMsg
>= WM_USER
) && (uMsg
< WM_APP
) && !COMCTL32_IsReflectedMessage(uMsg
))
956 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg
, wParam
, lParam
);
958 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
963 void ANIMATE_Register(void)
967 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
968 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
969 wndClass
.lpfnWndProc
= ANIMATE_WindowProc
;
970 wndClass
.cbClsExtra
= 0;
971 wndClass
.cbWndExtra
= sizeof(ANIMATE_INFO
*);
972 wndClass
.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
973 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
974 wndClass
.lpszClassName
= ANIMATE_CLASSW
;
976 RegisterClassW(&wndClass
);
980 void ANIMATE_Unregister(void)
982 UnregisterClassW(ANIMATE_CLASSW
, NULL
);