该文是转载:原文地址:

http://blog.csdn.net/wangchenggggdn/archive/2010/07/05/5713075.aspx

首先要感谢ffmpeg, 如果没有它,所有做电脑视频----包括PC, 嵌入式, DV/DC,DVD机等公司(也包括我们公司), 一大半得关门。没有它,一些中小公司将无法研发这些编解码器, 没有了这些技术基础,产品将无从谈起;没有它, PC上常见的Mplayer, KMPlayer, 暴风影音等都不会存在!所以,在很多情况下,做视频软件,ffmpeg是软件的底层库,是基础平台。

其次要感谢显卡的超强功能。显卡越来越强大,有些显卡的GPU能力甚至要超过了PC上CPU的计算能力-----是不是主次颠倒了?正是有了这些显卡,逼真高效的游戏才成为了可能。

现在我要说的,就是ffmpeg的解码后,多路高效显示的一点点小技巧。

微软推出DirectShow时,可以说是天生为流媒体开发而制作的, 因为它提供的功能太强大了:多种格式视频显示、视频音频同步、视频合成、视频分离等等令人激动的功能。如果是单路或几路视频显示,当然用DirectShow是最好的选择,但是,如果要显示的视频路非常多,例如25路,使用它就会发现资源占用率极高,一路视频显示,不算解码,要4个线程!并且图像合成时CPU占有率极高----总而言之,DirectShow不适合多路视频的专业监控。

DirectDraw是我发现的在Windows平台下最佳的解决方案,唯一的缺点就是,你需要做一些视频图像的处理,这需要更强的专业知识和更多的开发时间。事实上,从某种程度上来说,你就是在开发一款mini型的DirectShow COM.

不必多说,转入正文。

ffmpeg解码出来后,一般会生成YV12格式,在2005年以后出产的显卡,它可以直接放到显存中直接显示的---当然,这并不是绝对的,有些显卡,例如明基一些笔记本就不支持YV12。这种做法显然是最高效的,中间没有转换格式,数据量也是最小的。可是,有时我们需要对视频做一些特殊处理,例如,在视频上放一些文字,显示一些时间等,这种情况下,因为在DirectX提供的YUV表面上是无法得到HDC句柄的,如果直接操作YUV数据, 那非常的麻烦--你自已要完成提供画线,字体合成之类工作,也就是说,你不能使用Win32 API, 要自已写类似的API Function. 实际上有个很简单的办法,那就是利用显卡自已的格式转换功能!

显卡一般支持YUV格式直接转到RGB24/RGB32。至于显卡支持具体的格式,请用DirectX Caps来查询就知道了。要实现上述功能,其实是很简单,创建主表面-->创建RGB从表面---->创建YV12从表面,然后将YV12数据复制到 YV12表面, Blt到RGB表面(在这一步中显卡自动完成YV12到RGB的转换), 然后取RGB表面的HDC, 就可以利用TextOut, FillRect, Line之类的Win32 API来绘图写字了,最后,将RGB表面Blt到主表面,这个过程就算是结束了。

需要说明的是,这个过程只用到显卡的运算能力,没有用到CPU,所以CPU占有率不会提高,但对于显卡来说,要占用显卡的GPU和显存的带宽。显卡的性能就显得比较重要了。

以下是实现代码:(由于商业原因,一些细节代码被取消了,但整体技术实现流程是完整的)

class CVideoDraw

{

LPDIRECTDRAW7           m_lpDD;    // DirectDraw 对象指针

LPDIRECTDRAWSURFACE7    m_lpDDSPrimary;  // DirectDraw 主表面指针

LPDIRECTDRAWSURFACE7    m_lpDDSOffScrYUV;  // DirectDraw 离屏表面指针

LPDIRECTDRAWSURFACE7    m_lpDDSOffScrRGB;

DDSURFACEDESC2          m_ddsd;    // DirectDraw 表面描述

RECT                    m_rcDraw;

HWND                    m_hWnd;

bool InitDirectX(HWND hWnd, int nWidth, int nHeight);

void ClearDirectX();

bool Draw(LPBYTE pBuffer, int nWidth, int nHeight, int nSec);

};

