最近在优化视频播放,原先使用.net+ocx(DirectX)进行接收视频流并展示到前端界面,在使用的过程中发现视频窗口多的话,容易分配内存失败并占用内存、GPU、CPU过高,不能满足客户的需要;
后来在优化的过程中,发现是使用DirextX导致的,在使用下面语句创建设备时经常创建失败,并且发现内存增长跟使用DirextX有关 。
d3d9->CreateDevice(D3DADAPTER_DEFAULT,deviceType,hwnd,vp,&d3dpp,device);
采取了第二种方案进行优化,就想到了使用GDI进行播放,并且操作也比使用DirectX更加简单。
if (m_pSwsContext == NULL)
{
m_pSwsContext = sws_getContext(w,h,m_pCodecContext->pix_fmt,w, h,AV_PIX_FMT_BGR24, SWS_FAST_BILINEAR,NULL, NULL, NULL);
av_image_alloc(m_pFrameRGB->data, m_pFrameRGB->linesize,w, h, AV_PIX_FMT_BGR24,1);
}
sws_scale(m_pSwsContext,(uint8_t const * const *)m_pSrcFrame->data,
m_pSrcFrame->linesize, 0, h, m_pFrameRGB->data,m_pFrameRGB->linesize);
GetClientRect(m_hWnd, &recWindow);//获取窗口大小
int width = recWindow.right - recWindow.left; //窗口的宽度
int height = recWindow.bottom - recWindow.top; //窗口的高度
HDC hdc = GetDC(m_hWnd);
//转换成RGB24
BITMAPINFO m_bmphdr = { 0 };
DWORD dwBmpHdr = sizeof(BITMAPINFO);
//24bit
m_bmphdr.bmiHeader.biBitCount = 24;
m_bmphdr.bmiHeader.biClrImportant = 0;
m_bmphdr.bmiHeader.biSize = dwBmpHdr;
m_bmphdr.bmiHeader.biSizeImage = 0;
m_bmphdr.bmiHeader.biWidth = w;
//Notice: BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
//So we must set reverse biHeight to show image correctly.m_bmphdr.bmiHeader.biHeight = -h;
m_bmphdr.bmiHeader.biXPelsPerMeter = 0;
m_bmphdr.bmiHeader.biYPelsPerMeter = 0;
m_bmphdr.bmiHeader.biClrUsed = 0;
m_bmphdr.bmiHeader.biPlanes = 1;
m_bmphdr.bmiHeader.biCompression = BI_RGB;
//Draw data
//YUV420P data convert to another buffer
SetStretchBltMode(hdc, STRETCH_HALFTONE);
int nResult = StretchDIBits(hdc,
0, 0,
width, height,
0, 0,
w, h,
m_pFrameRGB->data[0],
&m_bmphdr,
DIB_RGB_COLORS,
SRCCOPY);
//DeleteDC(hdc);
ReleaseDC(m_hWnd, hdc);
av_frame_unref(m_pSrcFrame);
sws_freeContext(m_pSwsContext);
使用上述代码展示视频后,内存占用没有原来的的多了,并且使用到的GPU很少(一般客户那里的电脑没有GPU),视频十分流畅;上述代码中 SetStretchBltMode(hdc, STRETCH_HALFTONE);这一句非常重要,在测试阶段发现视频失真非常严重,导致画面十分难看,加上了这段代码后,视频质量提升了不少,播放效果大大提升。在使用ffmpeg的过程中,一定要小心内存泄漏,该释放的一定要释放。