欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-02 11:03:22
...

功能描述:

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