NVAPI抓屏传递给D3D11(D3D9到D3D11的数据传递)

功能描述:

1、用NVAPI 进行D3D9抓屏,抓屏后创建HANDLE进行数据交换
2、D3D11利用D3D9传入的HANDLE使用OpenSharedResource来打开句柄实现D3D9到D3D11的数据传递

需要的库:
1、NVAPI 安装完成后需要运行NVIDIA Capture SDK\bin目录下的NvFBCEnable.exe使能NVFBC抓屏
2、DXSDK_Jun10

步奏:

一、抓屏

1、初始化设备

//初始化D3d设备   deviceID为显示器ID
BOOL NVAPIGrab::InitD3D(unsigned int deviceID)
{
	HRESULT hr = S_OK;
	D3DPRESENT_PARAMETERS d3dpp;
	D3DADAPTER_IDENTIFIER9 adapterId;
	unsigned int iAdapter = NULL;

	//判断能否抓对应显示器的数据
	Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx);
	if (deviceID >= m_pD3DEx->GetAdapterCount())
	{
		printf("Error: (deviceID=%d) is not a valid GPU device. Headless video devices will not be detected.  <<\n\n", deviceID);
		return FALSE;
	}

	hr = m_pD3DEx->GetAdapterIdentifier(deviceID, 0, &adapterId);
	if (hr != S_OK)
	{
		printf("Error: (deviceID=%d) is not a valid GPU device. <<\n\n", deviceID);
		return FALSE;
	}

	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.Windowed = true;
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferWidth = m_width;
	d3dpp.BackBufferHeight = m_height;
	d3dpp.BackBufferCount = 1;
	d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
	DWORD dwBehaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING;
	hr = m_pD3DEx->CreateDeviceEx(deviceID, D3DDEVTYPE_HAL, NULL, dwBehaviorFlags, &d3dpp, NULL, &m_pD3D9Device);

	if (FAILED(hr))
	{
		OutputDebugString(L"CreateDevice Filed!");
		return FALSE;
	}

	return TRUE;
}

2、创建抓屏表面

//创建抓屏表面
BOOL NVAPIGrab::InitD3DSurfaces()
{
	HRESULT hr = E_FAIL;
	if (m_pD3D9Device)
	{
		hr = m_pD3D9Device->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pD3D9Surf, NULL);
		if (FAILED(hr))
		{
			fprintf(stderr, "Failed to create D3D9 surfaces for output. Error 0x%08x\n", hr);
			return FALSE;
		}
	}
	return TRUE;
}

3、初始化抓屏

BOOL NVAPIGrab::InitGrab(HANDLE & sharehand)
{
	DWORD maxDisplayWidth = -1, maxDisplayHeight = -1;

	NVFBC_TODX9VID_OUT_BUF NvFBC_OutBuf;

	//加载NvFBCLibary
	m_pNVFBCLib = new NvFBCLibrary();
	if (!m_pNVFBCLib->load())
	{
		fprintf(stderr, "Unable to load the NvFBC library.\n");
		return FALSE;
	}
	m_bNvFBCLibLoaded = true;

	if (!InitD3D(0))
	{
		fprintf(stderr, "Unable to create a D3D9Ex Device.\n");
		ReleaseGrab();
		return FALSE;
	}

	if (!InitD3DSurfaces())
	{
		fprintf(stderr, "Unable to create a D3D9Ex Device.\n");
		ReleaseGrab();
		return FALSE;
	}

	m_pNvFBCDX9 = (NvFBCToDx9Vid *)m_pNVFBCLib->create(NVFBC_TO_DX9_VID, &maxDisplayWidth, &maxDisplayHeight, 0, (void *)m_pD3D9Device);
	if (!m_pNvFBCDX9)
	{
		fprintf(stderr, "Failed to create an instance of NvFBCToDx9Vid.\n");
		ReleaseGrab();
		return FALSE;
	}

	NvFBC_OutBuf.pPrimary = m_pD3D9Surf;
	NVFBC_TODX9VID_SETUP_PARAMS DX9SetupParams = { 0 };
	DX9SetupParams.dwVersion = NVFBC_TODX9VID_SETUP_PARAMS_V2_VER;
	DX9SetupParams.bWithHWCursor = 0;
	DX9SetupParams.bStereoGrab = 0;
	DX9SetupParams.bDiffMap = 0;
	DX9SetupParams.ppBuffer = &NvFBC_OutBuf;
	DX9SetupParams.eMode = NVFBC_TODX9VID_ARGB;
	DX9SetupParams.dwNumBuffers = 1;

	//设置抓屏信息
	if (NVFBC_SUCCESS != m_pNvFBCDX9->NvFBCToDx9VidSetUp(&DX9SetupParams))
	{
		fprintf(stderr, "Failed when calling NvFBCDX9->NvFBCToDX9VidSetup()\n");
		ReleaseGrab();
		return FALSE;
	}

	//创建一个新的Texture用于D3D9传递数据给D3D11
	D3DSURFACE_DESC _desc;
	m_pD3D9Surf->GetDesc(&_desc);
	HRESULT hr = m_pD3D9Device->CreateTexture(m_width, m_height, 1, D3DUSAGE_RENDERTARGET, _desc.Format, D3DPOOL_DEFAULT, &m_pGrabResult, &m_hGrabShare);
	if (hr != D3D_OK)
		return FALSE;
	sharehand = m_hGrabShare;
	return TRUE;
}

4、抓一帧数据

