private DxVBLib.DDSURFACEDESC2 m_sDDOverlayDesc;
private DxVBLib.DirectDrawSurface7 m_pDDOverlay;
private int m_colortype;
private DirectShowLib.BitmapInfoHeader m_bmpInfo;
private int m_dwRawSize;
private DxVBLib.DirectDrawSurface7 m_pDDPrimary;
private int m_width;
private int m_height;
private DxVBLib.DirectX7 m_dx = new DxVBLib.DirectX7();
private DxVBLib.DirectDraw7 m_pDD;
private RECT m_WindowRect = new RECT();
private RECT m_ClientRect = new RECT();
private int m_hRenderWnd;
private bool m_bPreview = false;
public bool m_IsOpen = true;
public VideoRenderer(int hWnd)
{
m_hRenderWnd = hWnd;
m_bmpInfo = new DirectShowLib.BitmapInfoHeader();
m_bmpInfo.Size = 0;
SetDrawScale(0, 0);
OpenDirectDraw();
}
/// <summary>
/// 是否预览
/// </summary>
public bool IsPreview
{
set { m_bPreview = value;}
get { return m_bPreview; }
}
public void CreateLiveWindow(int nChroma, int width, int height)
{
DirectShowLib.BitmapInfoHeader bmpFormat = new DirectShowLib.BitmapInfoHeader();
bmpFormat.Width = width;
bmpFormat.Height = height;
bmpFormat.Planes = 1;
m_width = width;
m_height = height;
if (nChroma == 0)
{
bmpFormat.BitCount = (short)32;
bmpFormat.Compression = GetColorTypeValue("2YUY");
}
else if(nChroma == 1)
{
bmpFormat.BitCount = (short)16;
bmpFormat.Compression = GetColorTypeValue("2YUY");
}
else if (nChroma == GetColorTypeValue("024I"))
{
bmpFormat.BitCount = (short)12;
bmpFormat.Compression = GetColorTypeValue("024I");
}
else if (nChroma == GetColorTypeValue("21VY"))
{
bmpFormat.BitCount = (short)12;
bmpFormat.Compression = GetColorTypeValue("21VY");
}
else
{
bmpFormat.BitCount = (short)32;
}
bmpFormat.ImageSize = bmpFormat.Width * bmpFormat.Height * bmpFormat.BitCount / 8;
OpenVideoRender(bmpFormat);
}
public bool OpenDirectDraw()
{
bool bSuccess = false;
m_pDD = m_dx.DirectDrawCreate("");
if (m_pDD != null)
{
// Request normal cooperative level to put us in windowed mode
m_pDD.SetCooperativeLevel(m_hRenderWnd, CONST_DDSCLFLAGS.DDSCL_NORMAL);
bSuccess = true;
// Create primary surface
DDSURFACEDESC2 m_sDDPrimaryDesc = new DDSURFACEDESC2();
m_sDDPrimaryDesc.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS;
m_sDDPrimaryDesc.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE;
m_pDDPrimary = m_pDD.CreateSurface(ref m_sDDPrimaryDesc);
if (m_pDDPrimary != null)
{
DirectDrawClipper pDDClipper = null;
pDDClipper = m_pDD.CreateClipper(0);
if (pDDClipper == null)
return true;
pDDClipper.SetHWnd(m_hRenderWnd);
m_pDDPrimary.SetClipper(pDDClipper);
}
}
return bSuccess;
}
public bool OpenVideoRender(DirectShowLib.BitmapInfoHeader pbmphInfo)
{
bool bSuccess = false;
//CloseVideoRender();
int dwWidth = pbmphInfo.Width;
int dwHeight = pbmphInfo.Height;
int dwBitCount = pbmphInfo.BitCount;
int dwFourCC = pbmphInfo.Compression;
m_colortype = dwFourCC;
m_bmpInfo = pbmphInfo;
m_dwRawSize = dwWidth * ((dwBitCount + 1) / 8);
m_bmpInfo.ImageSize = m_dwRawSize * dwHeight;
m_ClientRect.Left = 0;
m_ClientRect.Top = 0;
m_ClientRect.Right = dwWidth;
m_ClientRect.Bottom = dwHeight;
if (m_pDDPrimary != null)
{
DDCAPS sDDHalCaps = new DDCAPS();
DDCAPS sDDHalCaps2 = new DDCAPS ();
//m_pDD.GetCaps(ref sDDHalCaps,null);
m_pDD.GetCaps(ref sDDHalCaps, ref sDDHalCaps2);
m_sDDOverlayDesc = new DDSURFACEDESC2();
m_sDDOverlayDesc.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT;
m_sDDOverlayDesc.lWidth = dwWidth;
m_sDDOverlayDesc.lHeight = dwHeight;
sDDHalCaps.lCaps = CONST_DDCAPS1FLAGS.DDCAPS_OVERLAY;
m_sDDOverlayDesc.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN
| CONST_DDSURFACECAPSFLAGS.DDSCAPS_LIVEVIDEO
| CONST_DDSURFACECAPSFLAGS.DDSCAPS_VIDEOMEMORY
| CONST_DDSURFACECAPSFLAGS.DDSCAPS_NONLOCALVIDMEM
;
DDPIXELFORMAT ddPixelFormat = new DDPIXELFORMAT();
if (dwFourCC != 0)//BI_RGB
{
// FOURCC need HARDWARE support (VideoMem)
m_sDDOverlayDesc.lFlags |= CONST_DDSURFACEDESCFLAGS.DDSD_PIXELFORMAT;
m_sDDOverlayDesc.ddsCaps.lCaps &= ~CONST_DDSURFACECAPSFLAGS.DDSCAPS_NONLOCALVIDMEM;
m_sDDOverlayDesc.ddsCaps.lCaps |= CONST_DDSURFACECAPSFLAGS.DDSCAPS_HWCODEC;
ddPixelFormat.lFlags = CONST_DDPIXELFORMATFLAGS.DDPF_FOURCC;
ddPixelFormat.lFourCC = dwFourCC;
ddPixelFormat.lYUVBitCount = 16;//dwBitCount;
if (dwFourCC == GetColorTypeValue("VNUY") || dwFourCC == GetColorTypeValue("224V") || dwFourCC == GetColorTypeValue("2YUY")
|| dwFourCC == GetColorTypeValue("YVYU") || dwFourCC == GetColorTypeValue("UYVY"))
{
ddPixelFormat.lFourCC = GetColorTypeValue("2YUY");
}
else if (dwFourCC == GetColorTypeValue("024I") ||dwFourCC == GetColorTypeValue("21VY") ||dwFourCC == GetColorTypeValue("P14Y"))
{
ddPixelFormat.lFourCC = GetColorTypeValue("21VY");
}
//else if (dwFourCC == BI_BITFIELDS)//BI_BITFIELDS
//{
// ddPixelFormat.lFourCC = GetColorTypeValue("21VY");
//}
}
else
{
if ((m_sDDOverlayDesc.ddsCaps.lCaps & CONST_DDSURFACECAPSFLAGS.DDSCAPS_OVERLAY) == 0)
{
m_sDDOverlayDesc.ddsCaps.lCaps &= ~CONST_DDSURFACECAPSFLAGS.DDSCAPS_NONLOCALVIDMEM;
}
else
{
m_sDDOverlayDesc.ddsCaps.lCaps |= CONST_DDSURFACECAPSFLAGS.DDSCAPS_NONLOCALVIDMEM;
}
ddPixelFormat.lFlags = CONST_DDPIXELFORMATFLAGS.DDPF_RGB;
ddPixelFormat.lRGBBitCount = dwBitCount;
switch (dwBitCount)
{
case 16: // 16-bit RGB 5:6:5
break;
case 15: // 16-bit RGB 5:5:5
break;
}
}
m_sDDOverlayDesc.ddpfPixelFormat = ddPixelFormat;
// Default is NonLocal VideoMem (AGP)
m_pDDOverlay = m_pDD.CreateSurface(ref m_sDDOverlayDesc);
if (bSuccess = (m_pDDOverlay != null)) { }
else
return false;
// try to Local VideoMem (Hardware)
if (!bSuccess && ((m_sDDOverlayDesc.ddsCaps.lCaps & CONST_DDSURFACECAPSFLAGS.DDSCAPS_NONLOCALVIDMEM) == 0))
{
m_sDDOverlayDesc.ddsCaps.lCaps &= ~CONST_DDSURFACECAPSFLAGS.DDSCAPS_NONLOCALVIDMEM;
m_pDDOverlay = m_pDD.CreateSurface(ref m_sDDOverlayDesc);
}
// try to SystemMem (Software)
if (!bSuccess && ((m_sDDOverlayDesc.ddsCaps.lCaps & CONST_DDSURFACECAPSFLAGS.DDSCAPS_VIDEOMEMORY) == 0))
{
m_sDDOverlayDesc.ddsCaps.lCaps &= ~CONST_DDSURFACECAPSFLAGS.DDSCAPS_VIDEOMEMORY;
m_sDDOverlayDesc.ddsCaps.lCaps |= CONST_DDSURFACECAPSFLAGS.DDSCAPS_SYSTEMMEMORY;
m_pDDOverlay = m_pDD.CreateSurface(ref m_sDDOverlayDesc);
}
}
return bSuccess;
}
public unsafe void DrawVideo(byte* pFrame,int datalen)
{
RECT rcClient = new RECT();
m_pDDOverlay.Lock(ref rcClient, ref m_sDDOverlayDesc, DxVBLib.CONST_DDLOCKFLAGS.DDLOCK_SURFACEMEMORYPTR | DxVBLib.CONST_DDLOCKFLAGS.DDLOCK_WAIT, 0);
if (m_bmpInfo.Compression != 0)//BI_RGB
{
byte* dst = (byte*)m_sDDOverlayDesc.lpSurface;
byte* lpY = (byte*)pFrame;
byte* lpU = null;
byte* lpV = null;
if(m_colortype == GetColorTypeValue("024I"))
{
lpU = (byte*)pFrame + m_width * m_height;
lpV = (byte*)pFrame + m_width * m_height * 5 / 4;
}
if (m_colortype == GetColorTypeValue("21VY"))//'21VY'
{
lpV = (byte*)pFrame + m_width * m_height;
lpU = (byte*)pFrame + m_width * m_height * 5 / 4;
}
byte* lpSurf = (byte*)m_sDDOverlayDesc.lpSurface;
uint i = 0;
if (lpSurf != null)
{
// fill Y data
lpY += 0;
for (i = 0; i < m_sDDOverlayDesc.lHeight; i++)
{
memcpy(lpSurf, lpY, m_sDDOverlayDesc.lWidth);
lpY += m_width;
lpSurf += m_sDDOverlayDesc.lPitch;
}
//fill V data
lpY += 0 * m_width / 4 + 0 / 2;
for (i = 0; i < m_sDDOverlayDesc.lHeight / 2; i++)
{
memcpy(lpSurf, lpV, m_sDDOverlayDesc.lWidth / 2);
lpV += m_width / 2;
lpSurf += m_sDDOverlayDesc.lPitch / 2;
}
//fill U data
lpU += 0 * m_width / 4 + 0 / 2;
for (i = 0; i < m_sDDOverlayDesc.lHeight / 2; i++)
{
//printf("lpSurf = %p, lines=%d, copy V/n", lpSurf, m_sDDOverlayDesc.lHeight / 2);
memcpy(lpSurf, lpU, m_sDDOverlayDesc.lWidth / 2);
//printf("lpSurf = %p, copy V ok, line %d/n", lpSurf, i);
lpU += m_width / 2;
lpSurf += m_sDDOverlayDesc.lPitch / 2;
}
}
}
else // RGBA
{
}
m_pDDOverlay.Unlock(ref m_ClientRect);
UpdateDisplay();
}
void SetDrawScale(float fScaleHor, float fScaleVer)
{
RECT rcClient = new RECT ();
m_dx.GetWindowRect(m_hRenderWnd, ref rcClient);
if (m_bmpInfo.Size > 0)
{
m_bmpInfo.Width = rcClient.Right;
m_bmpInfo.Height = rcClient.Bottom;
}
if (fScaleHor >= 0)
{
m_WindowRect.Right = (int)((float)m_bmpInfo.Width * fScaleHor);
}
else
{
// Fit for Window
// Dst: Window Rect All
m_WindowRect.Right = rcClient.Right;
}
if (fScaleVer > 0)
{
m_WindowRect.Bottom = (int)((float)m_bmpInfo.Height * fScaleVer);
}
else
{
// Fit for Window
// Dst: Window Rect All
m_WindowRect.Bottom = rcClient.Bottom;
}
// If window rect large than the displayed Bmp, replace it.
if (rcClient.Right == m_WindowRect.Right)
{
m_WindowRect.Left = 0;
}
else
{
m_WindowRect.Left = (rcClient.Right - m_WindowRect.Right) >> 1;
}
if (rcClient.Bottom == m_WindowRect.Bottom)
{
m_WindowRect.Top = 0;
}
else
{
m_WindowRect.Top = (rcClient.Bottom - m_WindowRect.Bottom) >> 1;
}
UpdateDisplay();
}
#region C# 下内存拷贝(unsafe)
unsafe void* memcpy(void* pvTo, void* pvFrom, int size)
{
byte* pbTo = (byte*)pvTo; // 防止改变pvTo的地址
byte* pbFrom = (byte*)pvFrom; // 防止改变pvFrom的地址
while (size-- > 0)
*pbTo++ = *pbFrom++;
return pvTo;
}
#endregion
#region 显示视频图像
void UpdateDisplay()
{
//printf("-------------------- UpdateDisplay --------------------/n");
if (m_pDDPrimary != null && m_pDDOverlay != null)
{
RECT rcWin = new RECT();
m_dx.GetWindowRect(m_hRenderWnd, ref rcWin); // Dst Window
if ((m_sDDOverlayDesc.ddsCaps.lCaps & CONST_DDSURFACECAPSFLAGS.DDSCAPS_OVERLAY) != 0)
{
m_pDDOverlay.UpdateOverlay(ref m_ClientRect, // src
m_pDDPrimary, // dest surface
ref rcWin, // dest rect
CONST_DDOVERFLAGS.DDOVER_SHOW | CONST_DDOVERFLAGS.DDOVER_DDFX
| CONST_DDOVERFLAGS.DDOVER_KEYDESTOVERRIDE);
}
else
{
//DirectDrawSurface7 dDsurfaceSec = m_pDD.CreateSurfaceFromFile("c://3.bmp", ref m_sDDOverlayDesc);
m_pDDPrimary.Blt(ref rcWin, m_pDDOverlay, ref m_ClientRect, CONST_DDBLTFLAGS.DDBLT_ASYNC);
}
m_IsOpen = true;
}
}
#endregion
//附上效果图