AVIファイル内のビデオストリームを、Direct3D にて表示

プロジェクトダウンロード(VC++2005)

※Direct3D の初期化・終了には、D3DQuickLib を使用しています。

【プログラム主要部分1(AVITextue.cpp)】


#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;
   }
}

 

 AVIFile ライブラリを用いて解凍した画像を、Direct3D を使って表示させます。

   Direct3D での表示には、リスト2・3のCAVIVideoTexture というクラスの機能を使っています。

 

【プログラム主要部分2・クラスCAVIVideoTextureの宣言(AVIVideoTexture.h)】


//-----------------------------------------------------------------------------
// 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

 

【プログラム主要部分3・クラスCPCMStreamForAVIStreamの実装(PCMStreamForAVIStream.cpp)】


//
//    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);
}

 

戻る