program VmrAlloc;
uses
Windows,
Messages,
untVideo in 'untVideo.pas';
const
AppName = 'VmrAlloctor';
var
g_video: YVideo = NIL;
g_hwnd: HWND = 0;
{$R *.RES}
procedure PaintWindow(hWnd: HWND);
var
ps: PAINTSTRUCT;
dc: HDC;
begin
dc := BeginPaint(hWnd, ps);
// if( g_mediaControl == NULL ) // we know that there is nothing loaded
{
bNeedPaint = true;
}
// else
{
// If we have a movie loaded, we only need to repaint
// when the graph is stopped
OAFilterState state;
if( SUCCEEDED( g_mediaControl->GetState(0, & state ) ) )
{
bNeedPaint = ( state == State_Stopped );
}
// }
// if ( bNeedPaint )
{
RECT rc2;
GetClientRect(hWnd, &rc2);
FillRect(hdc, &rc2, (HBRUSH)(COLOR_WINDOW+1));
}
EndPaint( hWnd, ps );
end;
function WindowProc(hWnd, uMsg, wParam, lParam: Integer): Integer; stdcall;
begin
result := 0;
case uMsg of
WM_DESTROY:
begin
PostQuitMessage(0);
Exit;
end;
WM_KEYUP:
begin
case wParam of
VK_ESCAPE: DestroyWindow(hWnd);
end;
Exit;
end;
WM_PAINT:
begin
PaintWindow(hWnd);
Exit;
end;
end;
Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
end;
function RegWindowClass(): Bool;
var
WinClass: TWndClassEx;
begin
FillChar(WinClass, sizeof(WinClass), 0);
WinClass.cbSize := sizeof(WinClass);
WinClass.style := CS_CLASSDC;
WinClass.lpfnWndProc := @WindowProc;
WinClass.hInstance := hInstance;
WinClass.lpszClassName := AppName;
WinClass.hCursor := LoadCursor(0, IDC_ARROW);
Result := RegisterClassEx(WinClass) <> 0;
end;
begin
//注册窗口类
if not RegWindowClass then
begin
MessageBox(0, 'Call RegisterClass() Failed.', AppName, MB_IConERROR);
Exit;
end;
//创建窗口
g_hwnd := CreateWindowEx(0, AppName, AppName, WS_OVERLAPPED,
0, 0, 700, 500, 0, 0, hInstance, nil);
if g_hwnd = 0 then
begin
MessageBox(0, 'Call CreateWindowEx() Failed.', AppName, MB_IConERROR);
UnregisterClass(AppName, hInstance);
Exit;
end;
//创建g_game
g_video := YVideo.Create;
//初始化g_game
if g_video.Initialise(g_hwnd, NiL)then
begin
ShowWindow( g_hwnd, SW_SHOWDEFAULT );
UpdateWindow( g_hwnd );
g_video.LoadVideoFromFile('Windows Movie Maker 样本文件.wmv');
g_video.Play();
g_video.GameLoop();
end else
begin
MessageBox(0, 'g_video.Initialise() Failed.', AppName, MB_IConERROR);
end;
//销毁g_game
g_video.Free;
UnregisterClass(AppName, hInstance);
end.
unit untVideo;
interface
uses
Windows, Messages, sysUtils, Classes, Direct3D9, D3DX9, DirectMusic, DirectShow9,
ActiveX, MultiMon, untConst;
const
PANEL_D3DFVF_CUSTOMVERTEX = D3DFVF_XYZ or D3DFVF_DIFFUSE or D3DFVF_TEX1;
type
PANEL_CUSTOMVERTEX = record
x, y, z: float;
color: DWORD;
u, v: float;
end;
PPANEL_CUSTOMVERTEX = ^PANEL_CUSTOMVERTEX;
YVideoPanel = class
public
constructor Create();
destructor Destroy; override;
function Init(d3ddev: IDirect3DDevice9):HRESULT;
function DrawScene(d3ddev: IDirect3DDevice9; texture: IDirect3DTexture9):HRESULT;
procedure UpdateVertices(fTU, fTV: FLOAT);
private
m_pVertexBuffer: IDIRECT3DVERTEXBUFFER9;
m_vertices: Array [00..3] of PANEL_CUSTOMVERTEX;
end;
//有3个成员变量需要外部传入:m_window, m_d3dDev, m_vmrSurfAllocNotify
YAllocator = class(TInterfacedObject, IVMRSurfaceAllocator9, IVMRImagePresenter9)
public
constructor Create(hwnd: HWND; d3d: IDirect3D9; d3ddd3dDev: IDIRECT3DDEVICE9; var hr: HRESULT);
destructor Destroy();override;
function CreateDevice():HRESULT;
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;
function StartPresenting(dwUserID: DWORD):HResult; stdcall;
function StopPresenting(dwUserID: DWORD):HResult; stdcall;
function PresentImage(dwUserID: DWORD; lpPresInfo: PVMR9PresentationInfo):HResult; stdcall;
{ function QueryInterface(const riid: TGUID; out ppvObject):HRESULT; stdcall;
function _AddRef():S32; stdcall;
function _Release():S32; stdcall; }
protected
procedure _DeleteSurfaces();
private
m_window: HWND;
m_d3d: IDirect3D9;
m_d3dDev: IDIRECT3DDEVICE9;
m_refCount: S32;
m_vmrSurfAllocNotify: IVMRSurfaceAllocatorNotify9;
m_privateTexture: IDirect3DTexture9;
m_d3dSurfaces: Array of IDirect3DSurface9;
m_renderTarget: IDirect3DSurface9;
m_scene: YVideoPanel;
end;
YVideo = class
public
constructor Create();
destructor Destroy();override;
function Initialise(hwnd: HWND; d3dDev: IDIRECT3DDEVICE9):BOOL;
procedure LoadVideoFromFile(sFileName: string);
procedure Play();
procedure Stop();
procedure GameLoop();
private
m_GraphBuilder: IGraphBuilder; //FILTER管理器
m_BaseFilter: IBaseFilter; //用于创建VMR9
m_MediaControl: IMediaControl; //媒体控制
m_vmrAllocator: YAllocator;
end;
implementation
var
CS_VIDEOTEXTRUE_LOCK: TRTLCriticalSection; //临界区,保证线程安全
{ YVideoPanel }
constructor YVideoPanel.Create();
begin
m_pVertexBuffer := NULL;
end;
destructor YVideoPanel.Destroy;
begin
SafeRelease(m_pVertexBuffer);
end;
function YVideoPanel.Init(d3ddev: IDirect3DDevice9):HRESULT;
var
backBuffer: IDirect3DSurface9;
backBufferDesc: D3DSURFACE_DESC;
matProj, matView: TD3DXMATRIX;
fAspect: FLOAT;
from, at, up: TD3DXVECTOR3;
begin
if( d3ddev = NULL ) then
begin
result := E_POINTER;
Exit;
end;
d3ddev.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
d3ddev.SetRenderState(D3DRS_LIGHTING, U32(FALSE));
d3ddev.SetRenderState(D3DRS_ALPHABLENDENABLE, U32(TRUE));
d3ddev.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
d3ddev.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
d3ddev.SetRenderState(D3DRS_ALPHATESTENABLE, U32(TRUE));
d3ddev.SetRenderState(D3DRS_ALPHAREF, $10);
d3ddev.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
d3ddev.SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
d3ddev.SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
d3ddev.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
d3ddev.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
d3ddev.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
m_pVertexBuffer := NULL;
d3ddev.CreateVertexBuffer(4 * sizeof(PANEL_CUSTOMVERTEX),D3DUSAGE_WRITEONLY,PANEL_D3DFVF_CUSTOMVERTEX,D3DPOOL_MANAGED,m_pvertexBuffer, NULL );
d3ddev.GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, backBuffer);
backBuffer.GetDesc( backBufferDesc);
// Set the projection matrix
//fAspect := backBufferDesc.Width / backBufferDesc.Height;
fAspect:=1.0;
D3DXMatrixPerspectiveFovLH( matProj, D3DX_PI/4, fAspect, 1.0, 500.0 );
d3ddev.SetTransform( D3DTS_PROJECTION, matProj );
from := D3DXVECTOR3( 0.0, 0.0, -9.0 );
at := D3DXVECTOR3( 0.0, 0.0, 0.0 );
up := D3DXVECTOR3( 0.0, 1.0, 0.0 );
D3DXMatrixLookAtLH(matView, from, at, up);
d3ddev.SetTransform( D3DTS_VIEW, matView );
//m_time = GetTickCount();
result := S_OK;
UpdateVertices(1.0,1.0);
end;
function YVideoPanel.DrawScene(d3ddev: IDirect3DDevice9; texture: IDirect3DTexture9):HRESULT;
begin
if( d3ddev = NULL) or( texture = NULL )then
begin
result := E_POINTER;
Exit;
end;
if( m_pvertexBuffer = NULL )then
begin
result := D3DERR_INVALIDCALL;
Exit;
end;
{
// get the difference in time
dwCurrentTime := GetTickCount();
double difference = m_time - dwCurrentTime ;
// figure out the rotation of the plane
float x = (float) ( -cos(difference / 2000.0 ) ) ;
float y = (float) ( cos(difference / 2000.0 ) ) ;
float z = (float) ( sin(difference / 2000.0 ) ) ;
// update the two rotating vertices with the new position
m_vertices[0].position = CUSTOMVERTEX::Position(x, y, z); // top left
m_vertices[3].position = CUSTOMVERTEX::Position(-x, -y, -z); // bottom right
// Adjust the color so the blue is always on the bottom.
// As the corner approaches the bottom, get rid of all the other
// colors besides blue
DWORD mask0 = (DWORD) (255 * ( ( y + 1.0 )/ 2.0 ));
DWORD mask3 = (DWORD) (255 * ( ( -y + 1.0 )/ 2.0 ));
m_vertices[0].color = 0xff0000ff | ( mask0 << 16 ) | ( mask0 << 8 );
m_vertices[3].color = 0xff0000ff | ( mask3 << 16 ) | ( mask3 << 8 );
// write the new vertex information into the buffer
void* pData;
FAIL_RET( m_vertexBuffer->Lock(0,sizeof(pData), &pData,0) );
memcpy(pData,m_vertices,sizeof(m_vertices));
FAIL_RET( m_vertexBuffer->Unlock() );
}
// clear the scene so we don't have any articats left
d3ddev.Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0, 0 );
d3ddev.BeginScene();
d3ddev.SetTexture( 0, texture);
d3ddev.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
d3ddev.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
d3ddev.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
d3ddev.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3ddev.SetStreamSource(0, m_pvertexBuffer, 0, sizeof(PANEL_CUSTOMVERTEX) ); //set next source ( NEW )
d3ddev.SetFVF( PANEL_D3DFVF_CUSTOMVERTEX );
d3ddev.DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); //draw quad
d3ddev.SetTexture( 0, NULL);
d3ddev.EndScene();
result := S_OK;
end;
procedure YVideoPanel.UpdateVertices(fTU, fTV: FLOAT);
const
W = 3.2;
H = 2.4;
var
pVertices: PPANEL_CUSTOMVERTEX;// = NULL;
begin
if m_pVertexBuffer = NULL then
Exit;
pVertices := NULL;
m_pVertexBuffer.Lock(0, 4 * sizeof(PANEL_CUSTOMVERTEX), Pointer(pVertices), 0);
//Set all the vertices to selected colour
m_Vertices[0].color := $ffffffff;
m_Vertices[1].color := $ffffffff;
m_Vertices[2].color := $ffffffff;
m_Vertices[3].color := $ffffffff;
//Set the positions of the vertices
m_Vertices[0].x := -W; m_Vertices[0].y := -H; m_Vertices[0].z := 0.0;
m_Vertices[1].x := -W; m_Vertices[1].y := +H; m_Vertices[1].z := 0.0;
m_Vertices[2].x := +W; m_Vertices[2].y := -H; m_Vertices[2].z := 0.0;
m_Vertices[3].x := +W; m_Vertices[3].y := +H; m_Vertices[3].z := 0.0;
//Set the texture coordinates of the vertices
m_Vertices[0].u := 0.0; m_Vertices[0].v := fTV;
m_Vertices[1].u := 0.0; m_Vertices[1].v := 0.0;
m_Vertices[2].u := fTU; m_Vertices[2].v := fTV;
m_Vertices[3].u := fTU; m_Vertices[3].v := 0.0;
Move(m_vertices[0], pVertices^, sizeof(m_vertices[0])*4);
m_pVertexBuffer.Unlock();
end;