📄 videorender.cpp
字号:
// DDSurface.cpp: implementation of the CVideoRender class.
//
//////////////////////////////////////////////////////////////////////
#include <windows.h>
//#include "HPlayer.h"
#include "VideoRender.h"
#include <WinUser.h>
#include "Log.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define RELEASE(x) { if (x) x->Release(); x = NULL; }
//##ModelId=4753B7E80282
CVideoRender::CVideoRender()
{
m_pDD = NULL;
m_pDDSPrimary = NULL;
m_pDrawSurface = NULL;
m_pClipper = NULL;
m_pVideoStream = NULL;
m_nState = THREAD_STOP;
m_nCurPlayTime = 0;
m_nLastFrameTime = 0;
m_bSyncCtrl = FALSE;
m_hhkLowLevelKybd = NULL;
m_pBackFrame = NULL;
m_pWriteFrameCB = NULL;
}
//##ModelId=4753B7E80290
CVideoRender::~CVideoRender()
{
}
//##ModelId=4753B7E80292
int CVideoRender::CreateVideoRender(HWND hWnd, TWriteFrameCB cb, double dFps, int nWidth, int nHeight)
{
m_nWidth = nWidth;
m_nHeight = nHeight;
m_dFps = dFps;
m_pWriteFrameCB = cb;
m_nDisplayTime = (int)(1000.0/(m_dFps));
memset(&m_BitmapInfo, 0, sizeof(BITMAPINFO));
m_BitmapInfo.bmiHeader.biBitCount = 24;
m_BitmapInfo.bmiHeader.biHeight = nHeight;
m_BitmapInfo.bmiHeader.biPlanes = 1;
m_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_BitmapInfo.bmiHeader.biWidth = nWidth;
m_BitmapInfo.bmiHeader.biCompression = BI_RGB;
m_hStop = CreateEvent(NULL, FALSE, FALSE, NULL);
if( !m_hStop )
return -1;
m_hPause = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hWait = CreateEvent(NULL, FALSE, FALSE, NULL);
if( !m_hPause || !m_hWait )
return -1;
m_hWnd = hWnd;
m_nState = THREAD_STOP;
m_nLastFrameTime = 0;
m_nCurPlayTime = 0;
m_bSyncCtrl = FALSE;
m_pBackFrame = (BYTE *)malloc(nWidth * nHeight * 3);
memset(m_pBackFrame, 0, nWidth * nHeight * 3);
LogMsg(LOG_INFO, HCLN, "Create VideoRender!");
if( !m_pWriteFrameCB )
return InitDirectDraw(hWnd, nWidth, nHeight);
return TRUE;
}
//##ModelId=4753B7E802A0
int CVideoRender::DestroyVideoRender()
{
if( m_nState == THREAD_PAUSE )
{
SetEvent(m_hPause);
}
if( GetHandle() )
{
SetEvent(m_hStop);
WaitForClosure(INFINITE);
Close();
CloseHandle(m_hStop);
m_nState = THREAD_STOP;
}
CloseHandle(m_hPause);
CloseHandle(m_hWait);
DestroyDDraw();
if( m_pBackFrame )
free(m_pBackFrame);
LogMsg(LOG_INFO, HCLN, "Destroy VideoRender!");
return 0;
}
//##ModelId=4753B7E802AF
int CVideoRender::InitDirectDraw(HWND hWnd, int nWidth, int nHeight)
{
DDSURFACEDESC2 ddsd;
HRESULT nRet;
LPDIRECTDRAW7 pDD;
HDC hDC;
hDC = GetDC(m_hWnd);
m_BPP = GetDeviceCaps(hDC, PLANES) * GetDeviceCaps(hDC, BITSPIXEL);
ReleaseDC(m_hWnd, hDC);
// Create the main DirectDraw object.
nRet = DirectDrawCreateEx(NULL, (VOID**)&pDD, IID_IDirectDraw7, NULL);
if( nRet != DD_OK )
return -1;
// Fetch DirectDraw7 interface
nRet = pDD->QueryInterface(IID_IDirectDraw7, (LPVOID*)&m_pDD);
if(nRet != DD_OK)
{
// if failed, quit the app
return FALSE;
}
pDD->Release();
// Get exclusive mode.
nRet = m_pDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL);
if( nRet != DD_OK )
return -2;
// Prepare to create the primary surface by initializing
// the fields of a DDSURFACEDESC2 structure.
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
// Create the primary surface.
nRet = m_pDD->CreateSurface(&ddsd, &m_pDDSPrimary, NULL);
if( nRet != DD_OK )
return -1;
// Create the window clipper
nRet = m_pDD->CreateClipper(0, &m_pClipper, NULL);
if(nRet != DD_OK)
return -1;
nRet = m_pClipper->SetHWnd(0, hWnd);
if(nRet != DD_OK)
return -1;
nRet = m_pDDSPrimary->SetClipper(m_pClipper);
if(nRet != DD_OK)
return -1;
//Draw surface create
ZeroMemory(&m_DDSD, sizeof(m_DDSD));
m_DDSD.dwSize = sizeof(m_DDSD);
m_DDSD.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
m_DDSD.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
m_DDSD.dwWidth = nWidth;
m_DDSD.dwHeight = nHeight;
nRet = m_pDD->CreateSurface(&m_DDSD, &m_pDrawSurface, NULL);
if(nRet != DD_OK)
{
return -1;
}
LogMsg(LOG_INFO, HCLN, "Initialize DirectDraw!");
return 0;
}
//##ModelId=4753B7E802FE
void CVideoRender::DestroyDDraw()
{
RELEASE(m_pDDSPrimary);
RELEASE(m_pDrawSurface);
RELEASE(m_pClipper);
RELEASE(m_pDD);
LogMsg(LOG_INFO, HCLN, "Destroy DirectDraw!");
}
BOOL CVideoRender::Play()
{
if( m_nState == THREAD_STOP )
{
if( !Create(ThreadEntry, this) )
return FALSE;
m_nState = THREAD_RUNNING;
}
else if( m_nState == THREAD_PAUSE )
{
if( GetThreadState() != STILL_ACTIVE )
return FALSE;
SetEvent(m_hPause);
}
return TRUE;
}
BOOL CVideoRender::Stop()
{
if( m_nState == THREAD_RUNNING )
{
SetEvent(m_hPause);
WaitForSingleObject(m_hWait, INFINITE);
}
return TRUE;
}
void CVideoRender::SetSpeed()
{
m_nDisplayTime = (int)(1000.0/(m_dFps));
}
HRESULT CVideoRender::Blt(LPRECT pDestRect, LPRECT pSrcRect, CONST VOID *lpBits, CONST BITMAPINFO *lpBitsInfo)
{
HDC hDC;
if( !m_pDrawSurface )
return S_FALSE;
m_pDrawSurface->GetDC(&hDC);
::SetStretchBltMode(hDC, COLORONCOLOR);
if ((RECTWIDTH(pDestRect) == RECTWIDTH(pSrcRect)) &&
(RECTHEIGHT(pDestRect) == RECTHEIGHT(pSrcRect)))
{
::SetDIBitsToDevice(hDC, // hDC
pDestRect->left, // DestX
pDestRect->top, // DestY
RECTWIDTH(pDestRect), // nDestWidth
RECTHEIGHT(pDestRect), // nDestHeight
pSrcRect->left, // SrcX
pSrcRect->top, // SrcY
pSrcRect->top, // nStartScan
RECTHEIGHT(pSrcRect), // nNumScans
lpBits, // lpBits
lpBitsInfo, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
}
else
{
::StretchDIBits(hDC,
pDestRect->left,
pDestRect->top,
RECTWIDTH(pDestRect),
RECTHEIGHT(pDestRect),
pSrcRect->left,
pSrcRect->top,
RECTWIDTH(pSrcRect),
RECTHEIGHT(pSrcRect),
lpBits,
lpBitsInfo,
DIB_RGB_COLORS,
SRCCOPY);
}
m_pDrawSurface->ReleaseDC(hDC);
return 0;
}
BOOL CVideoRender::Draw(HWND hWnd)
{
HRESULT hr = S_OK;
BYTE *lpBits;
RECT DrawRect;
RECT DstRect, SrcRect;
UINT nSize;
UINT nTime;
double rate = (double)m_nHeight / (double)m_nWidth;
DWORD dwTime;
if( !m_pVideoStream )
return FALSE;
lpBits = (BYTE *)m_pVideoStream->Pop(&nSize, &nTime);
if( !lpBits )
return FALSE;
dwTime = (DWORD)nTime;
memcpy(m_pBackFrame, lpBits, nSize);
if( nTime > 0 )
m_nLastFrameTime = nTime;
//if callback function is setting, call callback function
if( m_pWriteFrameCB )
{
(*m_pWriteFrameCB)(lpBits, dwTime);
return TRUE;
}
if( m_pDD == NULL )
return FALSE;
GetWindowRect(hWnd, &DrawRect);
SrcRect.left = SrcRect.top = DstRect.left = DstRect.top = 0;
SrcRect.right = DstRect.right = m_nWidth;
SrcRect.bottom = DstRect.bottom = m_nHeight;
//LogMsg(LOG_DEBUG, HCLN, "Draw one frame!");
Restore();
//Draw video to DrawSurface
Blt(&DstRect, &SrcRect, lpBits, &m_BitmapInfo);
//Draw text to DrawSurface
// get size of surface.
LONG nRealHeight = DrawRect.bottom - DrawRect.top;
LONG nCalHeight = (LONG)(rate * (DrawRect.right - DrawRect.left));
// Draw Text
hr = m_pDDSPrimary->Blt(&DrawRect, m_pDrawSurface, &SrcRect, DDBLTFAST_SRCCOLORKEY, NULL);
// hr = m_pDDSPrimary->Blt(&DrawRect, m_pDrawSurface, &SrcRect, DDBLTFAST_DONOTWAIT, NULL);
if(hr == DDERR_SURFACELOST)
Restore();
return TRUE;
}
void CVideoRender::OnPaint()
{
DDSURFACEDESC2 ddsd;
RECT DrawRect;
RECT DstRect, SrcRect;
HRESULT hr;
HWND hWnd;
double rate = (double)m_nHeight / (double)m_nWidth;
if( m_pDD == NULL || !m_pDDSPrimary || !m_pDrawSurface )
return;
hWnd = m_hWnd;
GetWindowRect(hWnd, &DrawRect);
SrcRect.left = SrcRect.top = DstRect.left = DstRect.top = 0;
SrcRect.right = DstRect.right = m_nWidth;
SrcRect.bottom = DstRect.bottom = m_nHeight;
//LogMsg(LOG_DEBUG, HCLN, "Draw one frame!");
Restore();
Blt(&DstRect, &SrcRect, m_pBackFrame, &m_BitmapInfo);
// get size of surface.
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
m_pDDSPrimary->GetSurfaceDesc(&ddsd);
LONG nRealHeight = DrawRect.bottom - DrawRect.top;
LONG nCalHeight = (LONG)(rate * (DrawRect.right - DrawRect.left));
hr = m_pDDSPrimary->Blt(&DrawRect, m_pDrawSurface, &SrcRect, DDBLTFAST_SRCCOLORKEY, NULL);
if(hr == DDERR_SURFACELOST)
Restore();
}
void CVideoRender::Restore()
{
HRESULT hr = S_OK;
if(m_pDDSPrimary != NULL)
{
if(m_pDDSPrimary->IsLost() == DDERR_SURFACELOST)
hr = m_pDDSPrimary->Restore();
}
if( m_pDrawSurface != NULL)
{
if(m_pDrawSurface->IsLost() == DDERR_SURFACELOST)
hr = m_pDrawSurface->Restore();
}
if( hr == DDERR_WRONGMODE )
{
DestroyDDraw();
InitDirectDraw(m_hWnd, m_nWidth, m_nHeight);
}
}
UINT WINAPI CVideoRender::ThreadEntry(void *lpParam)
{
((CVideoRender *)lpParam)->RunVideoRender();
return 0;
}
void CVideoRender::RunVideoRender()
{
HANDLE hEvent[2];
DWORD nRet;
DWORD dwWorkTime;
while(TRUE)
{
dwWorkTime = GetTickCount();
hEvent[0] = m_hStop;
hEvent[1] = m_hPause;
nRet = WaitForMultipleObjects(2, hEvent, FALSE, 0);
if( nRet == WAIT_OBJECT_0 )
break;
else if( nRet == WAIT_OBJECT_0 + 1 )
{
SetEvent(m_hWait);
m_nState = THREAD_PAUSE;
WaitForSingleObject(m_hPause, INFINITE);
m_nState = THREAD_RUNNING;
continue;
}
BOOL bRet;
bRet = Draw(m_hWnd);
if( !bRet )
{
Sleep(30);
continue;
}
//if synchronization is set
if( m_bSyncCtrl )
{
//video ahead of audio
if( m_nCurPlayTime < m_nLastFrameTime )
{
m_nDeltaTime = m_nCurPlayTime - m_nLastFrameTime;
if( m_nLastFrameTime - m_nCurPlayTime > 5000 )//肥寇贸府
{
LogMsg(LOG_ERR, HCLN, "SyncCtrl:After Sleep audio : %d, video : %d, delta : %d",
m_nCurPlayTime, m_nLastFrameTime, m_nDeltaTime);
}
else
{
//updatae video and audio synchronization
Sleep(m_nLastFrameTime - m_nCurPlayTime);
m_bSyncCtrl = FALSE;
continue;
}
}
else if( m_nCurPlayTime > m_nLastFrameTime )
{
m_nDeltaTime = m_nCurPlayTime - m_nLastFrameTime;
if( m_nCurPlayTime - m_nLastFrameTime > 5000 )//肥寇贸府
{
LogMsg(LOG_ERR, HCLN, "SyncCtrl:Before Sleep audio : %d, video : %d, delta : %d",
m_nCurPlayTime, m_nLastFrameTime, m_nDeltaTime);
}
else
{
//updatae video and audio synchronization
continue;
}
}
//set to end updating synchronization
m_bSyncCtrl = FALSE;
}
//delay video frame display time
dwWorkTime = GetTickCount() - dwWorkTime;
if( dwWorkTime < m_nDisplayTime )
Sleep(m_nDisplayTime - dwWorkTime);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -