Windows C++ 弹框显示图片或者播放视频

工作需要排查问题,要将接收到的画面弹出一个小窗口显示出来

1,需要先将图片缩放(传入的buffer是RGBA的,如果是传入RGB,将从src_img获取像素的下标从 4* 改为 3* )

			int img_down_scale(const unsigned char* src_img, unsigned char* dst_img,
				unsigned int src_width, unsigned int src_height,
				unsigned int dst_width, unsigned int dst_height)
			{
				//bilinear interpolation
				if (!src_img || !dst_img) {
					//std::cout << "input array can not be null!" << std::endl;
					return -1;
				}
				if (!dst_width || !dst_height) {
					//std::cout << "image size wrong!" << std::endl;
					return -2;
				}

				double x_ratio = (double)src_width / dst_width;
				double y_ratio = (double)src_height / dst_height;
				double aspect_ratio = 0.0f;
				int border_shift = 0;
				unsigned int h = 0, w = 0;
				int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
				int dst_r = 0, dst_g = 0, dst_b = 0;

				if (x_ratio < y_ratio) {
					aspect_ratio = x_ratio;
					border_shift = (int)((src_height - (int)(dst_height * aspect_ratio)) / 2);
					for (h = 0; h < dst_height; h++) {
						for (w = 0; w < dst_width; w++) {
							double src_h = border_shift + h * aspect_ratio;
							double src_w = w * aspect_ratio;
							x0 = (int)src_w;
							x1 = x0 + 1;
							y0 = (int)src_h;
							y1 = y0 + 1;

							int rx0y0 = src_img[4 * (y0 * src_width + x0) + 0];
							int gx0y0 = src_img[4 * (y0 * src_width + x0) + 1];
							int bx0y0 = src_img[4 * (y0 * src_width + x0) + 2];

							int rx1y0 = src_img[4 * (y0 * src_width + x1) + 0];
							int gx1y0 = src_img[4 * (y0 * src_width + x1) + 1];
							int bx1y0 = src_img[4 * (y0 * src_width + x1) + 2];

							int rx0y1 = src_img[4 * (y1 * src_width + x0) + 0];
							int gx0y1 = src_img[4 * (y1 * src_width + x0) + 1];
							int bx0y1 = src_img[4 * (y1 * src_width + x0) + 2];

							int rx1y1 = src_img[4 * (y1 * src_width + x1) + 0];
							int gx1y1 = src_img[4 * (y1 * src_width + x1) + 1];
							int bx1y1 = src_img[4 * (y1 * src_width + x1) + 2];

							dst_r = (y1 - src_h) * ((x1 - src_w) * rx0y0 + (src_w - x0) * rx1y0) + (src_h - y0) * ((x1 - src_w) * rx0y1 + (src_w - x0) * rx1y1);
							dst_g = (y1 - src_h) * ((x1 - src_w) * gx0y0 + (src_w - x0) * gx1y0) + (src_h - y0) * ((x1 - src_w) * gx0y1 + (src_w - x0) * gx1y1);
							dst_b = (y1 - src_h) * ((x1 - src_w) * bx0y0 + (src_w - x0) * bx1y0) + (src_h - y0) * ((x1 - src_w) * bx0y1 + (src_w - x0) * bx1y1);

							dst_r = dst_r > 255 ? 255 : dst_r < 0 ? 0 : dst_r;
							dst_g = dst_g > 255 ? 255 : dst_g < 0 ? 0 : dst_g;
							dst_b = dst_b > 255 ? 255 : dst_b < 0 ? 0 : dst_b;

							dst_img[3 * (h * dst_width + w) + 0] = (unsigned char)dst_r;
							dst_img[3 * (h * dst_width + w) + 1] = (unsigned char)dst_g;
							dst_img[3 * (h * dst_width + w) + 2] = (unsigned char)dst_b;
						}
					}
				}
				else {
					aspect_ratio = y_ratio;
					border_shift = (int)((src_width - (int)(dst_width * aspect_ratio)) / 2);
					for (h = 0; h < dst_height; h++) {
						double src_h = h * aspect_ratio;
						for (w = 0; w < dst_width; w++) {
							double src_w = border_shift + w * aspect_ratio;
							x0 = (int)src_w;
							x1 = x0 + 1;
							y0 = (int)src_h;
							y1 = y0 + 1;

							int rx0y0 = src_img[4 * (y0 * src_width + x0) + 0];
							int gx0y0 = src_img[4 * (y0 * src_width + x0) + 1];
							int bx0y0 = src_img[4 * (y0 * src_width + x0) + 2];

							int rx1y0 = src_img[4 * (y0 * src_width + x1) + 0];
							int gx1y0 = src_img[4 * (y0 * src_width + x1) + 1];
							int bx1y0 = src_img[4 * (y0 * src_width + x1) + 2];

							int rx0y1 = src_img[4 * (y1 * src_width + x0) + 0];
							int gx0y1 = src_img[4 * (y1 * src_width + x0) + 1];
							int bx0y1 = src_img[4 * (y1 * src_width + x0) + 2];

							int rx1y1 = src_img[4 * (y1 * src_width + x1) + 0];
							int gx1y1 = src_img[4 * (y1 * src_width + x1) + 1];
							int bx1y1 = src_img[4 * (y1 * src_width + x1) + 2];

							dst_r = (y1 - src_h) * ((x1 - src_w) * rx0y0 + (src_w - x0) * rx1y0) + (src_h - y0) * ((x1 - src_w) * rx0y1 + (src_w - x0) * rx1y1);
							dst_g = (y1 - src_h) * ((x1 - src_w) * gx0y0 + (src_w - x0) * gx1y0) + (src_h - y0) * ((x1 - src_w) * gx0y1 + (src_w - x0) * gx1y1);
							dst_b = (y1 - src_h) * ((x1 - src_w) * bx0y0 + (src_w - x0) * bx1y0) + (src_h - y0) * ((x1 - src_w) * bx0y1 + (src_w - x0) * bx1y1);

							dst_r = dst_r > 255 ? 255 : dst_r < 0 ? 0 : dst_r;
							dst_g = dst_g > 255 ? 255 : dst_g < 0 ? 0 : dst_g;
							dst_b = dst_b > 255 ? 255 : dst_b < 0 ? 0 : dst_b;

							dst_img[3 * (h * dst_width + w) + 0] = (unsigned char)dst_r;
							dst_img[3 * (h * dst_width + w) + 1] = (unsigned char)dst_g;
							dst_img[3 * (h * dst_width + w) + 2] = (unsigned char)dst_b;
						}
					}
				}



				return 0;
			}

