⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 videorender.cpp

📁 播放被H264_AAC所压缩的avi文件的播放器。
💻 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 + -