再给你我以前的代码你参考吧.
我这个代码是枚举监视器.创建一个主表面和一个从表面.表面的格式是YVU格式的.
然后把YUV视频帧拷贝到从表面的显存缓冲区.然后由从表面直接画到主表面.
你要的创建Surface就是这样的.但你要正常画图的话则不要指定YUV格式即可.
unit UnitDDrawPanel;
interface
uses
Windows, Classes, SysUtils, Forms, Messages, MultiMon, DirectDraw,
Controls, Graphics, Dialogs;
type
TMMonitor = class(TComponent)
private
FIsDefault: Boolean;
FGUID: TGUID;
FRect: TRect;
FDriverDescription: string;
FDriverName: string;
public
property Rect: TRect read FRect;
end;
TDDrawPanel = class;
TDDrawItem = class(TCustomControl)
private
FMonitor: TMMonitor;
FId: Integer;
FPanleOnwer: TDDrawPanel;
FFormatWidth: Integer;
FFormatHeight: Integer;
FYUVLeft: Integer;
FYUVTop: Integer;
FYUVWidth: Integer;
FYUVHeight: Integer;
private
FFormatSize: Integer;
FFormatUOffset: Integer;
FFormatVOffset: Integer;
//-----------------------
m_lpDD: IDirectDraw7;
m_lpDDSPrimary: IDirectDrawSurface7;
m_lpDDSOffScr: IDirectDrawSurface7;
m_ddsd: TDDSurfaceDesc2;
protected
public
constructor Create(AOwner: TDDrawPanel;
AMonitor: TMMonitor);
destructor Destroy;
override;
procedure Init();
procedure FillYUV(lpYUV: PChar);
function BackSurface(): HRESULT;
procedure SetBounds(ALeft: Integer;
ATop: Integer;
AWidth: Integer;
AHeight: Integer);
override;
end;
TItems = array of TDDrawItem;
TDDrawPanel = class(TForm)
private
FItems: TItems;
FFormatWidth: Integer;
FFormatHeight: Integer;
protected
procedure CreateParams(var Params: TCreateParams);
override;
procedure Clear();
procedure WMActivate(var Message: TWMActivate);
message WM_ACTIVATE;
public
constructor Create(AOwner: TComponent;
AFormatWidth, AFormatHeight: Integer);
destructor Destroy;
override;
public
property Items: TItems read FItems write FItems;
end;
var
MonitorCount : Integer;
Monitors : array of TMMonitor;
//初始化屏幕
procedure InitScreen();
stdcall;
implementation
function DDEnumCallbackEx(lpGUID: PGUID;
lpDriverDescription: PAnsiChar;
lpDriverName: PAnsiChar;
lpContext: Pointer;
Monitor: HMonitor): BOOL;
stdcall;
var
MM : TMMonitor;
mi : TMonitorInfoEx;
begin
MM := TMMonitor.Create(Application);
MM.FIsDefault := lpGUID = nil;
if MM.FIsDefault then
begin
MM.FRect := Rect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
MM.FDriverDescription := lpDriverDescription;
MM.FDriverName := lpDriverName;
end
else
begin
mi.cbSize := SizeOf(TMonitorInfoEx);
GetMonitorInfo(Monitor, @mi);
MM.FGUID := lpGUID^;
MM.FRect := mi.rcMonitor;
MM.FDriverDescription := lpDriverDescription;
MM.FDriverName := lpDriverName;
end;
Inc(MonitorCount);
Result := TRUE;
end;
procedure InitScreen();
procedure Clear();
var
I : Integer;
begin
Monitors := nil;
for I := Application.ComponentCount - 1do
wnto 0do
if Application.Components is TMMonitor then
Application.Components.Free;
end;
var
I, J : Integer;
begin
Clear();
MonitorCount := 0;
DirectDrawEnumerateEx(@DDEnumCallbackEx,
nil,
DDENUM_ATTACHEDSECONDARYDEVICES or DDENUM_NONDISPLAYDEVICES
);
if MonitorCount = 1 then
begin
SetLength(Monitors, MonitorCount);
for I := Application.ComponentCount - 1do
wnto 0do
if (Application.Components is TMMonitor) and
TMMonitor(Application.Components).FIsDefault then
begin
Monitors[0] := TMMonitor(Application.Components);
Break;
end;
end
else
begin
SetLength(Monitors, MonitorCount - 1);
J := 0;
for I := Application.ComponentCount - 1do
wnto 0do
if (Application.Components is TMMonitor) and
(not TMMonitor(Application.Components).FIsDefault) then
begin
Monitors[J] := TMMonitor(Application.Components);
Inc(J);
end;
end;
end;
{ TDDrawPanel }
procedure TDDrawPanel.Clear;
var
I : Integer;
begin
if Length(FItems) = 0 then
Exit;
for I := High(FItems) to Low(FItems)do
begin
FItems.Free;
FItems := nil;
end;
end;
constructor TDDrawPanel.Create(AOwner: TComponent;
AFormatWidth, AFormatHeight: Integer);
var
SCount : Integer;
begin
inherited CreateNew(AOwner);
FFormatWidth := AFormatWidth;
FFormatHeight := AFormatHeight;
SCount := Length(Monitors);
if SCount > 0 then
begin
SetLength(FItems, SCount);
ZeroMemory(@FItems[0], Length(FItems));
end;
end;
procedure TDDrawPanel.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style and (not WS_CHILD);
end;
destructor TDDrawPanel.Destroy;
begin
Clear();
inherited Destroy;
end;
procedure TDDrawPanel.WMActivate(var Message: TWMActivate);
var
PH : HWND;
begin
if Self.HandleAllocated() and Visible then
SetActiveWindow(GetParent(Self.Handle));
end;
{ TDDrawItem }
function TDDrawItem.BackSurface: HRESULT;
var
Ret : HRESULT;
begin
ZeroMemory(@m_ddsd, sizeof(DDSURFACEDESC2));
m_ddsd.dwSize := sizeof(DDSURFACEDESC2);
m_ddsd.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN or 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;
m_lpDDSOffScr := nil;
Ret := m_lpDD.CreateSurface(m_ddsd, m_lpDDSOffScr, nil);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
result := DD_OK;
end;
constructor TDDrawItem.Create(AOwner: TDDrawPanel;
AMonitor: TMMonitor);
var
I : Integer;
begin
inherited Create(AOwner);
FPanleOnwer := AOwner;
FMonitor := AMonitor;
FFormatWidth := FPanleOnwer.FFormatWidth;
FFormatHeight := FPanleOnwer.FFormatHeight;
FFormatSize := FFormatWidth * FFormatHeight;
FFormatUOffset := FFormatSize;
FFormatVOffset := FFormatSize + (FFormatSize shr 2);
FId := -1;
for I := Low(Monitors) to High(Monitors)do
if Monitors = AMonitor then
begin
FId := I;
Break;
end;
{
case FId of
0:
Color := clYellow;
1:
Color := clRed;
2:
Color := clBlack;
3:
Color := clWhite;
end;
}
Color := clBlack;
end;
destructor TDDrawItem.Destroy;
begin
inherited Destroy;
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 FFormatHeight - 1do
begin
CopyMemory(lpSurf, lpY, FFormatWidth);
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;
//RectBack := Classes.Rect(0, 0, m_ddsd.dwWidth, m_ddsd.dwHeight);
RectBack := Classes.Rect(FYUVLeft, FYUVTop, FYUVWidth + FYUVLeft, FYUVHeight + FYUVTop);
OffsetRect(Rect, -FMonitor.FRect.Left, -FMonitor.FRect.Top);
//------------------------------
m_lpDDSOffScr.Unlock(nil);
m_lpDDSPrimary.Blt(@Rect, m_lpDDSOffScr, @RectBack, DDBLT_WAIT, nil);
end;
procedure TDDrawItem.Init;
var
lpclip : IDirectDrawClipper;
Ret : HRESULT;
begin
if m_lpDD = nil then
begin
if not FMonitor.FIsDefault then
begin
Ret := DirectDrawCreateEx(@FMonitor.FGUID, m_lpDD, IID_IDirectDraw7, nil);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
end
else
begin
Ret := DirectDrawCreateEx(nil, m_lpDD, IID_IDirectDraw7, nil);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
end;
Ret := m_lpDD.SetCooperativeLevel(Handle, DDSCL_NORMAL);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
//※主表面
ZeroMemory(@m_ddsd, sizeof(DDSURFACEDESC2));
m_ddsd.dwSize := sizeof(DDSURFACEDESC2);
m_ddsd.dwFlags := DDSD_CAPS;
m_ddsd.ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;
//------------------------------
Ret := m_lpDD.CreateSurface(m_ddsd, m_lpDDSPrimary, nil);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
Ret := m_lpDD.CreateClipper(0, lpclip, nil);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
Ret := m_lpDDSPrimary.SetClipper(lpclip);
if Ret <> DD_OK then
begin
ShowMessage(DDErrorString(Ret));
Exit;
end;
lpclip.SetHWnd(0, Handle);
//注意这里
lpclip := nil;
BackSurface();
end;
end;
procedure TDDrawItem.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
FYUVLeft := Trunc(Left / FPanleOnwer.Width * FFormatWidth);
FYUVTop := Trunc(Top / FPanleOnwer.Height * FFormatHeight);
FYUVWidth := Trunc(Width / FPanleOnwer.Width * FFormatWidth);
FYUVHeight := Trunc(Height / FPanleOnwer.Height * FFormatHeight);
end;
end.