2,将buffer显示到窗口上面

			void ShowImage(HWND hWnd, long width, long height, char* bmpBuf)
			{
				//HWND hWnd = GetForegroundWindow();
				//if (hWnd == NULL)
				//{
				//	hWnd = GetDesktopWindow();
				//}
				RECT rc;
				::GetWindowRect((HWND)hWnd, &rc);
				int left, right, top, bottom;
				if (rc.right - rc.left > 0)
				{
					left = 0;
					right = rc.right - rc.left;
					top = 0;
					bottom = rc.bottom - rc.top;
				}

				HWND _hWnd = (HWND)hWnd;
				HDC hdc = ::GetDC(_hWnd);

				SetStretchBltMode(hdc, STRETCH_DELETESCANS);// STRETCH_HALFTONE);
				BITMAPINFO BitsInfo;
				memset(&BitsInfo, 0, sizeof(BITMAPINFOHEADER));
				BitsInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
				BitsInfo.bmiHeader.biWidth = width;
				BitsInfo.bmiHeader.biHeight = height;
				BitsInfo.bmiHeader.biPlanes = 1;
				BitsInfo.bmiHeader.biBitCount = 24;
				BitsInfo.bmiHeader.biCompression = BI_RGB;
				BitsInfo.bmiHeader.biSizeImage = 0;//BitsInfo.bmiHeader.biWidth*BitsInfo.bmiHeader.biHeight*4;


				StretchDIBits(hdc,           // handle to DC
					left,				// x-coord of destination upper-left corner
					top,				// y-coord of destination upper-left corner
					right + 1,				// width of destination rectangle
					bottom + 1,			// height of destination rectangle
					0,						// x-coord of source upper-left corner
					height - 1,						// y-coord of source upper-left corner
					width,				// width of source rectangle
					-height,			// height of source rectangle
					(void*)bmpBuf,		// bitmap bits
					&(BitsInfo),			// bitmap data
					DIB_RGB_COLORS,         // usage options
					SRCCOPY                 // raster operation code
				);
			}
		}
	}
}

3,窗口的回调函数(不对消息做任何处理,也可以加上相关的处理)

/*窗口回调函数*/
LRESULT CALLBACK WndProc1(HWND hwnd, UINT message/*窗口消息*/, WPARAM wParam, LPARAM lParam)
{
	//处理消息
	switch (message)
	{
	case WM_CREATE:
		/*窗口在创建时,会接收到该消息,通常在这里进行初始化操作*/
		return 0;
	case WM_SIZE:
		/*窗口被改变大小时,会接收到该消息,在窗口被创建时也会收到一次*/
		return 0;
	case WM_PAINT:
		/*窗口有绘图操作更新时,会收到这个消息*/
		return 0;
	case WM_DESTROY:
		/*关不窗口时,会收到该消息,PostQuitMessage()像系统表明终止当前线程,没有这个函数的话,窗口不会关闭*/
		PostQuitMessage(0);
		return 0;
	}
	//将不需要处理的消息传递给系统作默认处理
	return DefWindowProc(hwnd, message, wParam, lParam);
}

 4,开始显示

(1)创建一个窗口

	unsigned char* CvtYUYVdata = nullptr;
	unsigned char* dataRGBA = nullptr;
	unsigned char* dataRGBAScale = nullptr;
	static TCHAR szAppName[] = TEXT("Send"); //创建窗口的时候需要一个窗口类名
	HWND hwnd = nullptr;    //创建窗口函数CreateWindow()会返回一个HWND句柄,这里定义下,用来接收这个句柄
	//MSG msg;      //消息结构体,在消息循环的时候需要
	WNDCLASS wndclass; //创建窗口类对象


	//对窗口类的各属性进行初始化
	wndclass.style = CS_HREDRAW | CS_VREDRAW; /*窗口类的风格,CS前缀,C表示Class,S表示
					Style,这里使用了水平和垂直风格*/
	wndclass.lpfnWndProc = WndProc1;  /*这里将回到函数的名字赋值用以windows后面回调*/
	wndclass.cbClsExtra = 0;  //附加参数,通常情况下为0
	wndclass.cbWndExtra = 0;  //附加参数,通常情况下为0
	wndclass.hInstance = hInstance;  //窗口句柄,这里将WinMain中的hInstance句柄赋值就可
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); /*窗口图标,LoadIcon()是加载图标,这里是加载一个系统资源图标,LoadIcon()的原型是HICON LoadIcon(HINSTANCE, LPCSTR);*/
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);  /*加载鼠标,同上相似*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  /*窗口画刷,这里是使用的白色画刷,所以创建出来的窗口的背景颜色则是白色的*/
	wndclass.lpszMenuName = NULL;  //窗口菜单名称,这里没有菜单,设为NULL
	wndclass.lpszClassName = szAppName;  //窗口类名称,这个窗口类名称可作为这个窗口的唯一标识

	/*注册窗口类*/
	if (!RegisterClass(&wndclass))
	{
		//注册窗口类失败时,弹出提示
		//MessageBox(NULL, TEXT("This program requires Window NT!"), szAppName, MB_ICONERROR);
	}

(2)将buffer显示到弹框上面

			if (hwnd == nullptr)
			{
				hwnd = CreateWindow(szAppName,    //窗口类名
					TEXT("Send"),    //窗口标题,会在窗口的左上角标题栏显示
					WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, //窗口风格
					pSrcFrameData->iVideoWidth / 4 + 20, 0, pSrcFrameData->iVideoWidth / 4, pSrcFrameData->iVideoHeight / 4,
					NULL, //该窗口的父窗口或所有者窗口的句柄,这里用不到,设为NULL
					NULL, //窗口菜单句柄,这里没有菜单,设置为NULL
					hInstance, //窗口句柄
					NULL  //传递给窗口WM_CREATE消息的一个参数,这里不用,设置为NULL
				);

				/*显示窗口,显示方式使用WinMain的参数*/

				ShowWindow(hwnd, 1);
			}
			if (dataRGBAScale == nullptr)
			{
				dataRGBAScale = new unsigned char[pSrcFrameData->iVideoWidth / 4 * pSrcFrameData->iVideoHeight / 4 * 3.0f];
			}
			img_down_scale((unsigned char*)pSrcFrameData->pVideoData, dataRGBAScale, pSrcFrameData->iVideoWidth, pSrcFrameData->iVideoHeight, pSrcFrameData->iVideoWidth / 4, pSrcFrameData->iVideoHeight / 4);
			ShowImage(hwnd, pSrcFrameData->iVideoWidth / 4, pSrcFrameData->iVideoHeight / 4, (char*)dataRGBAScale);

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-13 21:54:09       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-13 21:54:09       106 阅读
  3. 在Django里面运行非项目文件

    2024-05-13 21:54:09       87 阅读
  4. Python语言-面向对象

    2024-05-13 21:54:09       96 阅读

热门阅读

  1. OpenCV特征匹配总结

    2024-05-13 21:54:09       39 阅读
  2. 信息系统架构_3.信息系统架构的一般原理

    2024-05-13 21:54:09       31 阅读
  3. vue3速览

    2024-05-13 21:54:09       34 阅读
  4. 完美实现vue3异步加载组件

    2024-05-13 21:54:09       39 阅读
  5. ts 详细-学习

    2024-05-13 21:54:09       32 阅读
  6. notepad++

    notepad++

    2024-05-13 21:54:09      31 阅读
  7. 存储芯片了解

    2024-05-13 21:54:09       34 阅读
  8. 大模型管理工具:Ollama

    2024-05-13 21:54:09       37 阅读
  9. 软件测试至关重要

    2024-05-13 21:54:09       26 阅读