#include "stdafx.h" #include <d3dx9.h> #include "D3DQuickLib.h" #include <mmsystem.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> // stat 関数を使う為インクルード #include <crtdbg.h> #include <TCHAR.h> #include <vfw.h> #include <mmreg.h> #include <msacm.h> #include "AVIVideoTexture.h" #pragma comment (lib, "winmm.lib") #pragma comment (lib, "vfw32.lib") // // Prototypes. // LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam); LRESULT CALLBACK IOProc(LPMMIOINFO lpMMIOInfo, UINT uMessage, LPARAM lParam1, LPARAM lParam2); CD3DEnv *g_pD3DEnv = NULL; CBillboard *g_pBillboard = NULL; static char * g_lpData = NULL; static long g_cfileSize; CRITICAL_SECTION g_csSema; CAVIVideoTexture *g_pVideoTexture = NULL; float g_fTime = 0; //------------------------------------------------------------ // Name: FrameMove // Desc: アニメーションを行う。 // UpdateScene 関数(d3dmain.cpp) からコールバックされる。 //------------------------------------------------------------ void FrameMove(float timeElapsed) { g_fTime = timeElapsed; //g_pVideoTexture->CheckMovieStatus(true); } //------------------------------------------------------------ // Name: RenderScene // Desc: レンダリングを行う。 // UpdateScene 関数(d3dmain.cpp) からコールバックされる。 //------------------------------------------------------------ void RenderScene(LPDIRECT3DDEVICE9 lpd3ddev) { Yield(); g_pVideoTexture->Lock(); LPDIRECT3DTEXTURE9 pTex = g_pVideoTexture->GetRenderableTexture(); if (pTex != NULL){ int w, h; g_pVideoTexture->GetRenderableTextureSize(&w,&h); g_pBillboard->Render(lpd3ddev,0,0,640,480,0,0,w,h,pTex); lpd3ddev->SetTexture(0,NULL); } g_pVideoTexture->Unlock(); } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = "AVITexture"; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wcex); HWND hWnd; hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wcex.lpszClassName,"AVITexture -- Play AVI Movie", WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, CW_USEDEFAULT,0,640,480,NULL,NULL,hInstance,NULL); if( !hWnd ) return FALSE; RECT bounds,client; GetWindowRect(hWnd,&bounds); GetClientRect(hWnd,&client); MoveWindow(hWnd,bounds.left,bounds.top, 640 * 2 - client.right, 480 * 2 - client.bottom, false ); ShowWindow( hWnd, nCmdShow ); UpdateWindow( hWnd ); //CoInitialize(NULL); InitializeCriticalSection(&g_csSema); g_pD3DEnv = new CD3DEnv(); if (SUCCEEDED(g_pD3DEnv->InitD3D(hWnd))){ PAVIFILE lpAviFile = NULL; PAVISTREAM lpVideoStream = NULL; struct _stat status; if (0 == _tstat(_T("test.avi"),&status)){ g_cfileSize = status.st_size; g_lpData = new char[g_cfileSize]; FILE *fp = fopen(_T("test.avi"),_T("rb")); if (fp != NULL){ fread(g_lpData,g_cfileSize,1,fp); fclose(fp); // mci:カスタムIOProc のインストール mmioInstallIOProc(mmioFOURCC('M', 'E', 'V', ' '), (LPMMIOPROC)IOProc, MMIO_INSTALLPROC | MMIO_GLOBALPROC); AVIFileInit(); if (AVIFileOpen(&lpAviFile, TEXT("test.MEV+"), OF_READ, NULL) != 0) return -1; if (AVIFileGetStream(lpAviFile, &lpVideoStream, streamtypeVIDEO, 0) != 0) lpVideoStream = NULL; } } if (lpVideoStream != NULL){ g_pVideoTexture = new CAVIVideoTexture(g_pD3DEnv,lpVideoStream); } g_pBillboard = new CBillboard(g_pD3DEnv,0); g_pD3DEnv->ReloadGraphics(); } MSG msg; while(true){ if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){ if(msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); }else{ g_pD3DEnv->UpdateScene(FrameMove,RenderScene); if (!g_pVideoTexture->IsPlaying()){ Sleep(100); g_pVideoTexture->Rewind(); g_pVideoTexture->Run(); } } } SAFE_DELETE(g_pBillboard); SAFE_DELETE(g_pVideoTexture); SAFE_DELETE(g_pD3DEnv); EnterCriticalSection(&g_csSema); if (g_lpData != NULL){ mmioInstallIOProc(mmioFOURCC('M', 'E', 'V', ' '), NULL,MMIO_REMOVEPROC); delete g_lpData; g_lpData = NULL; } LeaveCriticalSection(&g_csSema); DeleteCriticalSection(&g_csSema); //CoUninitialize(); return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { switch (message){ case WM_SIZE: if (SIZE_MAXIMIZED == wParam){ g_pD3DEnv->ForceFullscreen(); } break; case WM_SETCURSOR: if (g_pD3DEnv->IsWindowed()) ::SetCursor(::LoadCursor(NULL,IDC_ARROW)); else ::SetCursor(NULL); break; case WM_SYSCHAR: if (lParam&0x20000000){ if (wParam == '\x0d'){ g_pD3DEnv->ToggleFullscreen(); break; } } return DefWindowProc( hWnd, message, wParam, lParam ); case WM_SYSCOMMAND: if (!g_pD3DEnv->IsWindowed()){ // フルスクリーン時 if (wParam != SC_CLOSE) break; // Windowが閉じられる前にWindowモードに戻しておく。 g_pD3DEnv->ToggleFullscreen(); Sleep(100); } return DefWindowProc( hWnd, message, wParam, lParam ); case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // // mmio: IOProc // LRESULT CALLBACK IOProc(LPMMIOINFO lpMMIOInfo, UINT uMessage, LPARAM lParam1, LPARAM lParam2) { static BOOL alreadyOpened = FALSE; switch (uMessage) { case MMIOM_OPEN: if (alreadyOpened) return 0; alreadyOpened = TRUE; lpMMIOInfo->lDiskOffset = 0; return 0; case MMIOM_CLOSE: return 0; case MMIOM_READ:{ LPARAM dataRead = 0; EnterCriticalSection(&g_csSema); if (g_lpData != NULL){ dataRead = lParam2; memcpy((void *)lParam1, g_lpData+lpMMIOInfo->lDiskOffset, lParam2); lpMMIOInfo->lDiskOffset += lParam2; dataRead = lParam2; } LeaveCriticalSection(&g_csSema); return (dataRead); } case MMIOM_SEEK: switch (lParam2) { case SEEK_SET: lpMMIOInfo->lDiskOffset = lParam1; break; case SEEK_CUR: lpMMIOInfo->lDiskOffset += lParam1; break; case SEEK_END: lpMMIOInfo->lDiskOffset = g_cfileSize - lParam1; break; } return lpMMIOInfo->lDiskOffset; default: return -1; } }
//----------------------------------------------------------------------------- // File: AVIVideoTexture.h // // Desc: //----------------------------------------------------------------------------- #ifndef __AVIVIDEOTEXTURE_H__ #define __AVIVIDEOTEXTURE_H__ #define AVIVIDEOTEXTURE_PHASE_CREATED 0 #define AVIVIDEOTEXTURE_PHASE_PREPARED 1 #define AVIVIDEOTEXTURE_PHASE_PLAYING 2 #define AVIVIDEOTEXTURE_PHASE_PAUSED 3 #define AVIVIDEOTEXTURE_PHASE_END 4 #define kNumTextures 2 typedef struct{ LONG m_lTextureWidth; LONG m_lTextureHeight; } TextureSize; //-------------------------------------------------------------- // CAVIVideoTexture //-------------------------------------------------------------- class CAVIVideoTexture : public CGraphicsObject { public: CAVIVideoTexture(CD3DEnv *pEnv,PAVISTREAM pVideoStream); virtual ~CAVIVideoTexture(); virtual HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 lpd3ddev); virtual HRESULT RestoreDeviceObjects(LPDIRECT3DDEVICE9 lpd3ddev); virtual HRESULT InvalidateDeviceObjects(); virtual HRESULT DeleteDeviceObjects(); LPDIRECT3DTEXTURE9 GetRenderableTexture(); void GetRenderableTextureSize(int *x, int *y); void GetVideoSize(int *x, int *y); BOOL IsPlaying(){ return m_dwPhase == AVIVIDEOTEXTURE_PHASE_PLAYING; } void Rewind(); void Pause(); void Run(); void Stop(); void DoThread(); void Lock(); void Unlock(); protected: LPDIRECT3DTEXTURE9 m_ppTextures[kNumTextures]; // TextureSize m_TextureSize[kNumTextures]; // テクスチャサイズ CD3DEnv *m_pD3DEnv; BOOL m_bPlaying; DWORD m_dwThreadID; HANDLE m_hThread; BOOL m_bTerminateThread; BOOL m_bThreadAlive; PAVISTREAM m_pVideoStream; LONG m_lVidWidth; LONG m_lVidHeight; LONG m_lVidPitch; D3DFORMAT m_TextureFormat; INT m_iRenderableTexture; CRITICAL_SECTION m_semaphore; LONG m_lCurrentVideoTime; LONG m_lOldTime; DWORD m_dwPhase; }; #endif
// // VideoTexture.cpp // #include "stdafx.h" #include <d3dx9.h> #include <mmsystem.h> #include <stdio.h> #include <d3d9types.h> #include <crtdbg.h> #include "d3d9env.h" #include <vfw.h> #include <mmreg.h> #include <msacm.h> #include "AVIVideoTexture.h" static DWORD WINAPI ThreadProc(LPVOID lp); // // class: CAVIVideoTexture // CAVIVideoTexture::CAVIVideoTexture(CD3DEnv *pEnv,PAVISTREAM pVideoStream){ int i; for (i = 0; i < kNumTextures ; ++i){ m_ppTextures[i] = NULL; m_TextureSize[i].m_lTextureWidth = -1; m_TextureSize[i].m_lTextureHeight = -1; } m_bPlaying = false; m_pD3DEnv = pEnv; m_pVideoStream = pVideoStream; pEnv->AddGraphicsObject(this); m_hThread = NULL; m_lVidWidth = -1; m_lVidHeight= -1; InitializeCriticalSection(&m_semaphore); m_dwPhase = AVIVIDEOTEXTURE_PHASE_CREATED; m_lCurrentVideoTime = 0; } CAVIVideoTexture::~CAVIVideoTexture(){ InvalidateDeviceObjects(); DeleteDeviceObjects(); InitializeCriticalSection(&m_semaphore); DeleteCriticalSection(&m_semaphore); m_pD3DEnv->RemoveGraphicsObject(this); } //----------------------------------------------------------------------------- // Init : ビデオ再生を準備する。 //----------------------------------------------------------------------------- HRESULT CAVIVideoTexture::InitDeviceObjects(LPDIRECT3DDEVICE9 lpd3ddev) { if (m_hThread == NULL){ m_bTerminateThread = FALSE; m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)this, 0, &m_dwThreadID); m_dwPhase = AVIVIDEOTEXTURE_PHASE_PREPARED; } return S_OK; } HRESULT CAVIVideoTexture::RestoreDeviceObjects(LPDIRECT3DDEVICE9 lpd3ddev){ return S_OK; } HRESULT CAVIVideoTexture::InvalidateDeviceObjects(){ return S_OK; } HRESULT CAVIVideoTexture::DeleteDeviceObjects(){ if (m_hThread != NULL){ m_bTerminateThread = TRUE; while(m_bThreadAlive){ Sleep(10); } CloseHandle(m_hThread); m_hThread = NULL; for (int i = 0; i < kNumTextures ; ++i){ if (m_ppTextures[i] != NULL){ m_ppTextures[i]->Release(); m_ppTextures[i] = NULL; } } } return S_OK; } LPDIRECT3DTEXTURE9 CAVIVideoTexture::GetRenderableTexture (){ int iRenderableTexture = m_iRenderableTexture; if (iRenderableTexture < 0) return NULL; return m_ppTextures[iRenderableTexture]; } void CAVIVideoTexture::GetRenderableTextureSize(int *x, int *y){ *x = -1; *y = -1; int iRenderableTexture = m_iRenderableTexture; if (iRenderableTexture < 0) return; *x = m_TextureSize[iRenderableTexture].m_lTextureWidth; *y = m_TextureSize[iRenderableTexture].m_lTextureHeight; } void CAVIVideoTexture::GetVideoSize(int *x, int *y){ *x = (INT)m_lVidWidth; *y = (INT)m_lVidHeight; } void CAVIVideoTexture::Run(){ if (m_dwPhase != AVIVIDEOTEXTURE_PHASE_PLAYING){ m_dwPhase = AVIVIDEOTEXTURE_PHASE_PREPARED; m_lOldTime = timeGetTime(); m_dwPhase = AVIVIDEOTEXTURE_PHASE_PLAYING; } } void CAVIVideoTexture::Stop(){ if (m_dwPhase == AVIVIDEOTEXTURE_PHASE_PLAYING){ m_dwPhase = AVIVIDEOTEXTURE_PHASE_END; m_lCurrentVideoTime = 0; } } void CAVIVideoTexture::Rewind(){ if (m_dwPhase == AVIVIDEOTEXTURE_PHASE_PLAYING){ m_dwPhase = AVIVIDEOTEXTURE_PHASE_END; } m_lCurrentVideoTime = 0; m_lOldTime = timeGetTime(); } void CAVIVideoTexture::Pause(){ if (m_dwPhase == AVIVIDEOTEXTURE_PHASE_PLAYING){ m_dwPhase = AVIVIDEOTEXTURE_PHASE_PAUSED; } } void CAVIVideoTexture::DoThread(){ LONG i,lCurrent; LONG lStart, lEnd; LONG lSize; HWND hWnd; LPBYTE lpBits; AVISTREAMINFO asi; BITMAPINFOHEADER bih; BOOL bOffscreen = FALSE; HIC hic =NULL; // イメージデコンプレッサへのハンドル m_bThreadAlive = true; lStart = AVIStreamStart(m_pVideoStream); DWORD st = timeGetTime(); DWORD ct; lEnd = lStart + AVIStreamLength(m_pVideoStream); lCurrent = lEnd+1; AVIStreamInfo(m_pVideoStream, &asi, sizeof(AVISTREAMINFO)); m_iRenderableTexture = -1; hic = ICOpen(mmioFOURCC('V', 'I', 'D', 'C'),asi.fccHandler,ICMODE_DECOMPRESS); lSize = sizeof(BITMAPINFOHEADER); AVIStreamReadFormat(m_pVideoStream, lStart, &bih, &lSize); m_lVidWidth = bih.biWidth; m_lVidHeight = bih.biHeight; m_lVidPitch = (m_lVidWidth * 3 + 3) & ~(3); // 4バイト毎にアライメントをとる /* * デコード出力先のDibSection を作成する。 */ HDC hDC = CreateCompatibleDC( NULL ); HBITMAP hbmBitmap = NULL; BYTE *pBitmapBits; BITMAPINFO bmiOut; ZeroMemory( &bmiOut.bmiHeader, sizeof(BITMAPINFOHEADER) ); bmiOut.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmiOut.bmiHeader.biWidth = (int)m_lVidWidth; bmiOut.bmiHeader.biHeight = -(int)m_lVidHeight; bmiOut.bmiHeader.biPlanes = 1; bmiOut.bmiHeader.biCompression = BI_RGB; bmiOut.bmiHeader.biBitCount = 24; hbmBitmap = CreateDIBSection( hDC, &bmiOut, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0 ); if (hic != NULL) ICDecompressBegin(hic, &bih, &bmiOut.bmiHeader); /* * テクスチャのフリッピングを行う為複数のテクスチャを生成する。 */ LPDIRECT3DDEVICE9 lpd3ddev; HRESULT hr = S_OK; m_pD3DEnv->GetD3DDevice(&lpd3ddev); if( FAILED( hr = D3DXCreateTexture(lpd3ddev, m_lVidWidth, m_lVidHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_ppTextures[0] ) ) ){ _RPT1(_CRT_WARN,TEXT("テクスチャ生成に失敗しました! hr=0x%x"), hr); }else{ D3DSURFACE_DESC ddsd; D3DFORMAT fmtPrimary; if ( FAILED( hr = m_ppTextures[0]->GetLevelDesc( 0, &ddsd ) ) ) { _RPT1(_CRT_WARN,TEXT("テクスチャ情報の取得に失敗しました! hr = 0x%x"), hr); }else{ m_TextureSize[0].m_lTextureWidth = ddsd.Width; m_TextureSize[0].m_lTextureHeight = ddsd.Height; fmtPrimary = ddsd.Format; for (int i = 1; i < kNumTextures ; ++i){ if( FAILED( hr = D3DXCreateTexture(lpd3ddev, m_lVidWidth, m_lVidHeight, 1, 0, fmtPrimary, D3DPOOL_MANAGED, &m_ppTextures[i] ) ) ) { _RPT1(_CRT_WARN,TEXT("テクスチャ生成に失敗しました! hr=0x%x"), hr); }else{ // D3DXCreateTexture が実際に作ったテクスチャのサイズを取得 if ( FAILED( hr = m_ppTextures[i]->GetLevelDesc( 0, &ddsd ) ) ) { _RPT1(_CRT_WARN,TEXT("テクスチャ情報の取得に失敗しました! hr = 0x%x"), hr); }else{ m_TextureFormat = ddsd.Format; if (m_TextureFormat == fmtPrimary){ m_TextureSize[i].m_lTextureWidth = ddsd.Width; m_TextureSize[i].m_lTextureHeight = ddsd.Height; } } } } } } while (!m_bTerminateThread) { while (true) { if (m_dwPhase != AVIVIDEOTEXTURE_PHASE_PLAYING) goto frame_conversion_end; LONG tc = timeGetTime(); m_lCurrentVideoTime += tc - m_lOldTime; m_lOldTime = tc; i = AVIStreamTimeToSample(m_pVideoStream,(LONG)m_lCurrentVideoTime); if (i >= lEnd){ i = lEnd; lCurrent = lEnd; m_dwPhase = AVIVIDEOTEXTURE_PHASE_END; m_bPlaying = FALSE; } if (lCurrent != i){ if (i > (lCurrent + 1)){ _RPT0(_CRT_WARN,_T("Frame Dropped\n")); ++lCurrent; for (int j = 0; j < 4 ; ++j){ // up to x4 lSize = sizeof(BITMAPINFOHEADER); AVIStreamReadFormat(m_pVideoStream, lCurrent, &bih, &lSize); lpBits = new BYTE[ bih.biSizeImage ]; AVIStreamRead(m_pVideoStream, lCurrent, 1, lpBits, bih.biSizeImage, NULL, NULL); if (hic != NULL){ DWORD err; err = ICDecompress(hic,0,&bih,lpBits,&bmiOut.bmiHeader,pBitmapBits); if (ICERR_OK != err){ _RPT4(_CRT_WARN,_T("ICDecompress failed. frame %d,%d,%d:%d\n"),lCurrent,m_lVidWidth,m_lVidHeight,err); } } delete lpBits; if (i <= ++lCurrent) break; } }else{ lCurrent = i; } lSize = sizeof(BITMAPINFOHEADER); AVIStreamReadFormat(m_pVideoStream, lCurrent, &bih, &lSize); lpBits = new BYTE[bih.biSizeImage]; AVIStreamRead(m_pVideoStream, lCurrent, 1, lpBits, bih.biSizeImage, NULL, NULL); if (hic != NULL){ DWORD err; err = ICDecompress(hic,0,&bih,lpBits,&bmiOut.bmiHeader,pBitmapBits); if (ICERR_OK != err){ _RPT4(_CRT_WARN,_T("ICDecompress failed. frame %d,%d,%d:%d\n"),lCurrent,m_lVidWidth,m_lVidHeight,err); } } delete lpBits; // テクスチャへの転送を行う UINT uiToRender = 0; if (m_iRenderableTexture >= 0){ uiToRender = m_iRenderableTexture; uiToRender++; uiToRender %= kNumTextures; } // テクスチャをロック D3DLOCKED_RECT d3dlr; if (FAILED(m_ppTextures[uiToRender]->LockRect(0, &d3dlr, 0, 0))){ hr = E_FAIL; continue; } // テクスチャバッファとそのY方向のピッチを取得する BYTE *pTxtBuffer; // Bitmap バッファ, texture バッファ LONG lTxtPitch; // テクスチャのピッチ pTxtBuffer = static_cast<byte *>(d3dlr.pBits); lTxtPitch = d3dlr.Pitch; // テクスチャのピッチ // テクスチャに転送! // 画像のコピー if (m_TextureFormat == D3DFMT_A8R8G8B8) { _asm{ mov edi, pTxtBuffer ; mov esi, pBitmapBits ; mov ebx, this; mov ecx, [ebx].m_lVidHeight; mov eax, [ebx].m_lVidPitch; mov ebx, eax; transfer_loop_y1: push edi; push esi; push ecx; push ebx; mov ebx, this; mov ecx, [ebx].m_lVidWidth; mov dl, 0xff; transfer_loop1: mov al, byte ptr[esi]; mov byte ptr[edi], al; mov al, byte ptr[esi+1]; mov byte ptr[edi+1], al; mov al, byte ptr[esi+2]; mov byte ptr[edi+2], al; mov byte ptr[edi+3], dl; add esi, 3; add edi, 4; dec ecx; jnz transfer_loop1; pop ebx; pop ecx; pop esi; pop edi; add esi, ebx; mov edx, lTxtPitch; add edi, edx dec ecx; jnz transfer_loop_y1; } }else if (m_TextureFormat == D3DFMT_A1R5G5B5) { _asm{ mov edi, pTxtBuffer ; mov esi, pBitmapBits ; mov ebx, this; mov ecx, [ebx].m_lVidHeight; mov eax, [ebx].m_lVidPitch; mov ebx, eax; transfer_loop_y2: push edi; push esi; push ecx; push ebx; mov ebx, this; mov ecx, [ebx].m_lVidWidth; transfer_loop2: mov ah, 1 ; mov al, byte ptr[esi+2] ; shl ax, 5 ; mov al, byte ptr[esi+1] ; shl ax, 2 ; and al, 0xe0 ; mov dl, byte ptr[esi] ; shr dl, 3 ; add al, dl ; mov word ptr[edi], ax ; add esi, 3; add edi, 2; dec ecx; jnz transfer_loop2; pop ebx; pop ecx; pop esi; pop edi; mov edx, lTxtPitch; add edi, edx add esi, ebx; dec ecx; jnz transfer_loop_y2; } } // テクスチャのアンロック if (FAILED(m_ppTextures[uiToRender]->UnlockRect(0))){ hr = E_FAIL; continue; } Lock(); m_iRenderableTexture = uiToRender; Unlock(); } frame_conversion_end: if (m_bTerminateThread) break; Yield(); } } if (hic != NULL){ ICDecompressEnd(hic); ICClose(hic); hic = NULL; } if (hDC) DeleteDC( hDC ); if (hbmBitmap) DeleteObject( hbmBitmap ); hDC = NULL; hbmBitmap = NULL; pBitmapBits = NULL; m_bThreadAlive = false; } static DWORD WINAPI ThreadProc(LPVOID lp) { CAVIVideoTexture *lpTmp = (CAVIVideoTexture*)lp; lpTmp->DoThread(); return 0; } void CAVIVideoTexture::Lock(){ EnterCriticalSection(&m_semaphore); } void CAVIVideoTexture::Unlock(){ LeaveCriticalSection(&m_semaphore); }
戻る