Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenanimate.c
Go to the documentation of this file.
00001 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 00002 /* 00003 * Animation control 00004 * 00005 * Copyright 1998, 1999 Eric Kohl 00006 * Copyright 1999 Eric Pouech 00007 * Copyright 2005 Dimitrie O. Paun 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 * 00023 * NOTES 00024 * 00025 * This code was audited for completeness against the documented features 00026 * of Comctl32.dll version 6.0 on Mar. 15, 2005, by Dimitrie O. Paun. 00027 * 00028 * Unless otherwise noted, we believe this code to be complete, as per 00029 * the specification mentioned above. 00030 * If you discover missing features, or bugs, please note them below. 00031 * 00032 * TODO: 00033 * - check for the 'rec ' list in some AVI files 00034 */ 00035 00036 #include <stdarg.h> 00037 #include <string.h> 00038 #include "windef.h" 00039 #include "winbase.h" 00040 #include "wingdi.h" 00041 #include "winuser.h" 00042 #include "winnls.h" 00043 #include "commctrl.h" 00044 #include "vfw.h" 00045 #include "mmsystem.h" 00046 #include "comctl32.h" 00047 #include "wine/debug.h" 00048 00049 WINE_DEFAULT_DEBUG_CHANNEL(animate); 00050 00051 static struct { 00052 HMODULE hModule; 00053 HIC (WINAPI *fnICOpen)(DWORD, DWORD, UINT); 00054 LRESULT (WINAPI *fnICClose)(HIC); 00055 LRESULT (WINAPI *fnICSendMessage)(HIC, UINT, DWORD_PTR, DWORD_PTR); 00056 DWORD (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID); 00057 } fnIC; 00058 00059 typedef struct 00060 { 00061 /* reference to input stream (file or resource) */ 00062 HGLOBAL hRes; 00063 HMMIO hMMio; /* handle to mmio stream */ 00064 HWND hwndSelf; 00065 HWND hwndNotify; 00066 DWORD dwStyle; 00067 /* information on the loaded AVI file */ 00068 MainAVIHeader mah; 00069 AVIStreamHeader ash; 00070 LPBITMAPINFOHEADER inbih; 00071 LPDWORD lpIndex; 00072 /* data for the decompressor */ 00073 HIC hic; 00074 LPBITMAPINFOHEADER outbih; 00075 LPVOID indata; 00076 LPVOID outdata; 00077 /* data for the background mechanism */ 00078 CRITICAL_SECTION cs; 00079 HANDLE hStopEvent; 00080 HANDLE hThread; 00081 DWORD threadId; 00082 UINT uTimer; 00083 /* data for playing the file */ 00084 int nFromFrame; 00085 int nToFrame; 00086 int nLoop; 00087 int currFrame; 00088 /* transparency info*/ 00089 COLORREF transparentColor; 00090 HBRUSH hbrushBG; 00091 HBITMAP hbmPrevFrame; 00092 } ANIMATE_INFO; 00093 00094 #define ANIMATE_COLOR_NONE 0xffffffff 00095 00096 static void ANIMATE_Notify(const ANIMATE_INFO *infoPtr, UINT notif) 00097 { 00098 PostMessageW(infoPtr->hwndNotify, WM_COMMAND, 00099 MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), notif), 00100 (LPARAM)infoPtr->hwndSelf); 00101 } 00102 00103 static BOOL ANIMATE_LoadResW(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPCWSTR lpName) 00104 { 00105 static const WCHAR aviW[] = { 'A', 'V', 'I', 0 }; 00106 HRSRC hrsrc; 00107 MMIOINFO mminfo; 00108 LPVOID lpAvi; 00109 00110 hrsrc = FindResourceW(hInst, lpName, aviW); 00111 if (!hrsrc) 00112 return FALSE; 00113 00114 infoPtr->hRes = LoadResource(hInst, hrsrc); 00115 if (!infoPtr->hRes) 00116 return FALSE; 00117 00118 lpAvi = LockResource(infoPtr->hRes); 00119 if (!lpAvi) 00120 return FALSE; 00121 00122 memset(&mminfo, 0, sizeof(mminfo)); 00123 mminfo.fccIOProc = FOURCC_MEM; 00124 mminfo.pchBuffer = lpAvi; 00125 mminfo.cchBuffer = SizeofResource(hInst, hrsrc); 00126 infoPtr->hMMio = mmioOpenW(NULL, &mminfo, MMIO_READ); 00127 if (!infoPtr->hMMio) 00128 { 00129 FreeResource(infoPtr->hRes); 00130 return FALSE; 00131 } 00132 00133 return TRUE; 00134 } 00135 00136 00137 static BOOL ANIMATE_LoadFileW(ANIMATE_INFO *infoPtr, LPWSTR lpName) 00138 { 00139 infoPtr->hMMio = mmioOpenW(lpName, 0, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); 00140 00141 if(!infoPtr->hMMio) return FALSE; 00142 return TRUE; 00143 } 00144 00145 00146 static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr) 00147 { 00148 BOOL stopped = FALSE; 00149 00150 EnterCriticalSection(&infoPtr->cs); 00151 00152 /* should stop playing */ 00153 if (infoPtr->hThread) 00154 { 00155 HANDLE handle = infoPtr->hThread; 00156 00157 TRACE("stopping animation thread\n"); 00158 infoPtr->hThread = 0; 00159 SetEvent( infoPtr->hStopEvent ); 00160 00161 if (infoPtr->threadId != GetCurrentThreadId()) 00162 { 00163 LeaveCriticalSection(&infoPtr->cs); /* leave it a chance to run */ 00164 WaitForSingleObject( handle, INFINITE ); 00165 TRACE("animation thread stopped\n"); 00166 EnterCriticalSection(&infoPtr->cs); 00167 } 00168 00169 CloseHandle( handle ); 00170 CloseHandle( infoPtr->hStopEvent ); 00171 infoPtr->hStopEvent = 0; 00172 stopped = TRUE; 00173 } 00174 if (infoPtr->uTimer) { 00175 KillTimer(infoPtr->hwndSelf, infoPtr->uTimer); 00176 infoPtr->uTimer = 0; 00177 stopped = TRUE; 00178 } 00179 00180 LeaveCriticalSection(&infoPtr->cs); 00181 00182 if (stopped) 00183 ANIMATE_Notify(infoPtr, ACN_STOP); 00184 00185 return TRUE; 00186 } 00187 00188 00189 static void ANIMATE_Free(ANIMATE_INFO *infoPtr) 00190 { 00191 if (infoPtr->hMMio) { 00192 ANIMATE_DoStop(infoPtr); 00193 mmioClose(infoPtr->hMMio, 0); 00194 if (infoPtr->hRes) { 00195 FreeResource(infoPtr->hRes); 00196 infoPtr->hRes = 0; 00197 } 00198 Free (infoPtr->lpIndex); 00199 infoPtr->lpIndex = NULL; 00200 if (infoPtr->hic) { 00201 fnIC.fnICClose(infoPtr->hic); 00202 infoPtr->hic = 0; 00203 } 00204 Free (infoPtr->inbih); 00205 infoPtr->inbih = NULL; 00206 Free (infoPtr->outbih); 00207 infoPtr->outbih = NULL; 00208 Free (infoPtr->indata); 00209 infoPtr->indata = NULL; 00210 Free (infoPtr->outdata); 00211 infoPtr->outdata = NULL; 00212 if( infoPtr->hbmPrevFrame ) 00213 { 00214 DeleteObject(infoPtr->hbmPrevFrame); 00215 infoPtr->hbmPrevFrame = 0; 00216 } 00217 00218 memset(&infoPtr->mah, 0, sizeof(infoPtr->mah)); 00219 memset(&infoPtr->ash, 0, sizeof(infoPtr->ash)); 00220 infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0; 00221 } 00222 infoPtr->transparentColor = ANIMATE_COLOR_NONE; 00223 } 00224 00225 static void ANIMATE_TransparentBlt(ANIMATE_INFO const *infoPtr, HDC hdcDest, HDC hdcSource) 00226 { 00227 HDC hdcMask; 00228 HBITMAP hbmMask; 00229 HBITMAP hbmOld; 00230 00231 /* create a transparency mask */ 00232 hdcMask = CreateCompatibleDC(hdcDest); 00233 hbmMask = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1,1,NULL); 00234 hbmOld = SelectObject(hdcMask, hbmMask); 00235 00236 SetBkColor(hdcSource,infoPtr->transparentColor); 00237 BitBlt(hdcMask,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCCOPY); 00238 00239 /* mask the source bitmap */ 00240 SetBkColor(hdcSource, RGB(0,0,0)); 00241 SetTextColor(hdcSource, RGB(255,255,255)); 00242 BitBlt(hdcSource, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); 00243 00244 /* mask the destination bitmap */ 00245 SetBkColor(hdcDest, RGB(255,255,255)); 00246 SetTextColor(hdcDest, RGB(0,0,0)); 00247 BitBlt(hdcDest, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); 00248 00249 /* combine source and destination */ 00250 BitBlt(hdcDest,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCPAINT); 00251 00252 SelectObject(hdcMask, hbmOld); 00253 DeleteObject(hbmMask); 00254 DeleteDC(hdcMask); 00255 } 00256 00257 static BOOL ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC) 00258 { 00259 void const *pBitmapData; 00260 BITMAPINFO const *pBitmapInfo; 00261 HDC hdcMem; 00262 HBITMAP hbmOld; 00263 int nOffsetX = 0; 00264 int nOffsetY = 0; 00265 int nWidth; 00266 int nHeight; 00267 00268 if (!hDC || !infoPtr->inbih) 00269 return TRUE; 00270 00271 if (infoPtr->hic ) 00272 { 00273 pBitmapData = infoPtr->outdata; 00274 pBitmapInfo = (LPBITMAPINFO)infoPtr->outbih; 00275 00276 nWidth = infoPtr->outbih->biWidth; 00277 nHeight = infoPtr->outbih->biHeight; 00278 } 00279 else 00280 { 00281 pBitmapData = infoPtr->indata; 00282 pBitmapInfo = (LPBITMAPINFO)infoPtr->inbih; 00283 00284 nWidth = infoPtr->inbih->biWidth; 00285 nHeight = infoPtr->inbih->biHeight; 00286 } 00287 00288 if(!infoPtr->hbmPrevFrame) 00289 { 00290 infoPtr->hbmPrevFrame=CreateCompatibleBitmap(hDC, nWidth,nHeight ); 00291 } 00292 00293 hdcMem = CreateCompatibleDC(hDC); 00294 hbmOld = SelectObject(hdcMem, infoPtr->hbmPrevFrame); 00295 00296 SetDIBits(hdcMem, infoPtr->hbmPrevFrame, 0, nHeight, pBitmapData, pBitmapInfo, DIB_RGB_COLORS); 00297 00298 /* 00299 * we need to get the transparent color even without ACS_TRANSPARENT, 00300 * because the style can be changed later on and the color should always 00301 * be obtained in the first frame 00302 */ 00303 if(infoPtr->transparentColor == ANIMATE_COLOR_NONE) 00304 { 00305 infoPtr->transparentColor = GetPixel(hdcMem,0,0); 00306 } 00307 00308 if(infoPtr->dwStyle & ACS_TRANSPARENT) 00309 { 00310 HDC hdcFinal = CreateCompatibleDC(hDC); 00311 HBITMAP hbmFinal = CreateCompatibleBitmap(hDC,nWidth, nHeight); 00312 HBITMAP hbmOld2 = SelectObject(hdcFinal, hbmFinal); 00313 RECT rect; 00314 00315 rect.left = 0; 00316 rect.top = 0; 00317 rect.right = nWidth; 00318 rect.bottom = nHeight; 00319 00320 if(!infoPtr->hbrushBG) 00321 infoPtr->hbrushBG = GetCurrentObject(hDC, OBJ_BRUSH); 00322 00323 FillRect(hdcFinal, &rect, infoPtr->hbrushBG); 00324 ANIMATE_TransparentBlt(infoPtr, hdcFinal, hdcMem); 00325 00326 SelectObject(hdcFinal, hbmOld2); 00327 SelectObject(hdcMem, hbmFinal); 00328 DeleteDC(hdcFinal); 00329 DeleteObject(infoPtr->hbmPrevFrame); 00330 infoPtr->hbmPrevFrame = hbmFinal; 00331 } 00332 00333 if (infoPtr->dwStyle & ACS_CENTER) 00334 { 00335 RECT rect; 00336 00337 GetWindowRect(infoPtr->hwndSelf, &rect); 00338 nOffsetX = ((rect.right - rect.left) - nWidth)/2; 00339 nOffsetY = ((rect.bottom - rect.top) - nHeight)/2; 00340 } 00341 BitBlt(hDC, nOffsetX, nOffsetY, nWidth, nHeight, hdcMem, 0, 0, SRCCOPY); 00342 00343 SelectObject(hdcMem, hbmOld); 00344 DeleteDC(hdcMem); 00345 return TRUE; 00346 } 00347 00348 static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr, HDC hDC) 00349 { 00350 TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop); 00351 00352 mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET); 00353 mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize); 00354 00355 if (infoPtr->hic && 00356 fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata, 00357 infoPtr->outbih, infoPtr->outdata) != ICERR_OK) { 00358 WARN("Decompression error\n"); 00359 return FALSE; 00360 } 00361 00362 ANIMATE_PaintFrame(infoPtr, hDC); 00363 00364 if (infoPtr->currFrame++ >= infoPtr->nToFrame) { 00365 infoPtr->currFrame = infoPtr->nFromFrame; 00366 if (infoPtr->nLoop != -1) { 00367 if (--infoPtr->nLoop == 0) { 00368 ANIMATE_DoStop(infoPtr); 00369 } 00370 } 00371 } 00372 00373 return TRUE; 00374 } 00375 00376 static LRESULT ANIMATE_Timer(ANIMATE_INFO *infoPtr) 00377 { 00378 HDC hDC; 00379 00380 if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) 00381 { 00382 EnterCriticalSection(&infoPtr->cs); 00383 ANIMATE_DrawFrame(infoPtr, hDC); 00384 LeaveCriticalSection(&infoPtr->cs); 00385 00386 ReleaseDC(infoPtr->hwndSelf, hDC); 00387 } 00388 00389 return 0; 00390 } 00391 00392 static DWORD CALLBACK ANIMATE_AnimationThread(LPVOID ptr_) 00393 { 00394 ANIMATE_INFO *infoPtr = ptr_; 00395 HANDLE event; 00396 DWORD timeout; 00397 00398 while(1) 00399 { 00400 HDC hDC = GetDC(infoPtr->hwndSelf); 00401 00402 EnterCriticalSection(&infoPtr->cs); 00403 ANIMATE_DrawFrame(infoPtr, hDC); 00404 timeout = infoPtr->mah.dwMicroSecPerFrame; 00405 event = infoPtr->hStopEvent; 00406 LeaveCriticalSection(&infoPtr->cs); 00407 00408 ReleaseDC(infoPtr->hwndSelf, hDC); 00409 00410 /* time is in microseconds, we should convert it to milliseconds */ 00411 if ((event == 0) || WaitForSingleObject( event, (timeout+500)/1000) == WAIT_OBJECT_0) 00412 break; 00413 } 00414 return TRUE; 00415 } 00416 00417 static LRESULT ANIMATE_Play(ANIMATE_INFO *infoPtr, UINT cRepeat, WORD wFrom, WORD wTo) 00418 { 00419 /* nothing opened */ 00420 if (!infoPtr->hMMio) 00421 return FALSE; 00422 00423 if (infoPtr->hThread || infoPtr->uTimer) { 00424 TRACE("Already playing\n"); 00425 return TRUE; 00426 } 00427 00428 infoPtr->nFromFrame = wFrom; 00429 infoPtr->nToFrame = wTo; 00430 infoPtr->nLoop = cRepeat; 00431 00432 if (infoPtr->nToFrame == 0xFFFF) 00433 infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1; 00434 00435 TRACE("(repeat=%d from=%d to=%d);\n", 00436 infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame); 00437 00438 if (infoPtr->nFromFrame >= infoPtr->mah.dwTotalFrames && 00439 (SHORT)infoPtr->nFromFrame < 0) 00440 infoPtr->nFromFrame = 0; 00441 00442 if (infoPtr->nFromFrame > infoPtr->nToFrame || 00443 infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames) 00444 return FALSE; 00445 00446 infoPtr->currFrame = infoPtr->nFromFrame; 00447 00448 /* seek - doesn't need to start a thread or set a timer and neither 00449 * does it send a notification */ 00450 if (infoPtr->nFromFrame == infoPtr->nToFrame) 00451 { 00452 HDC hDC; 00453 00454 if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) 00455 { 00456 ANIMATE_DrawFrame(infoPtr, hDC); 00457 00458 ReleaseDC(infoPtr->hwndSelf, hDC); 00459 } 00460 return TRUE; 00461 } 00462 00463 if (infoPtr->dwStyle & ACS_TIMER) 00464 { 00465 TRACE("Using a timer\n"); 00466 /* create a timer to display AVI */ 00467 infoPtr->uTimer = SetTimer(infoPtr->hwndSelf, 1, 00468 infoPtr->mah.dwMicroSecPerFrame / 1000, NULL); 00469 } 00470 else 00471 { 00472 TRACE("Using an animation thread\n"); 00473 infoPtr->hStopEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); 00474 infoPtr->hThread = CreateThread(0, 0, ANIMATE_AnimationThread, 00475 infoPtr, 0, &infoPtr->threadId); 00476 if(!infoPtr->hThread) return FALSE; 00477 00478 } 00479 00480 ANIMATE_Notify(infoPtr, ACN_START); 00481 00482 return TRUE; 00483 } 00484 00485 00486 static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr) 00487 { 00488 MMCKINFO ckMainRIFF; 00489 MMCKINFO mmckHead; 00490 MMCKINFO mmckList; 00491 MMCKINFO mmckInfo; 00492 DWORD numFrame; 00493 DWORD insize; 00494 00495 if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) { 00496 WARN("Can't find 'RIFF' chunk\n"); 00497 return FALSE; 00498 } 00499 00500 if ((ckMainRIFF.ckid != FOURCC_RIFF) || 00501 (ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) { 00502 WARN("Can't find 'AVI ' chunk\n"); 00503 return FALSE; 00504 } 00505 00506 mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l'); 00507 if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) { 00508 WARN("Can't find 'hdrl' list\n"); 00509 return FALSE; 00510 } 00511 00512 mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h'); 00513 if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) { 00514 WARN("Can't find 'avih' chunk\n"); 00515 return FALSE; 00516 } 00517 00518 mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah)); 00519 00520 TRACE("mah.dwMicroSecPerFrame=%d\n", infoPtr->mah.dwMicroSecPerFrame); 00521 TRACE("mah.dwMaxBytesPerSec=%d\n", infoPtr->mah.dwMaxBytesPerSec); 00522 TRACE("mah.dwPaddingGranularity=%d\n", infoPtr->mah.dwPaddingGranularity); 00523 TRACE("mah.dwFlags=%d\n", infoPtr->mah.dwFlags); 00524 TRACE("mah.dwTotalFrames=%d\n", infoPtr->mah.dwTotalFrames); 00525 TRACE("mah.dwInitialFrames=%d\n", infoPtr->mah.dwInitialFrames); 00526 TRACE("mah.dwStreams=%d\n", infoPtr->mah.dwStreams); 00527 TRACE("mah.dwSuggestedBufferSize=%d\n", infoPtr->mah.dwSuggestedBufferSize); 00528 TRACE("mah.dwWidth=%d\n", infoPtr->mah.dwWidth); 00529 TRACE("mah.dwHeight=%d\n", infoPtr->mah.dwHeight); 00530 00531 mmioAscend(infoPtr->hMMio, &mmckInfo, 0); 00532 00533 mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); 00534 if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) { 00535 WARN("Can't find 'strl' list\n"); 00536 return FALSE; 00537 } 00538 00539 mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h'); 00540 if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { 00541 WARN("Can't find 'strh' chunk\n"); 00542 return FALSE; 00543 } 00544 00545 mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash)); 00546 00547 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccType)), 00548 HIBYTE(LOWORD(infoPtr->ash.fccType)), 00549 LOBYTE(HIWORD(infoPtr->ash.fccType)), 00550 HIBYTE(HIWORD(infoPtr->ash.fccType))); 00551 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccHandler)), 00552 HIBYTE(LOWORD(infoPtr->ash.fccHandler)), 00553 LOBYTE(HIWORD(infoPtr->ash.fccHandler)), 00554 HIBYTE(HIWORD(infoPtr->ash.fccHandler))); 00555 TRACE("ash.dwFlags=%d\n", infoPtr->ash.dwFlags); 00556 TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority); 00557 TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage); 00558 TRACE("ash.dwInitialFrames=%d\n", infoPtr->ash.dwInitialFrames); 00559 TRACE("ash.dwScale=%d\n", infoPtr->ash.dwScale); 00560 TRACE("ash.dwRate=%d\n", infoPtr->ash.dwRate); 00561 TRACE("ash.dwStart=%d\n", infoPtr->ash.dwStart); 00562 TRACE("ash.dwLength=%d\n", infoPtr->ash.dwLength); 00563 TRACE("ash.dwSuggestedBufferSize=%d\n", infoPtr->ash.dwSuggestedBufferSize); 00564 TRACE("ash.dwQuality=%d\n", infoPtr->ash.dwQuality); 00565 TRACE("ash.dwSampleSize=%d\n", infoPtr->ash.dwSampleSize); 00566 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left, 00567 infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right); 00568 00569 mmioAscend(infoPtr->hMMio, &mmckInfo, 0); 00570 00571 mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f'); 00572 if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { 00573 WARN("Can't find 'strh' chunk\n"); 00574 return FALSE; 00575 } 00576 00577 infoPtr->inbih = Alloc(mmckInfo.cksize); 00578 if (!infoPtr->inbih) { 00579 WARN("Can't alloc input BIH\n"); 00580 return FALSE; 00581 } 00582 00583 mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize); 00584 00585 TRACE("bih.biSize=%d\n", infoPtr->inbih->biSize); 00586 TRACE("bih.biWidth=%d\n", infoPtr->inbih->biWidth); 00587 TRACE("bih.biHeight=%d\n", infoPtr->inbih->biHeight); 00588 TRACE("bih.biPlanes=%d\n", infoPtr->inbih->biPlanes); 00589 TRACE("bih.biBitCount=%d\n", infoPtr->inbih->biBitCount); 00590 TRACE("bih.biCompression=%d\n", infoPtr->inbih->biCompression); 00591 TRACE("bih.biSizeImage=%d\n", infoPtr->inbih->biSizeImage); 00592 TRACE("bih.biXPelsPerMeter=%d\n", infoPtr->inbih->biXPelsPerMeter); 00593 TRACE("bih.biYPelsPerMeter=%d\n", infoPtr->inbih->biYPelsPerMeter); 00594 TRACE("bih.biClrUsed=%d\n", infoPtr->inbih->biClrUsed); 00595 TRACE("bih.biClrImportant=%d\n", infoPtr->inbih->biClrImportant); 00596 00597 mmioAscend(infoPtr->hMMio, &mmckInfo, 0); 00598 00599 mmioAscend(infoPtr->hMMio, &mmckList, 0); 00600 00601 #if 0 00602 /* an AVI has 0 or 1 video stream, and to be animated should not contain 00603 * an audio stream, so only one strl is allowed 00604 */ 00605 mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); 00606 if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) { 00607 WARN("There should be a single 'strl' list\n"); 00608 return FALSE; 00609 } 00610 #endif 00611 00612 mmioAscend(infoPtr->hMMio, &mmckHead, 0); 00613 00614 /* no need to read optional JUNK chunk */ 00615 00616 mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i'); 00617 if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) { 00618 WARN("Can't find 'movi' list\n"); 00619 return FALSE; 00620 } 00621 00622 /* FIXME: should handle the 'rec ' LIST when present */ 00623 00624 infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD)); 00625 if (!infoPtr->lpIndex) 00626 return FALSE; 00627 00628 numFrame = insize = 0; 00629 while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 && 00630 numFrame < infoPtr->mah.dwTotalFrames) { 00631 infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset; 00632 if (insize < mmckInfo.cksize) 00633 insize = mmckInfo.cksize; 00634 numFrame++; 00635 mmioAscend(infoPtr->hMMio, &mmckInfo, 0); 00636 } 00637 if (numFrame != infoPtr->mah.dwTotalFrames) { 00638 WARN("Found %d frames (/%d)\n", numFrame, infoPtr->mah.dwTotalFrames); 00639 return FALSE; 00640 } 00641 if (insize > infoPtr->ash.dwSuggestedBufferSize) { 00642 WARN("insize=%d suggestedSize=%d\n", insize, infoPtr->ash.dwSuggestedBufferSize); 00643 infoPtr->ash.dwSuggestedBufferSize = insize; 00644 } 00645 00646 infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize); 00647 if (!infoPtr->indata) 00648 return FALSE; 00649 00650 return TRUE; 00651 } 00652 00653 00654 static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr) 00655 { 00656 DWORD outSize; 00657 00658 /* check uncompressed AVI */ 00659 if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) || 00660 (infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) || 00661 (infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0))) 00662 { 00663 infoPtr->hic = 0; 00664 return TRUE; 00665 } 00666 00667 /* try to get a decompressor for that type */ 00668 infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS); 00669 if (!infoPtr->hic) { 00670 WARN("Can't load codec for the file\n"); 00671 return FALSE; 00672 } 00673 00674 outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, 00675 (DWORD_PTR)infoPtr->inbih, 0L); 00676 00677 infoPtr->outbih = Alloc(outSize); 00678 if (!infoPtr->outbih) 00679 return FALSE; 00680 00681 if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, 00682 (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) 00683 { 00684 WARN("Can't get output BIH\n"); 00685 return FALSE; 00686 } 00687 00688 infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage); 00689 if (!infoPtr->outdata) 00690 return FALSE; 00691 00692 if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN, 00693 (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) { 00694 WARN("Can't begin decompression\n"); 00695 return FALSE; 00696 } 00697 00698 return TRUE; 00699 } 00700 00701 00702 static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lpszName) 00703 { 00704 HDC hdc; 00705 00706 ANIMATE_Free(infoPtr); 00707 00708 if (!lpszName) 00709 { 00710 TRACE("Closing avi!\n"); 00711 /* installer of thebat! v1.62 requires FALSE here */ 00712 return (infoPtr->hMMio != 0); 00713 } 00714 00715 if (!hInstance) 00716 hInstance = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE); 00717 00718 TRACE("(%s)\n", debugstr_w(lpszName)); 00719 00720 if (!IS_INTRESOURCE(lpszName)) 00721 { 00722 if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) 00723 { 00724 TRACE("No AVI resource found!\n"); 00725 if (!ANIMATE_LoadFileW(infoPtr, lpszName)) 00726 { 00727 WARN("No AVI file found!\n"); 00728 return FALSE; 00729 } 00730 } 00731 } 00732 else 00733 { 00734 if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) 00735 { 00736 WARN("No AVI resource found!\n"); 00737 return FALSE; 00738 } 00739 } 00740 00741 if (!ANIMATE_GetAviInfo(infoPtr)) 00742 { 00743 WARN("Can't get AVI information\n"); 00744 ANIMATE_Free(infoPtr); 00745 return FALSE; 00746 } 00747 00748 if (!ANIMATE_GetAviCodec(infoPtr)) 00749 { 00750 WARN("Can't get AVI Codec\n"); 00751 ANIMATE_Free(infoPtr); 00752 return FALSE; 00753 } 00754 00755 hdc = GetDC(infoPtr->hwndSelf); 00756 /* native looks at the top left pixel of the first frame here too. */ 00757 infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC, 00758 (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); 00759 ReleaseDC(infoPtr->hwndSelf, hdc); 00760 00761 if (!(infoPtr->dwStyle & ACS_CENTER)) 00762 SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight, 00763 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); 00764 00765 if (infoPtr->dwStyle & ACS_AUTOPLAY) 00766 return ANIMATE_Play(infoPtr, -1, 0, infoPtr->mah.dwTotalFrames - 1); 00767 00768 return TRUE; 00769 } 00770 00771 00772 static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpszName) 00773 { 00774 LPWSTR lpwszName; 00775 LRESULT result; 00776 INT len; 00777 00778 if (IS_INTRESOURCE(lpszName)) 00779 return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName); 00780 00781 len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0); 00782 lpwszName = Alloc(len * sizeof(WCHAR)); 00783 if (!lpwszName) return FALSE; 00784 MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len); 00785 00786 result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName); 00787 Free (lpwszName); 00788 return result; 00789 } 00790 00791 00792 static BOOL ANIMATE_Stop(ANIMATE_INFO *infoPtr) 00793 { 00794 /* nothing opened */ 00795 if (!infoPtr->hMMio) 00796 return FALSE; 00797 00798 ANIMATE_DoStop(infoPtr); 00799 return TRUE; 00800 } 00801 00802 00803 static BOOL ANIMATE_Create(HWND hWnd, const CREATESTRUCTW *lpcs) 00804 { 00805 static const WCHAR msvfw32W[] = { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', 0 }; 00806 ANIMATE_INFO *infoPtr; 00807 00808 if (!fnIC.hModule) 00809 { 00810 fnIC.hModule = LoadLibraryW(msvfw32W); 00811 if (!fnIC.hModule) return FALSE; 00812 00813 fnIC.fnICOpen = (void*)GetProcAddress(fnIC.hModule, "ICOpen"); 00814 fnIC.fnICClose = (void*)GetProcAddress(fnIC.hModule, "ICClose"); 00815 fnIC.fnICSendMessage = (void*)GetProcAddress(fnIC.hModule, "ICSendMessage"); 00816 fnIC.fnICDecompress = (void*)GetProcAddress(fnIC.hModule, "ICDecompress"); 00817 } 00818 00819 /* allocate memory for info structure */ 00820 infoPtr = Alloc(sizeof(ANIMATE_INFO)); 00821 if (!infoPtr) return FALSE; 00822 00823 /* store crossref hWnd <-> info structure */ 00824 SetWindowLongPtrW(hWnd, 0, (DWORD_PTR)infoPtr); 00825 infoPtr->hwndSelf = hWnd; 00826 infoPtr->hwndNotify = lpcs->hwndParent; 00827 infoPtr->transparentColor = ANIMATE_COLOR_NONE; 00828 infoPtr->hbmPrevFrame = 0; 00829 infoPtr->dwStyle = lpcs->style; 00830 00831 TRACE("Animate style=0x%08x, parent=%p\n", infoPtr->dwStyle, infoPtr->hwndNotify); 00832 00833 InitializeCriticalSection(&infoPtr->cs); 00834 infoPtr->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ANIMATE_INFO*->cs"); 00835 00836 return TRUE; 00837 } 00838 00839 00840 static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr) 00841 { 00842 /* free avi data */ 00843 ANIMATE_Free(infoPtr); 00844 00845 /* free animate info data */ 00846 SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); 00847 00848 infoPtr->cs.DebugInfo->Spare[0] = 0; 00849 DeleteCriticalSection(&infoPtr->cs); 00850 Free(infoPtr); 00851 00852 return 0; 00853 } 00854 00855 00856 static BOOL ANIMATE_EraseBackground(ANIMATE_INFO const *infoPtr, HDC hdc) 00857 { 00858 RECT rect; 00859 HBRUSH hBrush; 00860 00861 hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC, 00862 (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); 00863 GetClientRect(infoPtr->hwndSelf, &rect); 00864 FillRect(hdc, &rect, hBrush ? hBrush : GetCurrentObject(hdc, OBJ_BRUSH)); 00865 00866 return TRUE; 00867 } 00868 00869 00870 static LRESULT ANIMATE_StyleChanged(ANIMATE_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss) 00871 { 00872 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n", 00873 wStyleType, lpss->styleOld, lpss->styleNew); 00874 00875 if (wStyleType != GWL_STYLE) return 0; 00876 00877 infoPtr->dwStyle = lpss->styleNew; 00878 00879 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 00880 return 0; 00881 } 00882 00883 00884 static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00885 { 00886 ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)GetWindowLongPtrW(hWnd, 0); 00887 00888 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hWnd, uMsg, wParam, lParam); 00889 if (!infoPtr && (uMsg != WM_NCCREATE)) 00890 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 00891 switch (uMsg) 00892 { 00893 case ACM_OPENA: 00894 return ANIMATE_OpenA(infoPtr, (HINSTANCE)wParam, (LPSTR)lParam); 00895 00896 case ACM_OPENW: 00897 return ANIMATE_OpenW(infoPtr, (HINSTANCE)wParam, (LPWSTR)lParam); 00898 00899 case ACM_PLAY: 00900 return ANIMATE_Play(infoPtr, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); 00901 00902 case ACM_STOP: 00903 return ANIMATE_Stop(infoPtr); 00904 00905 case WM_CLOSE: 00906 ANIMATE_Free(infoPtr); 00907 return 0; 00908 00909 case WM_NCCREATE: 00910 return ANIMATE_Create(hWnd, (LPCREATESTRUCTW)lParam); 00911 00912 case WM_NCHITTEST: 00913 return HTTRANSPARENT; 00914 00915 case WM_DESTROY: 00916 return ANIMATE_Destroy(infoPtr); 00917 00918 case WM_ERASEBKGND: 00919 return ANIMATE_EraseBackground(infoPtr, (HDC)wParam); 00920 00921 case WM_STYLECHANGED: 00922 return ANIMATE_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); 00923 00924 case WM_TIMER: 00925 return ANIMATE_Timer(infoPtr); 00926 00927 case WM_PRINTCLIENT: 00928 case WM_PAINT: 00929 { 00930 /* the animation has not decompressed 00931 * (and displayed) the first frame yet, don't paint 00932 */ 00933 if (!infoPtr->hbmPrevFrame) 00934 { 00935 /* default paint handling */ 00936 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 00937 } 00938 00939 if (wParam) 00940 { 00941 EnterCriticalSection(&infoPtr->cs); 00942 ANIMATE_PaintFrame(infoPtr, (HDC)wParam); 00943 LeaveCriticalSection(&infoPtr->cs); 00944 } 00945 else 00946 { 00947 PAINTSTRUCT ps; 00948 HDC hDC = BeginPaint(infoPtr->hwndSelf, &ps); 00949 00950 EnterCriticalSection(&infoPtr->cs); 00951 ANIMATE_PaintFrame(infoPtr, hDC); 00952 LeaveCriticalSection(&infoPtr->cs); 00953 00954 EndPaint(infoPtr->hwndSelf, &ps); 00955 } 00956 } 00957 break; 00958 00959 case WM_SIZE: 00960 if (infoPtr->dwStyle & ACS_CENTER) 00961 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 00962 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 00963 00964 default: 00965 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 00966 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam); 00967 00968 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 00969 } 00970 return 0; 00971 } 00972 00973 void ANIMATE_Register(void) 00974 { 00975 WNDCLASSW wndClass; 00976 00977 ZeroMemory(&wndClass, sizeof(WNDCLASSW)); 00978 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; 00979 wndClass.lpfnWndProc = ANIMATE_WindowProc; 00980 wndClass.cbClsExtra = 0; 00981 wndClass.cbWndExtra = sizeof(ANIMATE_INFO *); 00982 wndClass.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); 00983 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 00984 wndClass.lpszClassName = ANIMATE_CLASSW; 00985 00986 RegisterClassW(&wndClass); 00987 } 00988 00989 00990 void ANIMATE_Unregister(void) 00991 { 00992 UnregisterClassW(ANIMATE_CLASSW, NULL); 00993 } Generated on Fri May 25 2012 04:20:55 for ReactOS by
1.7.6.1
|