BOOL NVAPIGrab::GrabOneFarme()
{
	NVFBC_TODX9VID_GRAB_FRAME_PARAMS fbcDX9GrabParams = { 0 };
	NvFBCFrameGrabInfo frameGrabInfo = { 0 };
	NVFBCRESULT fbcRes = NVFBC_SUCCESS;
	fbcDX9GrabParams.dwVersion = NVFBC_TODX9VID_GRAB_FRAME_PARAMS_VER;
	fbcDX9GrabParams.dwFlags = NVFBC_TODX9VID_NOWAIT;
	fbcDX9GrabParams.eGMode = NVFBC_TODX9VID_SOURCEMODE_SCALE;
	fbcDX9GrabParams.dwTargetWidth = m_width;
	fbcDX9GrabParams.dwTargetHeight = m_height;
	fbcDX9GrabParams.pNvFBCFrameGrabInfo = &frameGrabInfo;
	fbcRes = m_pNvFBCDX9->NvFBCToDx9VidGrabFrame(&fbcDX9GrabParams);
	if (fbcRes == NVFBC_SUCCESS)
	{
		//抓屏成功
		//将OffscreenSurface的数据给m_pGrabResult
		

		IDirect3DSurface9*  pGrabSurface = NULL;
		m_pGrabResult->GetSurfaceLevel(0, &pGrabSurface);
		m_pD3D9Device->StretchRect(m_pD3D9Surf, NULL, pGrabSurface, NULL, D3DTEXF_NONE);

		CString strIniFileB;
		strIniFileB.Format(_T(".\\%d.bmp"), cont);
		D3DXSaveTextureToFile(strIniFileB, D3DXIFF_BMP, m_pGrabResult, NULL);
		cont++;

		m_pD3D9Device->Present(0, 0, 0, 0);//提交一次避免数据没有刷新
		return TRUE;
	}
	else
	{
		return FALSE;
	}

	return TRUE;
}

二、D3D11

1、初始化

BOOL MyD3D11::InitD3D(IDXGIAdapter* pAdapter, HANDLE TargetHand)
{
	//创建D3D11
	UINT uCreateDeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

	D3D_FEATURE_LEVEL flvl[] = { D3D_FEATURE_LEVEL_11_0,D3D_FEATURE_LEVEL_11_0,D3D_FEATURE_LEVEL_10_0 };
	HRESULT hr = ::D3D11CreateDevice(
		pAdapter,
		D3D_DRIVER_TYPE_HARDWARE,
		NULL,
		uCreateDeviceFlags,
		flvl,
		sizeof(flvl) / sizeof(D3D_FEATURE_LEVEL),
		D3D11_SDK_VERSION,
		&m_pD3D11Device,
		NULL,
		&m_pD3D11Context
	);
	if (FAILED(hr))
	{
		OutputDebugString(L"Create Compute Device Filed");
		return FALSE;
	}

	if (m_pImageTexture != NULL)
	{
		m_pImageTexture->Release();
		m_pImageTexture = NULL;
	}

	//通过句柄绑定D3D9和D3D11的共享
	ID3D11Resource* pResource = NULL;
	if (TargetHand != NULL)
	{
		hr = m_pD3D11Device->OpenSharedResource(TargetHand, __uuidof(ID3D11Resource), (LPVOID*)&pResource);
		if (pResource == NULL || FAILED(hr))
		{
			OutputDebugString(L"OpenSharedResource Filed");
			return FALSE;
		}

		pResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)(&m_pImageTexture));
		pResource->Release();
	//	m_pD3D11Context->Flush();
	}

	return TRUE;
}

2、处理图片

BOOL MyD3D11::DealSharedPicture()
{
	CString strIniFileC;
	strIniFileC.Format(_T(".\\Pre_%d.dds"), cont);
	HRESULT hr = D3DX11SaveTextureToFile(m_pD3D11Context, m_pImageTexture, D3DX11_IFF_DDS, strIniFileC);
	cont++;

	return TRUE;
}

三、主函数

#include"NVAPIGrab.h"
#include"MyD3D11.h"

void  main()
{
	int cont = 0;
	NVAPIGrab* Grab = new NVAPIGrab();
	MyD3D11*   D3D11 = new MyD3D11();
	
	HANDLE ShareHandle;
	Grab->InitGrab(ShareHandle);
	D3D11->InitD3D(NULL, ShareHandle);


	while (cont < 10)
	{
		cont++;
		if (Grab->GrabOneFarme())
		{
			D3D11->DealSharedPicture();
		}
		else
		{
			break;
		}
	}


	if (Grab != NULL)
	{
		Grab->ReleaseGrab();
		Grab = NULL;
	}

	if (D3D11 != NULL)
	{
		D3D11->ReleaseD3D();
		D3D11 = NULL;
	}
	return;
}

 

注意:

一、D3D9

1、D3D9抓屏必须用CreateOffscreenPlainSurface来创建离屏表面进行抓屏,但是OffcreenSurface句柄共享到D3D11后,保存Texture到本地会导致D3D设备停止工作。所以从新创建了一个Texture,通过其HANDLE来和D3D11进行数据交换。

2、抓到一帧数据后切记D3D9Device要调用Present(0, 0, 0, 0)来进行数据提交。否则第一帧D3D11拿到的数据为空。

二、D3D11

1、D3D11获取数据时,直接调用OpenSharedResource,即可将D3D9内存与D3D11的内存进行绑定。绑定后一单D3D9传入HANDLE所指向的内容发生变化,D3D11对应位置也会变化。所以改函数只需调用一次即可。后面直接用D3D11对应的Texture。

2、如果D3D9的HANDLE是OffcreenSurface的HANDLE数据也能进行交换,但是D3D11调用保存图片设备会停止工作。

源码路径

你可能感兴趣的:(D3D)