?? allocator.pas
字號(hào):
//------------------------------------------------------------------------------
// File: Allocator.h & Allocator.cpp
//
// Desc: DirectShow sample code - interface for the TAllocator class
//
// Portions created by Microsoft are
// Copyright (C) 2002 Microsoft Corporation.
// All Rights Reserved.
//
// The initial developer of the Pascal code is Henri GOURVEST
// Email : hgourvest@progdigy.com
// WebSite : http://www.progdigy.com
//------------------------------------------------------------------------------
unit Allocator;
interface
uses Windows, DirectShow9, Direct3D9, SyncObjs, PlaneScene, DSPack;
type
TAllocator = class(TAbstractAllocator, IVMRSurfaceAllocator9, IVMRImagePresenter9)
private
// needed to make this a thread safe object
FObjectLock : TCriticalSection;
Fwindow : HWND;
FD3D : IDirect3D9;
FD3DDev : IDirect3DDevice9;
FlpIVMRSurfAllocNotify : IVMRSurfaceAllocatorNotify9;
Fsurfaces : array of IDirect3DSurface9;
FrenderTarget : IDirect3DSurface9;
FprivateTexture : IDirect3DTexture9;
Fscene : TPlaneScene;
protected
function CreateDevice: HResult;
// a helper function to erase every surface in the vector
procedure DeleteSurfaces;
function NeedToHandleDisplayChange: bool;
// This function is here so we can catch the loss of surfaces.
// All the functions are using the FAIL_RET macro so that they exit
// with the last error code. When this returns with the surface lost
// error code we can restore the surfaces.
function PresentHelper(lpPresInfo: PVMR9PresentationInfo): HRESULT;
public
constructor Create(out hr: HResult; wnd: THandle; d3d: IDirect3D9 = nil; d3dd: IDirect3DDevice9 = nil); override;
destructor Destroy; override;
// IVMRSurfaceAllocator9
function InitializeDevice(dwUserID: DWORD; lpAllocInfo: PVMR9AllocationInfo;
var lpNumBuffers: DWORD): HResult; stdcall;
function TerminateDevice(dwID: DWORD): HResult; stdcall;
function GetSurface(dwUserID: DWORD; SurfaceIndex: DWORD; SurfaceFlags: DWORD;
out lplpSurface: IDirect3DSurface9): HResult; stdcall;
function AdviseNotify(lpIVMRSurfAllocNotify: IVMRSurfaceAllocatorNotify9): HResult; stdcall;
// IVMRImagePresenter9
function StartPresenting(dwUserID: DWORD): HResult; stdcall;
function StopPresenting(dwUserID: DWORD): HResult; stdcall;
function PresentImage(dwUserID: DWORD; lpPresInfo: PVMR9PresentationInfo): HResult; stdcall;
end;
implementation
{ TAllocator }
function TAllocator.AdviseNotify(
lpIVMRSurfAllocNotify: IVMRSurfaceAllocatorNotify9): HResult;
var
hr: HResult;
AMonitor: HMONITOR;
function FailRet(hr: HResult): boolean;
begin
AdviseNotify := hr;
Result := Failed(hr);
end;
begin
FObjectLock.Enter;
try
FlpIVMRSurfAllocNotify := lpIVMRSurfAllocNotify;
AMonitor := FD3D.GetAdapterMonitor(D3DADAPTER_DEFAULT);
hr := FlpIVMRSurfAllocNotify.SetD3DDevice(FD3DDev, AMonitor);
result := hr;
finally
FObjectLock.Leave;
end;
end;
constructor TAllocator.Create(out hr: HResult; wnd: THandle; d3d: IDirect3D9 = nil; d3dd: IDirect3DDevice9 = nil);
begin
FD3D := d3d;
FD3DDev := d3dd;
Fwindow := wnd;
Fscene := TPlaneScene.Create;
FObjectLock := TCriticalSection.Create;
FObjectLock.Enter;
try
hr := E_FAIL;
if not IsWindow(wnd) then
begin
hr := E_INVALIDARG;
exit;
end;
if (FD3D = nil) then
begin
ASSERT(d3dd = nil);
FD3D := Direct3DCreate9(D3D_SDK_VERSION);
if (FD3D = nil) then
begin
hr := E_FAIL;
exit;
end;
end;
if (FD3DDev = nil) then
hr := CreateDevice;
finally
FObjectLock.Leave;
end;
end;
function TAllocator.CreateDevice: HResult;
var
dm: TD3DDisplayMode;
pp: TD3DPresentParameters;
function FailRet(hr: HResult): boolean;
begin
CreateDevice := hr;
Result := Failed(hr);
end;
begin
// HRESULT hr;
FD3DDev := nil;
result := FD3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, dm);
ZeroMemory(@pp, sizeof(pp));
pp.Windowed := TRUE;
pp.hDeviceWindow := Fwindow;
pp.SwapEffect := D3DSWAPEFFECT_COPY;
pp.BackBufferFormat := dm.Format;
if FailRet(FD3D.CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
Fwindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING or
D3DCREATE_MULTITHREADED,
@pp,
FD3DDev)) then exit;
FrenderTarget := nil;
Result := FD3DDev.GetRenderTarget(0, FrenderTarget);
end;
procedure TAllocator.DeleteSurfaces;
var i: integer;
begin
FObjectLock.Enter;
try
// clear out the private texture
FprivateTexture := nil;
for i := 0 to Length(FSurfaces) - 1 do
FSurfaces[i] := nil;
finally
FObjectLock.Leave;
end;
end;
destructor TAllocator.Destroy;
begin
DeleteSurfaces;
Fscene.Free;
FObjectLock.Destroy;
inherited;
end;
function TAllocator.GetSurface(dwUserID, SurfaceIndex, SurfaceFlags: DWORD;
out lplpSurface: IDirect3DSurface9): HResult;
begin
if (@lplpSurface = nil) then
begin
result := E_POINTER;
Exit;
end;
if (SurfaceIndex >= Cardinal(Length(Fsurfaces))) then
begin
result := E_FAIL;
Exit;
end;
FObjectLock.Enter;
try
try
lplpSurface := Fsurfaces[SurfaceIndex];
result := S_OK;
except
result := E_FAIL;
end;
finally
FObjectLock.Leave;
end;
end;
function TAllocator.InitializeDevice(dwUserID: DWORD;
lpAllocInfo: PVMR9AllocationInfo; var lpNumBuffers: DWORD): HResult;
var
d3dcaps: TD3DCaps9;
dwWidth: DWORD;
dwHeight: DWORD;
fTU: Single;
fTV: Single;
hr: HRESULT;
dm: TD3DDisplayMode;
function FailRet(hr: HResult): boolean;
begin
InitializeDevice := hr;
Result := Failed(hr);
end;
begin
dwWidth := 1;
dwHeight := 1;
if (lpNumBuffers = 0) then
begin
Result := E_POINTER;
Exit;
end;
if (FlpIVMRSurfAllocNotify = nil) then
begin
result := E_FAIL;
Exit;
end;
FD3DDev.GetDeviceCaps(d3dcaps);
if LongBool(d3dcaps.TextureCaps and D3DPTEXTURECAPS_POW2) then
begin
while (dwWidth < lpAllocInfo.dwWidth) do
dwWidth := dwWidth shl 1;
while (dwHeight < lpAllocInfo.dwHeight) do
dwHeight := dwHeight shl 1;
fTU := (lpAllocInfo.dwWidth) / (dwWidth);
fTV := (lpAllocInfo.dwHeight) / (dwHeight);
Fscene.SetSrcRect(fTU, fTV);
lpAllocInfo.dwWidth := dwWidth;
lpAllocInfo.dwHeight := dwHeight;
end;
// NOTE:
// we need to make sure that we create textures because
// surfaces can not be textured onto a primitive.
lpAllocInfo.dwFlags := lpAllocInfo.dwFlags or VMR9AllocFlag_TextureSurface;
DeleteSurfaces;
SetLength(Fsurfaces, lpNumBuffers);
hr := FlpIVMRSurfAllocNotify.AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, Fsurfaces[0]);
// If we couldn't create a texture surface and
// the format is not an alpha format,
// then we probably cannot create a texture.
// So what we need to do is create a private texture
// and copy the decoded images onto it.
if (FAILED(hr) and not LongBool(lpAllocInfo.dwFlags and VMR9AllocFlag_3DRenderTarget)) then
begin
DeleteSurfaces;
// is surface YUV ?
if (lpAllocInfo.Format > D3DFMT_UNKNOWN) then
begin
if FailRet(FD3DDev.GetDisplayMode(0, dm)) then exit;
// create the private texture
if FailRet(FD3DDev.CreateTexture(lpAllocInfo.dwWidth, lpAllocInfo.dwHeight,
1,
D3DUSAGE_RENDERTARGET,
dm.Format,
D3DPOOL_DEFAULT, // default pool - usually video memory
FprivateTexture, nil)) then exit;
end;
lpAllocInfo.dwFlags := lpAllocInfo.dwFlags and not VMR9AllocFlag_TextureSurface;
lpAllocInfo.dwFlags := lpAllocInfo.dwFlags or VMR9AllocFlag_OffscreenSurface;
if FailRet(FlpIVMRSurfAllocNotify.AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, Fsurfaces[0])) then exit;
end;
Result := Fscene.Init(FD3DDev);
end;
function TAllocator.NeedToHandleDisplayChange: bool;
var
Parameters: TD3DDeviceCreationParameters;
currentMonitor, AMonitor: HMONITOR;
begin
if (FlpIVMRSurfAllocNotify <> nil) then
begin
result := false;
exit;
end;
if (Failed(FD3DDev.GetCreationParameters(Parameters))) then
begin
Assert(false);
result := false;
exit;
end;
currentMonitor := FD3D.GetAdapterMonitor(Parameters.AdapterOrdinal);
AMonitor := FD3D.GetAdapterMonitor(D3DADAPTER_DEFAULT);
result := AMonitor <> currentMonitor;
end;
function TAllocator.PresentHelper(
lpPresInfo: PVMR9PresentationInfo): HRESULT;
var
surface: IDirect3DSurface9;
texture: IDirect3DTexture9;
function FailRet(hr: HResult): boolean;
begin
PresentHelper := hr;
Result := Failed(hr);
end;
begin
// parameter validation
if (lpPresInfo = nil) then
begin
result := E_POINTER;
exit;
end else
if (lpPresInfo.lpSurf = nil) then
begin
result := E_POINTER;
exit;
end;
FObjectLock.Enter;
try
FD3DDev.SetRenderTarget(0, FrenderTarget);
// if we created a private texture
// blt the decoded image onto the texture.
if(FprivateTexture <> nil) then
begin
if FailRet(FprivateTexture.GetSurfaceLevel(0 , surface)) then exit;
// copy the full surface onto the texture's surface
if FailRet(FD3DDev.StretchRect(lpPresInfo.lpSurf, nil,
surface, nil,
D3DTEXF_NONE)) then exit;
if FailRet(Fscene.DrawScene(FD3DDev, FprivateTexture)) then exit;
end
else // this is the case where we have got the textures allocated by VMR
// all we need to do is to get them from the surface
begin
if FailRet(lpPresInfo.lpSurf.GetContainer(IID_IDirect3DTexture9, Pointer(texture))) then exit;
if FailRet(Fscene.DrawScene(FD3DDev, texture)) then exit;
end;
if FailRet(FD3DDev.Present(nil, nil, 0, nil)) then exit;
// result := hr;
finally
Pointer(texture) := nil;
FObjectLock.leave;
end;
end;
function TAllocator.PresentImage(dwUserID: DWORD;
lpPresInfo: PVMR9PresentationInfo): HResult;
var
hr: HRESULT;
AMonitor: HMONITOR;
function FailRet(hr: HResult): boolean;
begin
PresentImage := hr;
Result := Failed(hr);
end;
begin
FObjectLock.Enter;
try
// if we are in the middle of the display change
if NeedToHandleDisplayChange then
begin
// NOTE: this piece of code is left as a user exercise.
// The D3DDevice here needs to be switched
// to the device that is using another adapter
end;
hr := PresentHelper(lpPresInfo);
// IMPORTANT: device can be lost when user changes the resolution
// or when (s)he presses Ctrl + Alt + Delete.
// We need to restore our video memory after that
if (hr = D3DERR_DEVICELOST) then
begin
if (FD3DDev.TestCooperativeLevel = D3DERR_DEVICENOTRESET) then
begin
DeleteSurfaces;
if FailRet(CreateDevice) then exit;
AMonitor := FD3D.GetAdapterMonitor(D3DADAPTER_DEFAULT);
if FailRet(FlpIVMRSurfAllocNotify.ChangeD3DDevice(FD3DDev, AMonitor)) then exit;
end;
hr := S_OK;
end;
result := hr;
finally
FObjectLock.Leave;
end;
end;
function TAllocator.StartPresenting(dwUserID: DWORD): HResult;
begin
FObjectLock.Enter;
try
ASSERT(assigned(FD3DDev));
if (FD3DDev = nil) then
begin
result := E_FAIL;
exit;
end;
result := S_OK;
finally
FObjectLock.Leave;
end;
end;
function TAllocator.StopPresenting(dwUserID: DWORD): HResult;
begin
result := S_OK;
end;
function TAllocator.TerminateDevice(dwID: DWORD): HResult;
begin
DeleteSurfaces;
result := S_OK;
end;
end.
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -