H264解码之DDraw显示YUV

头文件:

#pragma once
#include "ddraw.h"
#include <time.h>
#pragma  comment (lib, "ddraw.lib")
#pragma comment(lib, "dxguid.lib")
class display
{
public:
	display(void);
public:
	~display(void);
public:
	unsigned __int64 init(HWND hwnd);
	void uninit();
	unsigned __int64 inputsource(unsigned char * src, long nwidth, long nheight, long ntype, long nrate, unsigned __int64 npts);
	static BOOL WINAPI DDEnumCallBack( GUID *pguid, LPTSTR pszdesc, LPTSTR pszdevicename, LPVOID pcontext, HMONITOR hmonior );
	unsigned __int64 createoffscreen(LPDIRECTDRAWSURFACE7 * offscreen, DDSURFACEDESC2 * ddsd, long nwidth, long nheight, long ntype);
	unsigned __int64 createddsd(DDSURFACEDESC2 * ddsd, long nwidth, long nheight, long ntype);
	unsigned __int64 wait_ctrl(unsigned __int64 npts);
	void refrush();
	void reinit();

private:
	struct MONITOR_INFO
	{
		LPDIRECTDRAW7 lpDD;				// DirectDraw 对象指针
		HMONITOR hMon;	
	};
	LPDIRECTDRAW7 m_lpddraw;						// DirectDraw 对象指针
	LPDIRECTDRAWSURFACE7 m_lpddsprimary;			// DirectDraw 主表面指针
	LPDIRECTDRAWSURFACE7 m_lpddsoffscr;				// DirectDraw 离屏表面指针
	LPDIRECTDRAWSURFACE7 m_lpddsoffscr2;			// DirectDraw 离屏表面指针
	LPDIRECTDRAWCLIPPER m_lpclipper;
	HWND m_hwnd;
	DDSURFACEDESC2 m_ddsd;
	bool m_init;
	long m_lastwidth;
	long m_lastheight;

	RECT m_rctDest;			// 目标区域
	RECT m_rctSour;			// 源区域
	RECT m_rctDestLast;
	DDBLTFX  m_ddbltfx;
};

cpp文件:

#include "StdAfx.h"
#include "display.h"

display::display(void)
{
	m_lpddraw = NULL;
	m_lpddsprimary = NULL;
	m_lpddsoffscr = NULL;
	m_lpddsoffscr2 = NULL;
	m_lpclipper = NULL;
	m_init = false;
	memset(&m_ddsd, 0, sizeof(m_ddsd));
	m_lastwidth = 0;
	m_lastheight = 0;
}

display::~display(void)
{
}

BOOL WINAPI display::DDEnumCallBack( GUID *pguid, LPTSTR pszdesc, LPTSTR pszdevicename, LPVOID pcontext, HMONITOR hmonior )
{
	LPDIRECTDRAW7            lpDD = NULL;				// DirectDraw 对象指针
	MONITOR_INFO *pthis = ( MONITOR_INFO *)pcontext;
	if ( !pthis )
	{
		return FALSE;
	}
	if ( pthis->hMon == hmonior )
	{
        OutputDebugStringA("创建DirectDraw begin\r\n");
		if (DirectDrawCreateEx(pguid, (void**)&lpDD, IID_IDirectDraw7, NULL) != DD_OK)
		{
			OutputDebugStringA("创建lpDD error!\r\n");
		}
		pthis->lpDD = lpDD;
		lpDD = NULL;
	}

    OutputDebugStringA("创建DirectDraw end\r\n");
	// 创建DirectDraw对象

	return TRUE;
}

void display::reinit()
{
	uninit();
	init(m_hwnd);
}

