UAsyncRdr.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:14k
- //------------------------------------------------------------------------------
- // 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
- // the agreed allocator. Start and stop position must be aligned.
- // 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
- FLock.Lock;
- 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
- IsEqualGUID(LoadType.subtype, AType.subtype))) then
- 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.