bool CVideoDraw::InitDirectX(HWND hWnd, int nWidth, int nHeight) {
if (DirectDrawCreateEx(NULL, (LPVOID*)&m_lpDD, IID_IDirectDraw7, NULL) != DD_OK)
   return false;
 
if (m_lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL) != DD_OK){
   ClearDirectX();
   return false;
}

ZeroMemory(&m_ddsd, sizeof(m_ddsd));
m_ddsd.dwSize = sizeof(m_ddsd);
m_ddsd.dwFlags = DDSD_CAPS;
m_ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (m_lpDD->CreateSurface(&m_ddsd, &m_lpDDSPrimary, NULL) != DD_OK){
   ClearDirectX();
   return false;
}

LPDIRECTDRAWCLIPPER pcClipper;
if( m_lpDD->CreateClipper(0, &pcClipper, NULL) != DD_OK) {
   ClearDirectX();
   return false;
}

if( pcClipper->SetHWnd(0, m_hWnd) != DD_OK) {
   ClearDirectX();
   return false;
}

if( m_lpDDSPrimary->SetClipper(pcClipper) != DD_OK) {
   ClearDirectX();
   return false;
}

pcClipper->Release();

// 创建离屏表面对象
ZeroMemory(&m_ddsd, sizeof(m_ddsd));
m_ddsd.dwSize = sizeof(m_ddsd);
m_ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_VIDEOMEMORY ; // DDSCAPS_VIDEOMEMORY; //DDSCAPS_OVERLAY DDSCAPS_OFFSCREENPLAIN;
m_ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
m_ddsd.dwWidth = nWidth;
m_ddsd.dwHeight = nHeight;
m_ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
m_ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC | DDPF_YUV ;
m_ddsd.ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','V','1','2');
m_ddsd.ddpfPixelFormat.dwYUVBitCount = 8;
if (m_lpDD->CreateSurface(&m_ddsd, &m_lpDDSOffScrYUV, NULL) != DD_OK) {
   ClearDirectX();
   return false;
}

ZeroMemory(&m_ddsd, sizeof(m_ddsd));
m_ddsd.dwSize = sizeof(m_ddsd);
m_ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_VIDEOMEMORY; // DDSCAPS_VIDEOMEMORY; //DDSCAPS_OVERLAY DDSCAPS_OFFSCREENPLAIN;
m_ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
m_ddsd.dwWidth = nWidth;
m_ddsd.dwHeight = nHeight;
if (m_lpDD->CreateSurface(&m_ddsd, &m_lpDDSOffScrRGB, NULL) != DD_OK) {
   ClearDirectX();
   return false;
}

return true;
}

void CVideoDraw::ClearDirectX() {
if( m_lpDD != NULL ){
   SAFE_RELEASES(m_lpDDSOffScrRGB);
   SAFE_RELEASES(m_lpDDSOffScrYUV);
   SAFE_RELEASES(m_lpDDSPrimary);
   SAFE_RELEASES(m_lpDD);
}
}

