YUV数据有两种方式可以显示.
1.转换成RGB然后用GDI或者DirectDraw画出来.
2.直接创建DirectDraw的YUV表面.在上面画.我的实际经历是不是所有的显卡都支持创建YUV表面的.
方案1.你自己去找YUV和RGB的转换公式.我记得DFW上也有例子代码.你自己搜索一下.
方案2.给你一些我的代码片段.如果你有一点点DirectDraw的知识.这个很容易理解.
需要JEDI翻译的DirectX9的pas头文件.
var
lpclip : IDirectDrawClipper;
Ret : HRESULT;
begin
if m_lpDD = nil then
begin
if FScreen.HasGuid then
begin
if DirectDrawCreateEx(@FScreen.GUID, m_lpDD, IID_IDirectDraw7, nil) <> DD_OK then
Exit;
end
else
begin
if DirectDrawCreateEx(nil, m_lpDD, IID_IDirectDraw7, nil) <> DD_OK then
Exit;
end;
if m_lpDD.SetCooperativeLevel(Handle, DDSCL_NORMAL) <> DD_OK then
Exit;
//注意这里
//※主表面
ZeroMemory(@m_ddsd, sizeof(DDSURFACEDESC2));
m_ddsd.dwSize := sizeof(DDSURFACEDESC2);
m_ddsd.dwFlags := DDSD_CAPS;
m_ddsd.ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;
if m_lpDD.CreateSurface(m_ddsd, m_lpDDSPrimary, nil) <> DD_OK then
Exit;
if m_lpDD.CreateClipper(0, lpclip, nil) <> DD_OK then
Exit;
if m_lpDDSPrimary.SetClipper(lpclip) <> DD_OK then
Exit;
lpclip.SetHWnd(0, Handle);
//注意这里
lpclip := nil;
BackSurface();
end;
end;
//※次表面函数:
function TDDrawItem.BackSurface(): HRESULT;
var
Ret : HRESULT;
begin
ZeroMemory(@m_ddsd, sizeof(DDSURFACEDESC2));
m_ddsd.dwSize := sizeof(DDSURFACEDESC2);
{$IFDEF useformat}
m_ddsd.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN or DDSCAPS_3DDEVICE;
// DDSCAPS_VIDEOMEMORY;
//DDSCAPS_OVERLAY DDSCAPS_OFFSCREENPLAIN;
m_ddsd.dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH or DDSD_PIXELFORMAT;
m_ddsd.dwWidth := FFormatWidth;
m_ddsd.dwHeight := FFormatHeight;
m_ddsd.ddpfPixelFormat.dwSize := sizeof(DDPIXELFORMAT);
m_ddsd.ddpfPixelFormat.dwFlags := DDPF_FOURCC or DDPF_YUV;
m_ddsd.ddpfPixelFormat.dwFourCC := MAKEFOURCC('Y', 'V', '1', '2');
m_ddsd.ddpfPixelFormat.dwYUVBitCount := 8;
{$else
}
m_ddsd.dwFlags := DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT;
m_ddsd.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN or DDSCAPS_VIDEOMEMORY or DDSCAPS_LOCALVIDMEM;
m_ddsd.dwWidth := Self.Width;
m_ddsd.dwHeight := Self.Height;
{$ENDIF}
m_lpDDSOffScr := nil;
Ret := m_lpDD.CreateSurface(m_ddsd, m_lpDDSOffScr, nil);
if Ret <> DD_OK then
begin
ShowMessage(Format('创建离屏表面失败"%x"!', [Ret]));
Exit;
end;
result := DD_OK;
end;
procedure TDDrawItem.FillYUV(lpYUV: PChar);
var
Rect, RectBack : TRect;
lpY, lpU, lpV, lpSurf: PChar;
I : integer;
value1, value2, value3, value4: Integer;
begin
if (not Self.HandleAllocated) or (m_lpDDSOffScr = nil) then
Exit;
GetWindowRect(Handle, Rect);
m_lpDDSOffScr.Lock(nil, m_ddsd, DDLOCK_WAIT or DDLOCK_WRITEONLY, 0);
//------------------------------
lpY := lpYUV;
lpU := lpYUV + FFormatUOffset;
lpV := lpYUV + FFormatVOffset;
lpSurf := m_ddsd.lpSurface;
//ZeroMemory(lpSurf, (FFormatWidth * FFormatHeight) * 3 div 2);
//-------------------填充YUV-----------------------------
{
Inc(lpSurf, FFormatWidth*Self.FYUVTop + FYUVLeft);
Inc(lpY, FFormatWidth*Self.FYUVTop);
for I := Self.FYUVTop to Self.FYUVHeight - 1do
begin
Inc(lpY, FYUVLeft);
CopyMemory(lpSurf, lpY, FYUVWidth);
Inc(lpY, FFormatWidth);
Inc(lpSurf, m_ddsd.lPitch);
end;
value1 := m_ddsd.dwHeight div 2;
value2 := m_ddsd.dwWidth div 2;
value3 := FFormatWidth div 2;
value4 := m_ddsd.lPitch div 2;
for i := 0 to value1 - 1do
begin
CopyMemory(lpSurf, lpU, value2);
Inc(lpU, value3);
Inc(lpSurf, value4);
end;
for i := 0 to value1 - 1do
begin
CopyMemory(lpSurf, lpV, value2);
Inc(lpV, value3);
Inc(lpSurf, value4);
end;
}
for I := 0 to 480 - 1do
begin
CopyMemory(lpSurf, lpY, 640);
Inc(lpY, 640);
Inc(lpSurf, m_ddsd.lPitch);
end;
value1 := m_ddsd.dwHeight div 2;
value2 := m_ddsd.dwWidth div 2;
value3 := FFormatWidth div 2;
value4 := m_ddsd.lPitch div 2;
for i := 0 to value1 - 1do
begin
CopyMemory(lpSurf, lpU, value2);
Inc(lpU, value3);
Inc(lpSurf, value4);
end;
for i := 0 to value1 - 1do
begin
CopyMemory(lpSurf, lpV, value2);
Inc(lpV, value3);
Inc(lpSurf, value4);
end;
//RectBack := Classes.Rect(0, 0, m_ddsd.dwWidth, m_ddsd.dwHeight);
RectBack := Classes.Rect(FYUVLeft, FYUVTop, FYUVWidth + FYUVLeft, FYUVHeight + FYUVTop);
OffsetRect(Rect, -FScreen.Rect.Left, -FScreen.Rect.Top);
//------------------------------
m_lpDDSOffScr.Unlock(nil);
m_lpDDSPrimary.Blt(@Rect, m_lpDDSOffScr, @RectBack, DDBLT_WAIT, nil);
end;