//---------------------------------------------------------------------------


#pragma hdrstop

#include "DirectShowClass.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#define TIME_UNITS (10000000)  // 10^ 7

__fastcall TDirectShow::TDirectShow()
{
    //TODO: Add your source code here
    DllLoad();

}

__fastcall TDirectShow::~TDirectShow()
{
    //TODO: Add your source code here
    DllFree();
}

bool __fastcall TDirectShow::New(HWND hWnd)
{
    if (m_hDLL && m_New)
        return m_New(hWnd);
    return false;
}

void __fastcall TDirectShow::Delete(void)
{
    if (m_hDLL && m_Delete)
        m_Delete();
}

void __fastcall TDirectShow::Pause(void)
{
    if (m_hDLL && m_Pause)
        m_Pause();
}

void __fastcall TDirectShow::Stop(void)
{
    if (m_hDLL && m_Stop)
        m_Stop();
}

bool __fastcall TDirectShow::OpenFile(char * pFilename, int *pnVideoWidth, int *pnVideoHeight)
{
    if (m_hDLL && m_OpenFile)
        return m_OpenFile(pFilename, pnVideoWidth, pnVideoHeight);
    return false;
}

void __fastcall TDirectShow::CloseFile(void)
{
    if (m_hDLL && m_CloseFile)
        m_CloseFile();
}

bool __fastcall TDirectShow::SetDisplayRect(TRect rc){
    if (m_hDLL && m_SetDisplayRect)
        return m_SetDisplayRect(rc);
    return false;
}

void __fastcall TDirectShow::Repaint(void)
{
    if (m_hDLL && m_Repaint)
        m_Repaint();
}

bool __fastcall TDirectShow::DllLoad(void)
{
    //TODO: Add your source code here
    bool bSuccess = false;
    AnsiString strFile;
    strFile = ::ExtractFilePath(Application->ExeName) + "TERASIC_DX.DLL";
    m_hDLL = ::LoadLibrary(strFile.c_str());
    if (m_hDLL){
        m_New = (LPDX_New)::GetProcAddress(m_hDLL, "DX_New");
        m_Delete = (LPDX_Delete)::GetProcAddress(m_hDLL, "DX_Delete");
        m_OpenFile = (LPDX_OpenFile)::GetProcAddress(m_hDLL, "DX_OpenFile");
        m_CloseFile = (LPDX_CloseFile)::GetProcAddress(m_hDLL, "DX_CloseFile");
        m_Pause = (LPDX_Pause)::GetProcAddress(m_hDLL, "DX_Pause");
        m_Stop = (LPDX_Stop)::GetProcAddress(m_hDLL, "DX_Stop");
        m_Capture2File = (LPDX_Capture2File)::GetProcAddress(m_hDLL, "DX_Capture2File");
        m_CaptureImage = (LPDX_CaptureImage)::GetProcAddress(m_hDLL, "DX_CaptureImage");
        m_SetDisplayRect = (LPDX_SetDisplayRect)::GetProcAddress(m_hDLL, "DX_SetDisplayRect");
        m_Repaint = (LPDX_Repaint)::GetProcAddress(m_hDLL, "DX_Repaint");

        m_CanStep = (LPDX_CanStep)::GetProcAddress(m_hDLL, "DX_CanStep");
        m_Step = (LPDX_Step)::GetProcAddress(m_hDLL, "DX_Step");
        m_GetDuration = (LPDX_GetDuration)::GetProcAddress(m_hDLL, "DX_GetDuration");
        m_GetCurrentPosition = (LPDX_GetCurrentPosition)::GetProcAddress(m_hDLL, "DX_GetCurrentPosition");
        m_SeekToPosition = (LPDX_SeekToPosition)::GetProcAddress(m_hDLL, "DX_SeekToPosition");
        if (!m_New|| !m_Delete || !m_OpenFile || !m_CloseFile ||
            !m_Pause || !m_Stop || !m_Capture2File ||
            !m_CaptureImage || !m_SetDisplayRect || !m_Repaint ||
            !m_CanStep || !m_Step ||
            !m_GetDuration || !m_GetCurrentPosition || !m_SeekToPosition
            ){
            DllFree();
        }else{
            bSuccess = true;
        }
    }
    if (!bSuccess)
        MessageDlg("Failed to load DLL", mtError, TMsgDlgButtons() << mbOK, 0);


    return bSuccess;
}

void __fastcall TDirectShow::DllFree(void)
{
    //TODO: Add your source code here
    if (m_hDLL)
        ::FreeLibrary(m_hDLL);
    m_hDLL = NULL;
}

Graphics::TBitmap* __fastcall TDirectShow::CaptureImage(void){
    Graphics::TBitmap *pBitmap = NULL;
    if (m_hDLL && m_CaptureImage){
        LPBITMAPINFOHEADER pHeader;
       // DWORD dwStart = ::GetTickCount();
        pHeader = m_CaptureImage();  // it takes 1.8 second on my computer
       // DWORD dwTimeElapsed = ::GetTickCount() - dwStart;
        if (pHeader){
            int nBytePerLine;
            pBitmap = new Graphics::TBitmap;
            pBitmap->Width = pHeader->biWidth;
            pBitmap->Height = pHeader->biHeight;
            if (pHeader->biBitCount == 32){
                pBitmap->PixelFormat = pf32bit;
                nBytePerLine = pBitmap->Width * 4;
            }else if (pHeader->biBitCount == 24){
                pBitmap->PixelFormat = pf24bit;
                nBytePerLine = pBitmap->Width * 3;
            }
            BYTE *pSrc = (BYTE *)pHeader + sizeof(BITMAPINFOHEADER);
            for(int y=0;y<pBitmap->Height;y++){
                BYTE *pDes = (BYTE *)pBitmap->ScanLine[pBitmap->Height-y-1];
                memcpy(pDes, pSrc, nBytePerLine);
                pSrc += nBytePerLine;
            }
           // pBitmap->SaveToFile("test.bmp");
           // delete pBitmap;
           // free resource
           ::GlobalFree(pHeader);

        }
    }
    return pBitmap;
 //   if (m_hDLL && m_CaptureImage)
   //     return m_CaptureImage(pFilename);
//    return false;
}

bool __fastcall TDirectShow::Capture2File(char *pFilename){
    if (m_hDLL && m_Capture2File)
        return m_Capture2File(pFilename);
    return false;
}


bool __fastcall TDirectShow::CanStep(void){
    if (m_hDLL && m_CanStep)
        return m_CanStep();
    return false;
}

bool __fastcall TDirectShow::Step(int nFrameToStep){
    if (m_hDLL && m_Step)
        return m_Step(nFrameToStep);
    return false;
}

DWORD __fastcall TDirectShow::GetDuration(void){
    DWORD dwPosition = 0;
    if (m_hDLL && m_GetDuration)
        dwPosition =  (DWORD)(m_GetDuration()/TIME_UNITS);
    return dwPosition;
}

DWORD __fastcall TDirectShow::GetCurrentPosition(void){
    DWORD dwPosition = 0;
    if (m_hDLL && m_GetCurrentPosition)
        dwPosition =  (DWORD)(m_GetCurrentPosition()/TIME_UNITS);
    return dwPosition;
}

BOOL __fastcall TDirectShow::SeekToPosition(DWORD dwPosition, bool bFlashData){
    if (m_hDLL && m_SeekToPosition){
        LONGLONG dwPos = dwPosition*TIME_UNITS;
        return m_SeekToPosition(dwPos, bFlashData);
    }
    return false;
}

