Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192590
  • 博文数量: 44
  • 博客积分: 1515
  • 博客等级: 上尉
  • 技术积分: 480
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-06 16:39
文章分类

全部博文(44)

文章存档

2013年(3)

2012年(2)

2011年(2)

2009年(20)

2008年(17)

我的朋友

分类:

2008-09-28 11:41:59

项目要使用C#开发一个播放器,解码器解码后的码流为yuv420格式,转换为yuv422,送给播放器。打算使用directdraw来开发。
开发环境:
visual studio 2005
directx 9.0
必须在C#导入directdraw的命名空间,操作如下:
添加引用  项目->添加引用,选择COM标签页,添加Direct 7 for Visual Basic Type 选项。(DirectDraw好像不被direct9.0支持了)。

DirectDraw的使用流程如下:
1 创建一个DirectX7结构实体,directdraw对象必须由一个DirectX7结构实体创建;
   DxVBLib.DirectX7 dx=new DxVBLib.DirectX7();
2 由dx来创建directdraw对象:
    DxVBLib.DirectDraw7 dDrawdx.DirectDrawCreate(""); 该函数的参数做什么用我也没搞明白:)    dDraw.SetCooperativeLevel(this.Handle.ToInt32(),DxVBLib.CONST_DDSCLFLAGS.DDSCL_NORMAL);

3 创建DirectDrawSurface7对象:
   该类型对象是directdraw 用来存放图像信息和显示图像的内存/显存区域的, 是控制图像显示的 实体。通过DDSURFACEDESC 对象来设置 DirectDrawSurface7属性。
   //声明对象
    DxVBLib.DDSURFACEDESC2 dDDesc;
    DxVBLib.DirectDrawSurface7 dDsurface;
    DxVBLib.DDSURFACEDESC2 dDDesc1;
    DxVBLib.DirectDrawSurface7 dDsurfaceSec;
    DxVBLib.DDPIXELFORMAT g_ddpfOverlayFormats;
    StreamReader freader;
    DxVBLib.RECT rect, rectSec;
  //初始化对象

    dDDesc = new DxVBLib.DDSURFACEDESC2();
    dDDesc1 = new DxVBLib.DDSURFACEDESC2();
    unsafe {
                dDDesc.lSize = sizeof(DxVBLib.DDSURFACEDESC2);
                dDDesc1.lSize = sizeof(DxVBLib.DDSURFACEDESC2);
            }
    dDDesc.lFlags = DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_CAPS;
    dDDesc.ddsCaps.lCaps = DxVBLib.CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE;
            dDsurface = dDraw.CreateSurface(ref dDDesc);

          
    dDDesc1.lWidth = 352;
    dDDesc1.lHeight = 288;
    dDDesc1.lFlags = DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_CAPS |                                 DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH |
                     DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT|
                     DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_PIXELFORMAT;
   dDDesc1.ddsCaps.lCaps = DxVBLib.CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN                            |DxVBLib.CONST_DDSURFACECAPSFLAGS.DDSCAPS_VIDEOMEMORY;
             
   unsafe
   {
       g_ddpfOverlayFormats.lSize = sizeof(DxVBLib.DDPIXELFORMAT);
       g_ddpfOverlayFormats.lFlags = DxVBLib.CONST_DDPIXELFORMATFLAGS.DDPF_FOURCC;
       g_ddpfOverlayFormats.lFourCC = 0x59565955;
   }
   dDDesc1.ddpfPixelFormat = g_ddpfOverlayFormats;
   dDsurfaceSec = dDraw.CreateSurface(ref dDDesc1) ;
   fsreader = new FileStream("e:\\422.yuv", FileMode.Open);
   rect.Top = 0;
   rect.Left = 0;
   rect.Right = 352;// dDDesc1.lWidth;
   rect.Bottom = 288;// dDDesc1.lHeight; 
4 显示部分
  向dDsurfaceSec 拷贝数据:
  首先从文件中读数据:
  int i = 0, j = 0;        
  byte[] buff = new byte [152064*4/3];
  fsreader.Read(buff, 0, 152064 * 4 / 3); //每次读一帧的数据,该大小是根据355×288的                                          //yuv422视频数据计算出来的;
  接着应该将buff中的数据读到dDsurfaceSec 中去:
   首先将dDDesc1清零,在C#中没找到memset函数,只有采用相当笨蛋办法,如下:
   dDDesc1.lWidth = 0;
   dDDesc1.lHeight = 0;
   dDDesc1.lFlags = 0;
   dDDesc1.lpSurface = 0;
   dDDesc1.ddsCaps.lCaps = 0;
   unsafe{ dDDesc1.lSize = sizeof(DxVBLib.DDSURFACEDESC2);}
   然后对dDsurfaceSec加锁:
   dDsurfaceSec.Lock(ref rect, ref dDDesc1,                                                             DxVBLib.CONST_DDLOCKFLAGS.DDLOCK_SURFACEMEMORYPTR |                                 DxVBLib.CONST_DDLOCKFLAGS.DDLOCK_WAIT, 0);

   然后拷贝数据:
   unsafe
   {                        
       byte * pbuff=null;                      
       j = 0;
       pbuff = (byte*)dDDesc1.lpSurface;   
        //又发生了致命的事情,在C#中没找到memcpy类似的函数,很苦恼,:( 只有采用如此笨蛋办法
       while (j < 152064 * 4 / 3)
       {
           *pbuff =(byte)buff[j];
            pbuff++;
            j++;
        }
                  
    }
对dDsurfaceSec解锁:
dDsurfaceSec.Unlock(ref rect);

显示:
dx.GetWindowRect(this.Handle.ToInt32(), ref rectSec);
                   
dDsurface.Blt(ref rectSec, dDsurfaceSec, ref rect,                                   DxVBLib.CONST_DDBLTFLAGS.DDBLT_WAIT);



后记:
    1从文件中读数据是不要使用那个StreamReader,因为它将超过127的值丢掉了,开发过中让我迷惑了很长时间;
    2调用blt函数前一定将dDsurfaceSec解锁;
    3对于352×288的yuv420数据,一帧大小为:152064 ,而yuv422为其4/3倍。通过                    “g_ddpfOverlayFormats.lFourCC = 0x59565955”来指定显示yuv422格式。
    4对C#的语法不熟悉:(,上述代码通过调试,并且测试成功,但效率低下:)。
    5通过blt的返回值来跟踪错误,很有效。











阅读(6320) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-09-07 22:30:07

Hi,