Render video from OpenCV Mat using Direct3d

mainwindow.h

1
2
3
4
5
6
7
8
#include "vren_thread.h"
 
class MainWindow : public QMainWindow
{
	Q_OBJECT
	...
	vren_thread vren_;
};

mainwindow.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include "mainwindow.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>
 
void CALLBACK DecCBFun(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, long nReserved1, long nReserved2)
{
	long lFrameType = pFrameInfo->nType;
 
	if (lFrameType == T_YV12)
	{
		MainWindow* win = port2MainWindow[nPort];
		if (nullptr == win)
		{
			qDebug() << "lookup main window from " << nPort << " failed.";
			return;
		}
 
		win->realYuvCallback(pBuf, nSize, pFrameInfo->nStamp, pFrameInfo->nWidth, pFrameInfo->nHeight);
	}
}
 
void MainWindow::realYuvCallback(const char* pBuf, int len, int64_t nStamp, int width, int height)
{
	cv::Mat dst(height, width, CV_8UC3);
	cv::Mat src(height + height / 2, width, CV_8UC1, (uchar*)pBuf);
	cv::cvtColor(src, dst, CV_YUV2RGBA_YV12); // CV_YUV2BGR_YV12);
	cv::line(dst, cv::Point(0, 0), cv::Point(100, 100), cv::Scalar(255, 0, 0), 10);
 
	vren_.Render_d3d(dst);
}
 
void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize, void* pUser)
{
	MainWindow* pThis = (MainWindow*)pUser;
	pThis->realDataCallback(lRealHandle, dwDataType, pBuffer, dwBufSize);
}
 
void MainWindow::realDataCallback(LONG lRealHandle, DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize)
{
	DWORD dRet = 0;
	BOOL inData = FALSE;
 
	switch (dwDataType)
	{
	case NET_DVR_SYSHEAD:
		if (!PlayM4_GetPort(&port_))
		{
			break;
		}
 
		port2MainWindow[port_] = this;
		playWnd_ = (HWND)ui->widgetVideo->winId();
		vren_.SetParam(playWnd_);
 
		if (!PlayM4_OpenStream(port_, pBuffer, dwBufSize, 1024 * 1024))
		{
			dRet = PlayM4_GetLastError(port_);
			break;
		}
 
		if (!PlayM4_SetDecCallBackEx(port_, DecCBFun, NULL, NULL))
		{
			dRet = PlayM4_GetLastError(port_);
			break;
		}
 
		if (!PlayM4_Play(port_, NULL)) // playWnd_))
		{
			dRet = PlayM4_GetLastError(port_);
			break;
		}
	}
}

vren_thread.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef __VREN_THREAD_H__
#define __VREN_THREAD_H__
 
#include <d3d9.h>
#include <d3d11.h>
 
#include <opencv2/opencv.hpp>
 
class vren_thread
{
public:
	vren_thread();
 
	inline void SetParam(HWND& hwnd)
	{
		m_hwhd = hwnd;
	}
 
	void TryResizeViewport(size_t width, size_t height);
 
	int Render_d3d(cv::Mat frame);
	void DestroyRender_d3d();
	int InitRender_d3d(size_t width, size_t height);
 
	void ResizeViewport(size_t width, size_t height);
 
private:
	IDXGISwapChain* g_pSwapChain{ NULL };
	ID3D11Device* g_pd3dDevice{ NULL };
	ID3D11DeviceContext* g_pImmediateContext{ NULL };
	ID3D11RenderTargetView* g_pRenderTargetView{ NULL };
	ID3D11Texture2D* g_Texture{ NULL };
 
	HWND m_hwhd;
	bool m_d3dinit;
	IDirect3D9* m_d3d;
	IDirect3DDevice9* m_d3d_device;
	IDirect3DSurface9* m_surface;
	RECT m_rtViewport; 
	int m_width;
	int m_height;
 
	uint8_t* m_y_data;
	bool m_try_resize;
	int m_new_width;
	int m_new_height;
};
#endif

vren_thread.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "vren_thread.h"
 
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "winmm.lib") 
#pragma comment(lib, "OpenGl32.lib")
 
vren_thread::vren_thread()
	: m_hwhd(NULL)
	, m_d3d(NULL)
	, m_d3d_device(NULL)
	, m_surface(NULL)
	, m_d3dinit(false)
{
}
 
int vren_thread::Render_d3d(cv::Mat frame)
{
	if(!m_d3dinit)
	{
		if(this->InitRender_d3d(frame.size().width, frame.size().height))
			return -1;
 
	}
 
	if (m_width != frame.size().width || m_height != frame.size().height)
	{
		this->DestroyRender_d3d();
 
		if (this->InitRender_d3d(frame.size().width, frame.size().height))
			return -1;
	}
 
	size_t width = frame.size().width;
	size_t height = frame.size().height;
 
	int stride = width;
	m_y_data = frame.data;
 
	ID3D11Texture2D* pBackBuffer;
	g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
 
	g_pImmediateContext->UpdateSubresource(pBackBuffer, 0, NULL, m_y_data, stride * 4, 0);
 
	g_pSwapChain->Present(0, 0);
 
	return 0;
}
 
int vren_thread::InitRender_d3d(size_t width, size_t height)
{
	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory(&sd, sizeof(sd));
	sd.BufferCount = 1;
	sd.BufferDesc.Width = width;
	sd.BufferDesc.Height = height;
	sd.BufferDesc.Format =  DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = m_hwhd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;
 
	HRESULT hr = S_OK;
	D3D_FEATURE_LEVEL  FeatureLevelsRequested = D3D_FEATURE_LEVEL_11_0;
	UINT               numLevelsRequested = 1;
	D3D_FEATURE_LEVEL  FeatureLevelsSupported;
 
	if (FAILED(hr = D3D11CreateDeviceAndSwapChain(NULL,
		D3D_DRIVER_TYPE_HARDWARE,
		NULL,
		0,
		&FeatureLevelsRequested,
		numLevelsRequested,
		D3D11_SDK_VERSION,
		&sd,
		&g_pSwapChain,
		&g_pd3dDevice,
		&FeatureLevelsSupported,
		&g_pImmediateContext)))
	{
		return hr;
	}
 
	ID3D11Texture2D* pBackBuffer;
	hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
 
	// Create a render-target view
	g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
 
	// Bind the view
	g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
 
	// Setup the viewport
	D3D11_VIEWPORT vp;
	vp.Width = width;
	vp.Height = height;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	g_pImmediateContext->RSSetViewports(1, &vp);
 
	m_width = width;
	m_height = height;
 
 //	SetWindowPos(m_hwhd, NULL, 0, 0, width, height, SWP_NOZORDER);
 
	m_d3dinit = true;
//	m_y_data = new uint8_t[width*height * 4];
 
	return 0;
}
 
void vren_thread::DestroyRender_d3d()
{
	if(m_surface)  
		m_surface->Release();  
	if(m_d3d_device)  
		m_d3d_device->Release();  
	if(m_d3d)  
		m_d3d->Release();
 
	m_surface = NULL;
	m_d3d_device = NULL;
	m_d3d = NULL;
}

用qt opengl渲染rgb视频:
https://www.dazhuanlan.com/humphreydong/topics/1571432
用qt opengl渲染yuv视频:
https://blog.csdn.net/m0_37624402/article/details/123926611

refer to:
https://github.com/greenjim301/rtsp
https://blog.csdn.net/shangtao1989/article/details/50260661