With the advent of the information age, the application of the same screen technology in teaching, conferences, events more and more widely. End-screen nutshell, is the phone, tablet and other mobile devices some of the above audio and video data over a wireless or wired network synchronization to the display device. In other words, the scene in the mobile device audio and video data to the display frequency screen above. Like a looking glass, on what mobile device display, what is displayed on the display screen.
libEasyScreenLive achieved by D3D mode screen capture
In libEasyScreenLive we have achieved through the acquisition GDI mode screen, however, the low efficiency of GDI collection methods, which led to its acquisition of desktop video frame refresh desktop screen than the actual delay, this delay has been tested and can reach nearly 50ms, which we require very low latency with the screen does not match the demand, so we D3D by way of acquisition, this approach can be scheduled hardware drivers, better performance, and capture 60fps frame rate can reach more than, collection has become extremely low latency .
In libEasyScreenLive acquisition screen D3D by way mainly through CD3DCaptureScreem class, the following statement:
#include <d3d9.h>
#include <WinError.h>
typedef struct IDirect3D9* LPDIRECT3D9, *PDIRECT3D9;
typedef struct IDirect3DDevice9* LPDIRECT3DDevice9, *PDIRECT3DDevice9;
typedef struct IDirect3DSurface9* LPDIRECT3DSurface9, *PDIRECT3DSurface9;
typedef int (WINAPI *CaptureScreenCallback)(int nDevId, unsigned char *pBuffer, int nBufSize, int nRealDatatYPE, void* realDataInfo, void* pMaster);
class CD3DCaptureScreem
{
public:
CD3DCaptureScreem(void);
~CD3DCaptureScreem(void);
//接口函数
// 初始化
HRESULT InitD3DCapture(HWND hShowWnd);
//direct实现的截图
void DirectScreenCapture(LPVOID screenCaptureData);
//创建线程进行屏幕捕获
int CreateCaptureScreenThread();
static UINT WINAPI CaptureScreenThread(LPVOID pParam);
void CaptureVideoProcess();
//设置捕获数据回调函数
void SetCaptureScreenCallback(CaptureScreenCallback callBack, void * pMaster);
BOOL IsInCapturing()
{
return m_bCaptureScreen;
}
void GetCaptureScreenSize(int& nWidth, int& nHeight );
bool Convert24Image(BYTE *p32Img, BYTE *p24Img,DWORD dwSize32);
void StopD3DScreenCapture();
private:
HWND m_hMainWnd;
/*IDirect3D9**/ LPDIRECT3D9 m_pD3DScreenCapture;
/*IDirect3DDevice9* */LPDIRECT3DDevice9 m_pd3dDevice;
/*IDirect3DSurface9**/ LPDIRECT3DSurface9 m_pSurface;
CaptureScreenCallback m_pCallback;
void* m_pMaster;
int m_nCapWidth;
int m_nCapHeight;
LPVOID m_pScreenCaptureData;
RECT m_ScreenRect;
HANDLE m_hScreenCaptureThread;
BOOL m_bCaptureScreen;
};
We can see from the interface by way of acquisition D3D achieve simpler than GDI way, we just need to capture the rendering process equipment D3D9 take it again (temporarily not capture the mouse) to achieve the following functions:
HRESULT CD3DCaptureScreem:: InitD3DCapture(HWND hShowWnd)
{
m_hMainWnd = hShowWnd;
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biBitCount=32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biWidth=GetSystemMetrics(SM_CXSCREEN);
bmpInfo.bmiHeader.biHeight=GetSystemMetrics(SM_CYSCREEN);
bmpInfo.bmiHeader.biPlanes=1;
bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;
HDC hdc=GetDC(GetDesktopWindow());
HDC hBackDC=NULL;
HBITMAP hBackBitmap=NULL;
hBackDC=CreateCompatibleDC(hdc);
hBackBitmap=CreateDIBSection(hdc,&bmpInfo,DIB_RGB_COLORS,&m_pScreenCaptureData,NULL,0);
if(hBackBitmap==NULL)
{
return 0 ;
}
ReleaseDC(GetDesktopWindow(),hdc);
HWND hWnd = hShowWnd;
D3DDISPLAYMODE ddm;
D3DPRESENT_PARAMETERS d3dpp;
if((m_pD3DScreenCapture=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
{
return E_FAIL;
}
if(FAILED(m_pD3DScreenCapture->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
{
return E_FAIL;
}
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed=true;
d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dpp.BackBufferFormat=ddm.Format;
d3dpp.BackBufferHeight=m_ScreenRect.bottom =ddm.Height;
d3dpp.BackBufferWidth=m_ScreenRect.right =ddm.Width;
d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow=hWnd;
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
if(FAILED(m_pD3DScreenCapture->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING ,&d3dpp,&m_pd3dDevice)))
{
return E_FAIL;
}
m_nCapWidth = ddm.Width;
m_nCapHeight = ddm.Height;
if(FAILED(m_pd3dDevice->CreateOffscreenPlainSurface(m_nCapWidth, m_nCapHeight, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &m_pSurface, NULL)))
{
return E_FAIL;
}
CreateCaptureScreenThread();
return S_OK;
}
void CD3DCaptureScreem::StopD3DScreenCapture()
{
m_bCaptureScreen = 0;
//等待线程结束
//Sleep(300);
//获取线程结束代码 ,如果线程还在运行就等她结束
while (1)
{
DWORD dwExitCode ;
::GetExitCodeThread(m_hScreenCaptureThread,&dwExitCode);
if(dwExitCode == STILL_ACTIVE)
{
WaitForSingleObject(m_hScreenCaptureThread, 100);
}
else
{
break;
}
}
CloseHandle(m_hScreenCaptureThread);
m_hScreenCaptureThread = INVALID_HANDLE_VALUE;
m_pSurface->Release();
m_pd3dDevice->Release();
m_pD3DScreenCapture->Release();
}
//direct实现的截图
void CD3DCaptureScreem::DirectScreenCapture(LPVOID screenCaptureData)
{
m_pd3dDevice->GetFrontBufferData(0, m_pSurface);
D3DLOCKED_RECT lockedRect;
if(FAILED(m_pSurface->LockRect(&lockedRect,&m_ScreenRect,D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
{
return;
}
// for(int i=0;i<m_ScreenRect.bottom;i++)
// {
// }
memcpy((BYTE*)screenCaptureData/*+(i)*m_ScreenRect.right*32/8*/, (BYTE*)lockedRect.pBits/*+i*lockedRect.Pitch*/, m_ScreenRect.bottom*m_ScreenRect.right<<2);
m_pSurface->UnlockRect();
//printf("%d\n" , l3);
}
//创建线程进行屏幕捕获
int CD3DCaptureScreem::CreateCaptureScreenThread()
{
//创建线程
m_bCaptureScreen = TRUE;
m_hScreenCaptureThread=(HANDLE)_beginthreadex(NULL,0,(&CD3DCaptureScreem::CaptureScreenThread),
this,THREAD_PRIORITY_NORMAL,NULL);
return 1;
}
UINT WINAPI CD3DCaptureScreem::CaptureScreenThread(LPVOID pParam)
{
if (pParam)
{
CD3DCaptureScreem* pMaster = (CD3DCaptureScreem*)pParam;
if (pMaster)
{
pMaster->CaptureVideoProcess();
}
}
return 0;
}
void CD3DCaptureScreem::CaptureVideoProcess()
{
unsigned char * screenData = new unsigned char[1920*1080*4];
unsigned char * screenData24 = new unsigned char[1920*1080*3];
while (m_bCaptureScreen)
{
DirectScreenCapture(screenData);
Convert24Image(screenData, screenData24, 1920*1080*4);
#if 0
//显示图像
HWND hWnd=m_hMainWnd;
HDC hDC=::GetDC(hWnd);
::SetTextColor( hDC, RGB( 255, 255, 255 ) );
::SetBkMode( hDC, TRANSPARENT );
::SetStretchBltMode( hDC, COLORONCOLOR );
CRect rect;
::GetClientRect(m_hMainWnd, &rect);
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 1920;
bmi.bmiHeader.biHeight = -1080; // top-down image
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;//m_nColorBits;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
unsigned char * pData = (unsigned char *)screenData ;
::SetDIBitsToDevice( hDC, 0, 0, /*rect.Width()*/640, /*rect.Height()*/480, 0, 0, 0, 1080, (LPBYTE)pData , &bmi, DIB_RGB_COLORS );
#endif
if (m_pCallback&&m_pMaster)
{
ScreenCapDataInfo sCapScreenInfo;
sCapScreenInfo.nWidth = m_nCapWidth;
sCapScreenInfo.nHeight = m_nCapHeight;
sCapScreenInfo.nDataType = 24;
strcpy(sCapScreenInfo.strDataType, "RGB24");
m_pCallback(0, (unsigned char*)(screenData24), /*alpbi->biSizeImage*/m_nCapWidth*m_nCapHeight*3, 1, &sCapScreenInfo, m_pMaster);
}
//Sleep(30);
}
if (screenData)
{
delete screenData;
screenData = NULL;
}
if(screenData24)
{
delete screenData24;
screenData24 = NULL;
}
}
bool CD3DCaptureScreem::Convert24Image(BYTE *p32Img, BYTE *p24Img,DWORD dwSize32)
{
if(p32Img != NULL && p24Img != NULL && dwSize32>0)
{
DWORD dwSize24;
dwSize24=(dwSize32 * 3)/4;
BYTE *pTemp,*ptr;
pTemp=p32Img;
ptr = p24Img;
int ival=0;
for (DWORD index = 0; index < dwSize32/4 ; index++)
{
unsigned char r = *(pTemp++);
unsigned char g = *(pTemp++);
unsigned char b = *(pTemp++);
(pTemp++);//skip alpha
*(ptr++) = r;
*(ptr++) = g;
*(ptr++) = b;
}
}
else
{
return false;
}
return true;
}
//设置捕获数据回调函数
void CD3DCaptureScreem::SetCaptureScreenCallback(CaptureScreenCallback callBack, void * pMaster)
{
m_pCallback = callBack;
m_pMaster = pMaster;
}
void CD3DCaptureScreem::GetCaptureScreenSize(int& nWidth, int& nHeight )
{
nWidth = m_nCapWidth;
nHeight = m_nCapHeight;
}
EasyScreenlive scenarios
EasyScreenlive vote widely used in large-screen display screen, the same screen paperless conference presentations, classroom the same screen, etc., can be used with full screen, reverse analog touch remote control function (Android control Windows, Windows control Android, Windows and other Windows controls )