bool CVideoDraw::Draw(LPBYTE pBuffer, int nWidth, int nHeight, int nSec) {
HRESULT ddRval;
RECT rctDest;    // 目标区域
RECT rctSour;    // 源区域

for(int nTry=0; nTry < 5; nTry++){
   ddRval = m_lpDDSOffScrYUV->Lock(NULL,&m_ddsd, DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL);
   if( ddRval == DDERR_SURFACELOST ) {
    ddRval = m_lpDDSOffScrYUV->Restore();
   }
   if( ddRval == DD_OK ){
    break;
   }
}

if( ddRval != DD_OK ) return false;

int i=0;
LPBYTE lpSurf = (LPBYTE)m_ddsd.lpSurface;
LPBYTE lpY = (LPBYTE)pBuffer;
LPBYTE lpV = (LPBYTE)(pBuffer + nWidth * nHeight);
LPBYTE lpU = (LPBYTE)(pBuffer + nWidth * nHeight * 5 / 4);

int nOffset = 0;
int value1 = 0 ;
int value2 = 0 ;
int value3 = 0 ;
int value4 = 0 ;

lpY += nOffset;
for(i=0; i<m_ddsd.dwHeight; i++)
{
   memcpy(lpSurf, lpY, m_ddsd.dwWidth);
   lpY += nWidth;
   lpSurf += m_ddsd.lPitch;
}

value1 = m_ddsd.dwHeight/2;
value2 = m_ddsd.dwWidth / 2;
value3 = nWidth / 2;
value4 = m_ddsd.lPitch / 2;

for(i=0; i<value1; i++)
{
   memcpy(lpSurf, lpU, value2);
   lpU += value3;
   lpSurf += value4;
}

for(i=0; i<value1; i++)
{
   memcpy(lpSurf, lpV, value2);
   lpV += value3;
   lpSurf += value4;
}
m_lpDDSOffScrYUV->Unlock(NULL);

SetRect(&rctDest, 0,0, nWidth, nHeight);
ddRval = m_lpDDSOffScrRGB->Blt(&rctDest, m_lpDDSOffScrYUV, NULL, DDBLT_WAIT, NULL);
if( ddRval != DD_OK)
   return false;

ddRval = m_lpDDSOffScrRGB->Lock(NULL,&m_ddsd, DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL);
if( ddRval == DDERR_SURFACELOST )
   ddRval = m_lpDDSOffScrRGB->Restore();
 
if( ddRval != DD_OK )
   return false;

HDC hdc = NULL;
m_lpDDSOffScrRGB->GetDC(&hdc);
if( hdc )
{
   TCHAR szText[64];
   int thh = nSec/3600;
   int tmm = (nSec%3600)/60;
   int tss = nSec%60;
   wsprintf(szText, _T("%02d:%02d:%02d"), thh, tmm, tss);
   SetBkMode(hdc, TRANSPARENT);
   ::SetTextColor(hdc, RGB(255,0,0));
   TextOut(hdc, 1, 1, szText, wcslen(szText));
   m_lpDDSOffScrRGB->ReleaseDC(hdc);
}
m_lpDDSOffScrRGB->Unlock(NULL);

// Blt到主表面上
rctSour.left = 0;
rctSour.top = 0;
rctSour.right = m_ddsd.dwWidth;
rctSour.bottom = m_ddsd.dwHeight;
rctDest = m_rcDraw;
::ClientToScreen(m_hWnd, (LPPOINT)&rctDest.left);
::ClientToScreen(m_hWnd, (LPPOINT)&rctDest.right);

ddRval = m_lpDDSPrimary->Blt(&rctDest, m_lpDDSOffScrRGB, NULL, DDBLT_WAIT, NULL);

return (ddRval==DD_OK);
}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wangchenggggdn/archive/2010/07/05/5713075.aspx

