?? uasyncrdr.pas
字號:
//------------------------------------------------------------------------------
// File: UAsyncRdr.pas
// Original files: asyncrdr.h, asyncrdr.c
//
// Desc: Defines an IO source filter.
//
// This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the
// filter object itself. It has a single output pin (CAsyncOutputPin)
// which supports IPin and IAsyncReader.
//
// This filter is essentially a wrapper for the CAsyncFile class that does
// all the work.
//
//
// Portions created by Microsoft are
// Copyright (c) 2000-2002 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
unit UAsyncRdr;
interface
uses
BaseClass, DirectShow9, DSUtil, ActiveX, Windows, SysUtils,
UAsyncIo;
const
CLSID_AsyncSample: TGUID = '{10F9E8F1-FE54-470C-9F1A-FE587DF7BD0B}';
type
// the filter class (defined below)
TBCAsyncReader = class;
// the output pin class
TBCAsyncOutputPin = class(TBCBasePin, IAsyncReader)
protected
FReader: TBCAsyncReader;
FIo: TBCAsyncIo;
// This is set every time we're asked to return an IAsyncReader
// interface
// This allows us to know if the downstream pin can use
// this transport, otherwise we can hook up to thinks like the
// dump filter and nothing happens
FQueriedForAsyncReader: Boolean;
function InitAllocator(out AAlloc: IMemAllocator): HRESULT; virtual;
public
// constructor and destructor
constructor Create(out hr: HResult; Reader: TBCAsyncReader;
IO: TBCAsyncIo; Lock: TBCCritSec);
destructor Destroy; override;
// --- CUnknown ---
// need to expose IAsyncReader
function NonDelegatingQueryInterface(const IID: TGUID;
out Obj): HResult; override; stdcall;
// --- IPin methods ---
function Connect(AReceivePin: IPin;
const pmt: PAMMediaType): HResult; reintroduce; stdcall;
// --- CBasePin methods ---
// return the types we prefer - this will return the known
// file type
function GetMediaType(Position: Integer;
out MediaType: PAMMediaType): HResult; override;
// can we support this type?
function CheckMediaType(AType: PAMMediaType): HResult; override;
// Clear the flag so we see if IAsyncReader is queried for
function CheckConnect(Pin: IPin): HResult; override;
// See if it was asked for
function CompleteConnect(ReceivePin: IPin): HResult; override;
// Remove our connection status
function BreakConnect: HResult; override;
// --- IAsyncReader methods ---
// pass in your preferred allocator and your preferred properties.
// method returns the actual allocator to be used. Call GetProperties
// on returned allocator to learn alignment and prefix etc chosen.
// this allocator will be not be committed and decommitted by
// the async reader, only by the consumer.
function RequestAllocator(APreferred: IMemAllocator;
AProps: PAllocatorProperties;
out AActual: IMemAllocator): HResult; stdcall;
// queue a request for data.
// media sample start and stop times contain the requested absolute
// byte position (start inclusive, stop exclusive).
// may fail if sample not obtained from agreed allocator.
// may fail if start/stop position does not match agreed alignment.
// samples allocated from source pin's allocator may fail
// GetPointer until after returning from WaitForNext.
function Request(ASample: IMediaSample; AUser: DWord): HResult; stdcall;
// block until the next sample is completed or the timeout occurs.
// timeout (millisecs) may be 0 or INFINITE. Samples may not
// be delivered in order. If there is a read error of any sort, a
// notification will already have been sent by the source filter,
// and STDMETHODIMP will be an error.
function WaitForNext(ATimeout: DWord; out ASample: IMediaSample;
out AUser: DWord): HResult; stdcall;
// sync read of data. Sample passed in must have been acquired from
// equivalent to a Request/WaitForNext pair, but may avoid the
// need for a thread on the source filter.
function SyncReadAligned(ASample: IMediaSample): HResult; stdcall;
// sync read. works in stopped state as well as run state.
// need not be aligned. Will fail if read is beyond actual total
// length.
function SyncRead(APosition: int64; ALength: Longint;
ABuffer: PByte): HResult; stdcall;
// return total length of stream, and currently available length.
// reads for beyond the available length but within the total length will
// normally succeed but may block for a long period.
function Length(out ATotal, AAvailable: int64): HResult; stdcall;
// cause all outstanding reads to return, possibly with a failure code
// (VFW_E_TIMEOUT) indicating they were cancelled.
// these are defined on IAsyncReader and IPin
function BeginFlush: HResult; override;
function EndFlush: HResult; override;
end;
//
// The filter object itself. Supports IBaseFilter through
// CBaseFilter and also IFileSourceFilter directly in this object
TBCAsyncReader = class(TBCBaseFilter)
protected
// filter-wide lock
FCSFilter: TBCCritSec;
// all i/o done here
FIO: TBCAsyncIo;
// our output pin
FOutputPin: TBCAsyncOutputPin;
// Type we think our data is
Fmt: TAMMediaType;
public
// construction / destruction
constructor Create(Name: String; Unk: IUnknown;
Stream: TBCAsyncStream; out hr: HResult);
destructor Destroy; override;
// --- CBaseFilter methods ---
function GetPinCount: Integer; override;
function GetPin(n: Integer): TBCBasePin; override;
// --- Access our media type
function LoadType: PAMMediaType; virtual;
function Connect(pReceivePin: IPin;
const pmt: PAMMediaType): HRESULT; virtual;
end;
implementation
// --- TBCCAsyncReader ---
constructor TBCAsyncReader.Create(Name: String; Unk: IUnknown;
Stream: TBCAsyncStream; out hr: HResult);
begin
FCSFilter := TBCCritSec.Create;
ZeroMemory(@Fmt, SizeOf(TAMMediaType));
Inherited Create(Name, Unk, FCSFilter, CLSID_AsyncSample, hr);
FIO := TBCAsyncIo.Create(Stream);
FOutputPin := TBCAsyncOutputPin.Create(hr, Self, FIO, FCSFilter);
end;
destructor TBCAsyncReader.Destroy;
begin
Inherited;
// FCSFilter is destroyed by parent class
end;
function TBCAsyncReader.GetPinCount: Integer;
begin
Result := 1;
end;
function TBCAsyncReader.GetPin(n: Integer): TBCBasePin;
begin
if ((GetPinCount > 0) and (n = 0)) then
Result := FOutputPin
else
Result := nil;
end;
function TBCAsyncReader.LoadType: PAMMediaType;
begin
Result := @Fmt;
end;
function TBCAsyncReader.Connect(pReceivePin: IPin;
const pmt: PAMMediaType): HRESULT;
begin
Result := FOutputPin.Connect(pReceivePin, pmt);
end;
// --- TBCAsyncOutputPin ---
constructor TBCAsyncOutputPin.Create(out hr: HResult; Reader: TBCAsyncReader;
IO: TBCAsyncIo; Lock: TBCCritSec);
begin
Inherited Create('Async output pin', Reader, Lock, hr, 'Output',
PINDIR_OUTPUT);
FReader := Reader;
FIO := IO;
end;
destructor TBCAsyncOutputPin.Destroy;
begin
Inherited;
end;
function TBCAsyncOutputPin.InitAllocator(out AAlloc: IMemAllocator): HRESULT;
begin
// Create a default memory allocator
Result := CreateMemoryAllocator(AAlloc);
if Failed(Result) then
Exit;
if (AAlloc = nil) then
begin
Result := E_OUTOFMEMORY;
Exit;
end;
end;
function TBCAsyncOutputPin.NonDelegatingQueryInterface(const IID: TGUID;
out Obj): HResult;
begin
if IsEqualGUID(IID, IID_IAsyncReader) then
begin
FQueriedForAsyncReader := True;
if GetInterface(IID_IAsyncReader, Obj) then
Result := S_OK
else
Result := E_FAIL;
end
else
Result := Inherited NonDelegatingQueryInterface(IID, Obj);
end;
function TBCAsyncOutputPin.Connect(AReceivePin: IPin;
const pmt: PAMMediaType): HResult;
begin
Result := FReader.Connect(AReceivePin, pmt);
end;
function TBCAsyncOutputPin.GetMediaType(Position: Integer;
out MediaType: PAMMediaType): HResult;
begin
if (Position < 0) then
Result := E_INVALIDARG
else
if (Position > 0) then
Result := VFW_S_NO_MORE_ITEMS
else
begin
if (FReader = nil) then
begin
Result := E_UNEXPECTED;
Exit;
end;
CopyMemory(MediaType, FReader.LoadType, SizeOf(TAMMediaType));
Result := S_OK;
end;
end;
function TBCAsyncOutputPin.CheckMediaType(AType: PAMMediaType): HResult;
begin
try
// We treat MEDIASUBTYPE_NULL subtype as a wild card
with FReader do
if (IsEqualGUID(LoadType.majortype, AType.majortype) and
(IsEqualGUID(LoadType.subtype, MEDIASUBTYPE_NULL) or
Result := S_OK
else
Result := S_FALSE;
finally
FLock.Unlock;
end;
end;
function TBCAsyncOutputPin.CheckConnect(Pin: IPin): HResult;
begin
FQueriedForAsyncReader := False;
Result := Inherited CheckConnect(Pin);
end;
function TBCAsyncOutputPin.CompleteConnect(ReceivePin: IPin): HResult;
begin
if FQueriedForAsyncReader then
Result := inherited CompleteConnect(ReceivePin)
else
{$IFDEF VFW_E_NO_TRANSPORT}
Result := VFW_E_NO_TRANSPORT;
{$ELSE}
Result := E_FAIL;
{$ENDIF}
end;
function TBCAsyncOutputPin.BreakConnect: HResult;
begin
FQueriedForAsyncReader := False;
Result := Inherited BreakConnect;
end;
function TBCAsyncOutputPin.RequestAllocator(APreferred: IMemAllocator;
AProps: PAllocatorProperties; out AActual: IMemAllocator): HResult;
var
Actual: TAllocatorProperties;
Alloc: IMemAllocator;
begin
// we need to return an addrefed allocator, even if it is the preferred
// one, since he doesn't know whether it is the preferred one or not.
Assert(Assigned(FIO));
// we care about alignment but nothing else
if ((Not Boolean(AProps.cbAlign)) or
(Not FIo.IsAligned(AProps.cbAlign))) then
AProps.cbAlign := FIo.Alignment;
if Assigned(APreferred) then
begin
Result := APreferred.SetProperties(AProps^, Actual);
if (Succeeded(Result) and FIo.IsAligned(Actual.cbAlign)) then
begin
AActual := APreferred;
Result := S_OK;
Exit;
end;
end;
// create our own allocator
Result := InitAllocator(Alloc);
if Failed(Result) then
Exit;
//...and see if we can make it suitable
Result := Alloc.SetProperties(AProps^, Actual);
if (Succeeded(Result) and FIo.IsAligned(Actual.cbAlign)) then
begin
// we need to release our refcount on pAlloc, and addref
// it to pass a refcount to the caller - this is a net nothing.
AActual := Alloc;
Result := S_OK;
Exit;
end;
// failed to find a suitable allocator
Alloc._Release;
// if we failed because of the IsAligned test, the error code will
// not be failure
if Succeeded(Result) then
Result := VFW_E_BADALIGN;
end;
function TBCAsyncOutputPin.Request(ASample: IMediaSample; AUser: DWord): HResult;
var
Start, Stop: TReferenceTime;
Pos, Total, Available: LONGLONG;
Length, Align: Integer;
Buffer: PByte;
begin
// queue an aligned read request. call WaitForNext to get
// completion.
Result := ASample.GetTime(Start, Stop);
if Failed(Result) then
Exit;
Pos := Start div UNITS;
Length := (Stop - Start) div UNITS;
Total := 0;
Available := 0;
FIO.Length(Total, Available);
if (Pos + Length > Total) then
begin
// the end needs to be aligned, but may have been aligned
// on a coarser alignment.
FIo.Alignment(Align);
Total := (Total + Align -1) and (Not (Align-1));
if (Pos + Length > Total) then
begin
Length := Total - Pos;
// must be reducing this!
Assert((Total * UNITS) <= Stop);
Stop := Total * UNITS;
ASample.SetTime(@Start, @Stop);
end;
end;
Result := ASample.GetPointer(Buffer);
if Failed(Result) then
Exit;
Result := FIO.Request(Pos, Length, True, Buffer, Pointer(ASample), AUser);
end;
function TBCAsyncOutputPin.WaitForNext(ATimeout: DWord; out ASample: IMediaSample;
out AUser: DWord): HResult;
var
Actual: Integer;
Sample: IMediaSample;
begin
Sample := nil;
Result := FIo.WaitForNext(ATimeout, @Sample, AUser, Actual);
if Succeeded(Result) then
Sample.SetActualDataLength(Actual);
ASample := Sample;
end;
function TBCAsyncOutputPin.SyncReadAligned(ASample: IMediaSample): HResult;
var
Start, Stop: TReferenceTime;
Pos, Total, Available: LONGLONG;
Length, Align, Actual: Integer;
Buffer: PByte;
begin
Result := ASample.GetTime(Start, Stop);
if Failed(Result) then
Exit;
Pos := Start div UNITS;
Length := (Stop - Start) div UNITS;
FIo.Length(Total, Available);
if (Pos + Length > Total) then
begin
// the end needs to be aligned, but may have been aligned
// on a coarser alignment.
FIo.Alignment(Align);
Total := (Total + Align - 1) and (Not (Align - 1));
if (Pos + Length > Total) then
begin
Length := Total - Pos;
// must be reducing this!
Assert((Total * UNITS) <= Stop);
Stop := Total * UNITS;
ASample.SetTime(@Start, @Stop);
end;
end;
Result := ASample.GetPointer(Buffer);
if Failed(Result) then
Exit;
Result := FIO.SyncReadAligned(Pos, Length, Buffer, Actual, Pointer(ASample));
ASample.SetActualDataLength(Actual);
end;
function TBCAsyncOutputPin.SyncRead(APosition: Int64; ALength: Longint;
ABuffer: Pbyte): HResult;
begin
Result := FIO.SyncRead(APosition, ALength, ABuffer);
end;
function TBCAsyncOutputPin.Length(out ATotal, AAvailable: int64): HResult;
begin
Result := FIO.Length(ATotal, AAvailable);
end;
function TBCAsyncOutputPin.BeginFlush: HResult;
begin
Result := FIO.BeginFlush;
end;
function TBCAsyncOutputPin.EndFlush: HResult;
begin
Result := FIO.EndFlush;
end;
end.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -