项目要使用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的返回值来跟踪错误,很有效。
阅读(6349) | 评论(1) | 转发(0) |