yuv显卡转换rgb相关推荐

  1. YUV格式转换RGB(基于opencv)

    在编写代码将需要处理YUV格从每个视频帧中提取,然后将其保存为图片.有两种常见的方法在线,第一种是通过opencv自带cvCvtColor,可是这样的方法有bug.得到的图片会泛白.另外一种方法是公式 ...

  2. FFmpeg入门详解之121:颜色空间转换RGB和YUV的原理与实战

    5.颜色空间转换RGB和YUV的原理与实战 三种颜色空间模型:RGB.YUV.HSV 一.概述 颜色通常用三个独立的属性来描述,三个独立变量综合作用,自然就构成一个空间坐标,这就是颜色空间. 但被描述 ...

  3. rgb到yuv的转换

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 RGB到YUV(4:2:0)的转换 实验目标:实验RGB到YUV 的转换 一.实验原理 二.编程步骤 1.读入rgb分量 2.由RGB ...

  4. 流媒体之色彩转换——RGB(X)与YUV之间转换

    文章目录 一:RGB32转RGB24 二:YUV与RGB相互转换 2.1 YUV->RGB 2.1.1 常规转换 2.1.2 去浮点转换 2.1.3 去浮点去乘法转换 2.1.4 查表转换 2. ...

  5. 图片YUV格式与RGB格式的转换

    YUV格式与RGB格式的转换 YUV格式介绍 YUV420.YUV422.YUV444 (1) YUV4:2:0 (2) YUV4:2:2 (3) YUV4:4:4 内存排列方式 YUV与RGB转换 ...

  6. 色差输出 S-Video YUV YCbCr YPvPr RGB VGA WXGA

    色差输出 S-Video YUV YCbCr YPvPr RGB VGA WXGA 色差输出 色差信号y,r-y,b- y信号一般通称为y, cr,cb; 习惯上y,cr,cb为数字(pcm)的色差信 ...

  7. SPDIF 色差输出 视频输出 S-Video YUV YCbCr YPbPr RGB VGA WXGA 分别的详细介绍 视频方式接口简介

    SPDIF 色差输出 视频输出 S-Video YUV YCbCr YPbPr RGB VGA WXGA 分别的详细介绍 视频方式接口简介 2008年04月05日 星期六 00:27 SPDIF 数字 ...

  8. Bitmap和YUV的转换

    以前做过的一个视频通话中,有用到Bitmap和YUV的转换,现在整理出来. 参考自:http://blog.csdn.net/lancees/article/details/7686046 http: ...

  9. yuv格式转换是那个组织定义的_YUV格式

    在前几篇介绍了OpenGL几种2D效果(旋转.平移.缩放.滤镜)后可以看到,GL图像颜色空间是用R.G.B.A,也就是红.绿.蓝 加一个透明度通道来表示的.比如,gl_FragColor 通常在取值的 ...

最新文章

  1. 如何编写可测试的golang代码
  2. java清空栈_java - 如何使用Intent.FLAG_ACTIVITY_CLEAR_TOP清除活动堆栈?
  3. ios自动布局(1)
  4. web项目中的web.xml元素解析
  5. java添加时间,如何通过Java中的addHours()方法添加时间
  6. CVE-2021-29454——Smarty模板注入
  7. The 'Microsoft Jet OLEDB 4.0 Provider' is not registered on the local machine
  8. 区块链演进及跨域安全解决方案
  9. java制作扫雷游戏中埋雷的难点_月薪30K程序员花了一个小时,用c++做出经典扫雷游戏 !...
  10. 前端工程师如何摆脱舒适区,持续精进?
  11. Linux常用命令大全(非常全)
  12. 【英语学习】【加州教材】【G6】【科学】Earth Science目录及术语表
  13. 大学计算机基础模拟,模拟练习系统
  14. python 3d重建_三维人脸重建(一)——Python读取obj文件
  15. SQL语言:DQL,DML,DDL,DCL
  16. linux操作系统入门教学
  17. Spring全家桶+分布式微服务(十次方)
  18. 微信公众号引流的十种方法
  19. 影音嗅探专家 v2007.1 怎么用
  20. 随手写的绿色征途手游的脚本辅助代码

热门文章

  1. HTML5 在线学习网站
  2. Oracle--初学小白基础篇(第一版)
  3. 路缘石滑模机在作业中实现施工水平突破的特点
  4. 线性代数---第五章特征值和特征向量
  5. 如何在Windows中使用虚拟文件测试网络或硬盘速度
  6. GO工具开发|基于网站API的子域名与IP反查工具(一)
  7. 扑克牌面试问题:从牌顶拿出一张牌放到桌子上,再从牌顶拿一张牌放在手上牌的底部,重复第一步、第二步的操作
  8. 1.Azure虚拟机部署
  9. Opencv图像分割与Watershed算法
  10. 前方高能!吹爆这份HTTP顶级教程