工作需要排查问题,要将接收到的画面弹出一个小窗口显示出来
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);