本篇介绍如何使用d3d 9抓取屏幕图像,并将图像转化为RGB数据,转化后的数据可直接传递给FFmpeg进行编解码。
获取桌面数据容易,转为RGB网上的例子就少了,大多只会使用D3D api保存为一个图片,本文解决了这个难题,如果你想使用D3D抓图然后使用FFMPEG进行录制会对你有所帮助。
1.创建D3D对象
_d3d = Direct3DCreate9(D3D_SDK_VERSION);
2.获取display配置
memset(&_d3d_displaymodel, 0, sizeof(_d3d_displaymodel));
HRESULT hr = _d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &_d3d_displaymodel);
if (FAILED(hr))
{
SafeRelease(_d3d);
return error;
}
3.创建设备对象
D3DPRESENT_PARAMETERS d3dParam;
memset(&d3dParam, 0, sizeof(d3dParam));
d3dParam.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dParam.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dParam.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dParam.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dParam.Windowed = TRUE;
d3dParam.BackBufferWidth = 0;
d3dParam.BackBufferHeight = 0;
d3dParam.BackBufferFormat = D3DFMT_UNKNOWN;
d3dParam.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dParam.hDeviceWindow = hWnd;
// create d3ddevice
hr = _d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dParam, &_d3d_device);
if (FAILED(hr))
{
SafeRelease(_d3d_device);
return error;
}
4. 创建CreateOffscreenPlainSurface对象
hr = _d3d_device->CreateOffscreenPlainSurface(_d3d_displaymodel.Width, _d3d_displaymodel.Height,
D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &_d3d_surface, NULL);
if (FAILED(hr))
{
SafeRelease(_d3d_device);
SafeRelease(_d3d_surface);
return error;
}
5.获取数据
_d3d_device->GetFrontBufferData(0, _d3d_surface);
D3DLOCKED_RECT lr;
_d3d_surface->LockRect(&lr,NULL,
D3DLOCK_NO_DIRTY_UPDATE|
D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY);
6.转为为RGB数据
int BITSPERPIXEL = 32;
DWORD* pBuf = (DWORD*)lr.pBits;
int nPitch = lr.Pitch;
for( int i=0 ; i < winheight ; i++)
{
memcpy((BYTE*) _buffer + i *
winwidth * BITSPERPIXEL/8 ,
(BYTE*) pBuf+ i* nPitch ,
winwidth* BITSPERPIXEL/8);
}
注意桌面缓存不使用BackBuffer,所以这里一定要用GetFrontBufferData,GetBackBuffer是拿不到数据的。
完整代码:
#ifndef RECORD_WINDOW_D3D
#define RECORD_WINDOW_D3D
#include "record_desktop.h"
#include <Windows.h>
#include <d3d9.h>
#pragma comment(lib,"d3d9.lib")
namespace RecorderSP {
template <typename T>
inline void SafeRelease(T* &p)
{
if (NULL != p)