unsigned __int64 display::init(HWND hwnd)
{
	if (m_init)
	{
		return 0;
	}
	m_hwnd = hwnd;
	MONITOR_INFO mi_lpdd;
	mi_lpdd.hMon = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
	// 枚举监视器并创建DirectDraw对象
	DirectDrawEnumerateExA( display::DDEnumCallBack, 
		&mi_lpdd,
		DDENUM_ATTACHEDSECONDARYDEVICES | 
		DDENUM_DETACHEDSECONDARYDEVICES | 
		DDENUM_NONDISPLAYDEVICES
		);
	m_lpddraw = mi_lpdd.lpDD;
	if(m_lpddraw == NULL)
	{
		if (DirectDrawCreateEx(NULL, (VOID**)&m_lpddraw,IID_IDirectDraw7,NULL) != DD_OK) 
		{
			OutputDebugStringA("display::init 创建DirectDraw NOK\r\n");
		}
		if (!m_lpddraw)
		{
			OutputDebugStringA("display::init 2创建DirectDraw NOK\r\n");
			return -1;
		}
	}
	if (m_lpddraw->SetCooperativeLevel(/*pcd->hRenderWnd*/NULL,
		DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES | DDSCL_ALLOWREBOOT ) != DD_OK)
	{
		OutputDebugStringA("display::init 创建lpDDxiezuo error!\r\n");
		if (m_lpddraw)
		{
			m_lpddraw->Release();
			m_lpddraw = NULL;
		}
		return -1;
	}
	// 创建主表面
	DDSURFACEDESC2			ddsd;				// DirectDraw 表面描述
	ZeroMemory(&ddsd, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS;// | DDSD_BACKBUFFERCOUNT;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	//ddsd.dwBackBufferCount = 1;
	if (m_lpddraw->CreateSurface(&ddsd, &m_lpddsprimary, NULL) != DD_OK)
	{
		OutputDebugStringA("display::init 创建m_lpddsprimary error!\r\n");
		if (m_lpddraw)
		{
			m_lpddraw->Release();
			m_lpddraw = NULL;
		}
		return -1;
	}
	if(m_lpddraw->CreateClipper(0, &m_lpclipper, NULL) != DD_OK)
	{
		if (m_lpddraw)
		{
			m_lpddraw->Release();
			m_lpddraw = NULL;
		}
		OutputDebugStringA("display::init 创建m_lpclipper error!\r\n");
		return -1;
	}

	m_lpclipper->SetHWnd(0, hwnd);
	m_lpddsprimary->SetClipper(m_lpclipper);
	m_init = true;
	return 0;
}

void display::uninit()
{
	if (m_lpddsoffscr)
	{
		m_lpddsoffscr->Release();
		m_lpddsoffscr = NULL;
	}
	if (m_lpddsoffscr2)
	{
		m_lpddsoffscr2->Release();
		m_lpddsoffscr2 = NULL;
	}
	if (m_lpddsprimary)
	{
		m_lpddsprimary->Release();
		m_lpddsprimary = NULL;
	}
	if (m_lpclipper)
	{
		m_lpclipper->Release();
		m_lpclipper = NULL;
	}
	if (m_lpddraw)
	{
		m_lpddraw->Release();
		m_lpddraw = NULL;
	}
	m_init = false;
}

unsigned __int64 display::createddsd(DDSURFACEDESC2 * ddsd, long nwidth, long nheight, long ntype)
{
	ddsd->dwSize = sizeof(*ddsd);
	ddsd->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY ; //DDSCAPS_OVERLAY DDSCAPS_OFFSCREENPLAIN;
	ddsd->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;// | DDSD_PITCH | DDSD_LPSURFACE;
	ddsd->dwWidth = nwidth;
	ddsd->dwHeight = nheight;
	ddsd->ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
	ddsd->ddpfPixelFormat.dwFlags = DDPF_FOURCC;
	if ( ntype == 2)
	{
		ddsd->ddpfPixelFormat.dwFourCC = MAKEFOURCC('R','G','B',' ');
		ddsd->ddpfPixelFormat.dwFlags |= DDPF_RGB;
		ddsd->ddpfPixelFormat.dwRGBBitCount = 32;
	}
	else if ( ntype == 3)
	{
		ddsd->ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','V','1','2');
		ddsd->ddpfPixelFormat.dwFlags |= DDPF_YUV;
		ddsd->ddpfPixelFormat.dwYUVBitCount = 12;
	}
	else if ( ntype == 4)
	{
		ddsd->ddpfPixelFormat.dwFourCC = MAKEFOURCC('U','Y','V','Y');
		ddsd->ddpfPixelFormat.dwFlags |= DDPF_YUV;
		ddsd->ddpfPixelFormat.dwYUVBitCount = 16;
	}
	else if ( ntype == 5)
	{
		ddsd->ddpfPixelFormat.dwFourCC = MAKEFOURCC(/*'I','4','2','0'*/'Y','V','1','2');
		ddsd->ddpfPixelFormat.dwFlags |= DDPF_YUV;
		ddsd->ddpfPixelFormat.dwYUVBitCount = 12;
	}
	else if ( ntype == 6)
	{
		ddsd->ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','U','Y','2'); //or YUYV. the same format.
		ddsd->ddpfPixelFormat.dwFlags |= DDPF_YUV;
		ddsd->ddpfPixelFormat.dwYUVBitCount = 16;
	}
	else
	{
		OutputDebugStringA("************LOG_RTM, unsupported pixel format: %d, pcd->m_bdInRender.nType\r\n");
		return -1;
	}
	return 0;
}

void display::refrush()
{
	//m_lpddsprimary->Blt(&m_rctDest, m_lpddsoffscr, &m_rctSour, DDBLT_WAIT, &m_ddbltfx); 
}

unsigned __int64 display::createoffscreen(LPDIRECTDRAWSURFACE7 * offscreen, DDSURFACEDESC2 * ddsd, long nwidth, long nheight, long ntype)
{
	unsigned __int64 nerror = 0;
	//DDERR_UNSUPPORTEDMODE;
	HRESULT result = m_lpddraw->CreateSurface(ddsd, offscreen, NULL);
	if(FAILED (result))
	{
		if (result == DDERR_NODIRECTDRAWHW)
		{
			reinit();
		}
		return -1;
	}
	return 0;
}

unsigned __int64 display::wait_ctrl(unsigned __int64 npts)
{
	return 0;
}

unsigned __int64 display::inputsource(unsigned char * src, long nwidth, long nheight, long ntype, long nrate, unsigned __int64 npts)
{
	if (!m_init)
	{
		return -1;
	}
	unsigned __int64 nerror = 0;
	if (!m_lpddsoffscr || m_lastwidth != nwidth || m_lastheight != nheight)
	{
		if (m_lpddsoffscr)
		{
			m_lpddsoffscr->Release();
			m_lpddsoffscr = NULL;
		}
		nerror = createddsd(&m_ddsd, nwidth, nheight, ntype);
		if (nerror)
		{
			OutputDebugStringA("display::inputsource createddsd error[m_lpddsoffscr equ null]\r\n");
			return -1;
		}
		nerror = createoffscreen(&m_lpddsoffscr, &m_ddsd, nwidth, nheight, ntype);
		if (nerror)
		{
			OutputDebugStringA("display::inputsource createoffscreen error[m_lpddsoffscr equ null]\r\n");
			return -1;
		}
	}
	if (!m_lpddsoffscr)
	{
		OutputDebugStringA("display::inputsource error[m_lpddsoffscr equ null]\r\n");
		return -1;
	}
	HRESULT hr = m_lpddsoffscr->Lock(NULL,&m_ddsd, DDLOCK_WAIT |DDLOCK_WRITEONLY,NULL);
	if (hr == DDERR_SURFACELOST) 
	{
        OutputDebugStringA("DDERR_SURFACELOST DDERR_SURFACELOST DDERR_SURFACELOST...1\n");
		hr = m_lpddsoffscr->Restore(); 
		hr = (hr != DD_OK)? hr : m_lpddsoffscr->Lock(NULL,&m_ddsd,DDLOCK_WAIT | DDLOCK_WRITEONLY,NULL); 
	}
	if (hr != DD_OK)
	{
		OutputDebugStringA("display::inputsource  Lock error\r\n");
		return -1;
	}

	m_lastwidth = nwidth;
	m_lastheight = nheight;
	LPBYTE lpSurf = (LPBYTE)m_ddsd.lpSurface;
	LPBYTE lpSurfV = lpSurf + m_ddsd.dwHeight*m_ddsd.lPitch;
	LPBYTE lpSurfU = lpSurfV + (m_ddsd.dwHeight*m_ddsd.lPitch>>2);
	if (3 == ntype || 5 == ntype)
	{
		LPBYTE lpY = src;
		LPBYTE lpU;
		LPBYTE lpV;
		if (3 == ntype)
		{
			lpV = lpY + nwidth * nheight;
			lpU = lpV + (nwidth * nheight>>2);
		}
		else
		{
			lpU = lpY + nwidth * nheight;
			lpV = lpU + (nwidth * nheight>>2);
		}
		// 填充离屏表面
		long lddsdHeightHalf = m_ddsd.dwHeight>>1;
		long lddsdlPitchHalf = m_ddsd.lPitch>>1; 
		long lWidhtHalf = nwidth>>1;
		for(unsigned int i = 0; i < m_ddsd.dwHeight; i++)
		{
			memcpy(lpSurf, lpY, nwidth);
			lpY += nwidth;
			lpSurf += m_ddsd.lPitch;

			if (i < lddsdHeightHalf)
			{
				memcpy(lpSurfU, lpU, lWidhtHalf);				
				lpU += lWidhtHalf;
				lpSurfU += lddsdlPitchHalf;

				memcpy(lpSurfV, lpV, lWidhtHalf);
				lpV += lWidhtHalf;
				lpSurfV += lddsdlPitchHalf;				
			}
		}
	}
	
	m_lpddsoffscr->Unlock(NULL);

//  	RECT rctDest;
//  	GetClientRect(m_hwnd, &rctDest);
//  	ClientToScreen(m_hwnd,(LPPOINT)&rctDest.left);
//  	ClientToScreen(m_hwnd,(LPPOINT)&rctDest.right);
//  	if (rctDest.left != m_rctDestLast.left || rctDest.top != m_rctDestLast.top 
//  		|| rctDest.right != m_rctDestLast.right || rctDest.bottom != m_rctDestLast.bottom)
	{
		//m_rctDestLast = rctDest;
		m_rctSour.left = 0;
		m_rctSour.top = 0;
		m_rctSour.right = m_ddsd.dwWidth;
		m_rctSour.bottom = m_ddsd.dwHeight;

		GetClientRect(m_hwnd, &m_rctDest);				
		MONITORINFO mi;
		memset(&mi, 0, sizeof(MONITORINFO));
		mi.cbSize = sizeof(MONITORINFO);
		HMONITOR hmon = ::MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
		if (!hmon)
		{
			OutputDebugStringA("display::inputsource MonitorFromWindow error[hmon equ null]\r\n");
			return -1;
		}
		::GetMonitorInfo(hmon, &mi);
		m_rctDest.left -= mi.rcMonitor.left;
		m_rctDest.right -= mi.rcMonitor.left;
		m_rctDest.top -= mi.rcMonitor.top;
		m_rctDest.bottom -= mi.rcMonitor.top;
		ClientToScreen(m_hwnd, (LPPOINT)&m_rctDest.left);
		ClientToScreen(m_hwnd, (LPPOINT)&m_rctDest.right);
		
		memset(&m_ddbltfx, 0, sizeof(m_ddbltfx));
		m_ddbltfx.dwSize = sizeof(m_ddbltfx);
		m_ddbltfx.dwROP = SRCCOPY;
	}
		
	// Blt到主表面上
	HRESULT hr2 = m_lpddsprimary->Blt(&m_rctDest, m_lpddsoffscr, &m_rctSour, DDBLT_WAIT, &m_ddbltfx); 
	if (hr2 == DDERR_SURFACELOST)
	{
        OutputDebugStringA("DDERR_SURFACELOST DDERR_SURFACELOST DDERR_SURFACELOST...\n");
		hr2 = m_lpddsprimary->Restore();
	}
	if (hr2 != DD_OK)
	{
		OutputDebugStringA("display::inputsource Blt error\r\n");
		return -1;
	}
	return 0;
}

 

posted @ 2018-07-23 14:46  SunkingYang  阅读(290)  评论(0编辑  收藏  举报