UAsyncRdr.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:14k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. //------------------------------------------------------------------------------
  2. // File: UAsyncRdr.pas
  3. // Original files: asyncrdr.h, asyncrdr.c
  4. //
  5. // Desc: Defines an IO source filter.
  6. //
  7. // This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the
  8. // filter object itself. It has a single output pin (CAsyncOutputPin)
  9. // which supports IPin and IAsyncReader.
  10. //
  11. // This filter is essentially a wrapper for the CAsyncFile class that does
  12. // all the work.
  13. //
  14. //
  15. // Portions created by Microsoft are
  16. // Copyright (c) 2000-2002  Microsoft Corporation.  All rights reserved.
  17. //------------------------------------------------------------------------------
  18. unit UAsyncRdr;
  19. interface
  20. uses
  21.   BaseClass, DirectShow9, DSUtil, ActiveX, Windows, SysUtils,
  22.   UAsyncIo;
  23. const
  24.   CLSID_AsyncSample: TGUID = '{10F9E8F1-FE54-470C-9F1A-FE587DF7BD0B}';
  25. type
  26.   // the filter class (defined below)
  27.   TBCAsyncReader = class;
  28.   // the output pin class
  29.   TBCAsyncOutputPin = class(TBCBasePin, IAsyncReader)
  30.   protected
  31.     FReader: TBCAsyncReader;
  32.     FIo: TBCAsyncIo;
  33.     //  This is set every time we're asked to return an IAsyncReader
  34.     //  interface
  35.     //  This allows us to know if the downstream pin can use
  36.     //  this transport, otherwise we can hook up to thinks like the
  37.     //  dump filter and nothing happens
  38.     FQueriedForAsyncReader: Boolean;
  39.     function InitAllocator(out AAlloc: IMemAllocator): HRESULT; virtual;
  40.   public
  41.     // constructor and destructor
  42.     constructor Create(out hr: HResult; Reader: TBCAsyncReader;
  43.       IO: TBCAsyncIo; Lock: TBCCritSec);
  44.     destructor Destroy; override;
  45.     // --- CUnknown ---
  46.     // need to expose IAsyncReader
  47.     function NonDelegatingQueryInterface(const IID: TGUID;
  48.       out Obj): HResult; override; stdcall;
  49.     // --- IPin methods ---
  50.     function Connect(AReceivePin: IPin;
  51.       const pmt: PAMMediaType): HResult; reintroduce; stdcall;
  52.     // --- CBasePin methods ---
  53.     // return the types we prefer - this will return the known
  54.     // file type
  55.     function GetMediaType(Position: Integer;
  56.       out MediaType: PAMMediaType): HResult; override;
  57.     // can we support this type?
  58.     function CheckMediaType(AType: PAMMediaType): HResult; override;
  59.     // Clear the flag so we see if IAsyncReader is queried for
  60.     function CheckConnect(Pin: IPin): HResult; override;
  61.     // See if it was asked for
  62.     function CompleteConnect(ReceivePin: IPin): HResult; override;
  63.     //  Remove our connection status
  64.     function BreakConnect: HResult; override;
  65.     // --- IAsyncReader methods ---
  66.     // pass in your preferred allocator and your preferred properties.
  67.     // method returns the actual allocator to be used. Call GetProperties
  68.     // on returned allocator to learn alignment and prefix etc chosen.
  69.     // this allocator will be not be committed and decommitted by
  70.     // the async reader, only by the consumer.
  71.     function RequestAllocator(APreferred: IMemAllocator;
  72.         AProps: PAllocatorProperties;
  73.         out AActual: IMemAllocator): HResult; stdcall;
  74.     // queue a request for data.
  75.     // media sample start and stop times contain the requested absolute
  76.     // byte position (start inclusive, stop exclusive).
  77.     // may fail if sample not obtained from agreed allocator.
  78.     // may fail if start/stop position does not match agreed alignment.
  79.     // samples allocated from source pin's allocator may fail
  80.     // GetPointer until after returning from WaitForNext.
  81.     function Request(ASample: IMediaSample; AUser: DWord): HResult; stdcall;
  82.     // block until the next sample is completed or the timeout occurs.
  83.     // timeout (millisecs) may be 0 or INFINITE. Samples may not
  84.     // be delivered in order. If there is a read error of any sort, a
  85.     // notification will already have been sent by the source filter,
  86.     // and STDMETHODIMP will be an error.
  87.     function WaitForNext(ATimeout: DWord; out ASample: IMediaSample;
  88.         out AUser: DWord): HResult; stdcall;
  89.     // sync read of data. Sample passed in must have been acquired from
  90.     // the agreed allocator. Start and stop position must be aligned.
  91.     // equivalent to a Request/WaitForNext pair, but may avoid the
  92.     // need for a thread on the source filter.
  93.     function SyncReadAligned(ASample: IMediaSample): HResult; stdcall;
  94.     // sync read. works in stopped state as well as run state.
  95.     // need not be aligned. Will fail if read is beyond actual total
  96.     // length.
  97.     function SyncRead(APosition: int64; ALength: Longint;
  98.       ABuffer: PByte): HResult; stdcall;
  99.     // return total length of stream, and currently available length.
  100.     // reads for beyond the available length but within the total length will
  101.     // normally succeed but may block for a long period.
  102.     function Length(out ATotal, AAvailable: int64): HResult; stdcall;
  103.     // cause all outstanding reads to return, possibly with a failure code
  104.     // (VFW_E_TIMEOUT) indicating they were cancelled.
  105.     // these are defined on IAsyncReader and IPin
  106.     function BeginFlush: HResult; override;
  107.     function EndFlush: HResult; override;
  108.   end;
  109.   //
  110.   // The filter object itself. Supports IBaseFilter through
  111.   // CBaseFilter and also IFileSourceFilter directly in this object
  112.   TBCAsyncReader = class(TBCBaseFilter)
  113.   protected
  114.     // filter-wide lock
  115.     FCSFilter: TBCCritSec;
  116.     // all i/o done here
  117.     FIO: TBCAsyncIo;
  118.     // our output pin
  119.     FOutputPin: TBCAsyncOutputPin;
  120.     // Type we think our data is
  121.     Fmt: TAMMediaType;
  122.   public
  123.     // construction / destruction
  124.     constructor Create(Name: String; Unk: IUnknown;
  125.       Stream: TBCAsyncStream; out hr: HResult);
  126.     destructor Destroy; override;
  127.     // --- CBaseFilter methods ---
  128.     function GetPinCount: Integer; override;
  129.     function GetPin(n: Integer): TBCBasePin; override;
  130.     // --- Access our media type
  131.     function LoadType: PAMMediaType; virtual;
  132.     function Connect(pReceivePin: IPin;
  133.       const pmt: PAMMediaType): HRESULT; virtual;
  134.   end;
  135. implementation
  136. // --- TBCCAsyncReader ---
  137. constructor TBCAsyncReader.Create(Name: String; Unk: IUnknown;
  138.   Stream: TBCAsyncStream; out hr: HResult);
  139. begin
  140.   FCSFilter := TBCCritSec.Create;
  141.   ZeroMemory(@Fmt, SizeOf(TAMMediaType));
  142.   Inherited Create(Name, Unk, FCSFilter, CLSID_AsyncSample, hr);
  143.   FIO := TBCAsyncIo.Create(Stream);
  144.   FOutputPin := TBCAsyncOutputPin.Create(hr, Self, FIO, FCSFilter);
  145. end;
  146. destructor TBCAsyncReader.Destroy;
  147. begin
  148.   Inherited;
  149.   // FCSFilter is destroyed by parent class
  150. end;
  151. function TBCAsyncReader.GetPinCount: Integer;
  152. begin
  153.   Result := 1;
  154. end;
  155. function TBCAsyncReader.GetPin(n: Integer): TBCBasePin;
  156. begin
  157.   if ((GetPinCount > 0) and (n = 0)) then
  158.     Result := FOutputPin
  159.   else
  160.     Result := nil;
  161. end;
  162. function TBCAsyncReader.LoadType: PAMMediaType;
  163. begin
  164.   Result := @Fmt;
  165. end;
  166. function TBCAsyncReader.Connect(pReceivePin: IPin;
  167.   const pmt: PAMMediaType): HRESULT;
  168. begin
  169.   Result := FOutputPin.Connect(pReceivePin, pmt);
  170. end;
  171. // --- TBCAsyncOutputPin ---
  172. constructor TBCAsyncOutputPin.Create(out hr: HResult; Reader: TBCAsyncReader;
  173.   IO: TBCAsyncIo; Lock: TBCCritSec);
  174. begin
  175.   Inherited Create('Async output pin', Reader, Lock, hr, 'Output',
  176.     PINDIR_OUTPUT);
  177.   FReader := Reader;
  178.   FIO := IO;
  179. end;
  180. destructor TBCAsyncOutputPin.Destroy;
  181. begin
  182.   Inherited;
  183. end;
  184. function TBCAsyncOutputPin.InitAllocator(out AAlloc: IMemAllocator): HRESULT;
  185. begin
  186.   // Create a default memory allocator
  187.   Result := CreateMemoryAllocator(AAlloc);
  188.   if Failed(Result) then
  189.     Exit;
  190.   if (AAlloc = nil) then
  191.   begin
  192.     Result := E_OUTOFMEMORY;
  193.     Exit;
  194.   end;
  195. end;
  196. function TBCAsyncOutputPin.NonDelegatingQueryInterface(const IID: TGUID;
  197.   out Obj): HResult;
  198. begin
  199.   if IsEqualGUID(IID, IID_IAsyncReader) then
  200.   begin
  201.     FQueriedForAsyncReader := True;
  202.     if GetInterface(IID_IAsyncReader, Obj) then
  203.       Result := S_OK
  204.     else
  205.       Result := E_FAIL;
  206.   end
  207.     else
  208.       Result := Inherited NonDelegatingQueryInterface(IID, Obj);
  209. end;
  210. function TBCAsyncOutputPin.Connect(AReceivePin: IPin;
  211.   const pmt: PAMMediaType): HResult;
  212. begin
  213.   Result := FReader.Connect(AReceivePin, pmt);
  214. end;
  215. function TBCAsyncOutputPin.GetMediaType(Position: Integer;
  216.   out MediaType: PAMMediaType): HResult;
  217. begin
  218.   if (Position < 0) then
  219.     Result := E_INVALIDARG
  220.   else
  221.     if (Position > 0) then
  222.       Result := VFW_S_NO_MORE_ITEMS
  223.     else
  224.       begin
  225.         if (FReader = nil) then
  226.         begin
  227.           Result := E_UNEXPECTED;
  228.           Exit;
  229.         end;
  230.         CopyMemory(MediaType, FReader.LoadType, SizeOf(TAMMediaType));
  231.         Result := S_OK;
  232.       end;
  233. end;
  234. function TBCAsyncOutputPin.CheckMediaType(AType: PAMMediaType): HResult;
  235. begin
  236.   FLock.Lock;
  237.   try
  238.     // We treat MEDIASUBTYPE_NULL subtype as a wild card
  239.     with FReader do
  240.     if (IsEqualGUID(LoadType.majortype, AType.majortype) and
  241.       (IsEqualGUID(LoadType.subtype, MEDIASUBTYPE_NULL) or
  242.       IsEqualGUID(LoadType.subtype, AType.subtype))) then
  243.       Result := S_OK
  244.     else
  245.       Result := S_FALSE;
  246.   finally
  247.     FLock.Unlock;
  248.   end;
  249. end;
  250. function TBCAsyncOutputPin.CheckConnect(Pin: IPin): HResult;
  251. begin
  252.   FQueriedForAsyncReader := False;
  253.   Result := Inherited CheckConnect(Pin);
  254. end;
  255. function TBCAsyncOutputPin.CompleteConnect(ReceivePin: IPin): HResult;
  256. begin
  257.   if FQueriedForAsyncReader then
  258.     Result := inherited CompleteConnect(ReceivePin)
  259.   else
  260.     {$IFDEF VFW_E_NO_TRANSPORT}
  261.     Result := VFW_E_NO_TRANSPORT;
  262.     {$ELSE}
  263.     Result := E_FAIL;
  264.     {$ENDIF}
  265. end;
  266. function TBCAsyncOutputPin.BreakConnect: HResult;
  267. begin
  268.   FQueriedForAsyncReader := False;
  269.   Result := Inherited BreakConnect;
  270. end;
  271. function TBCAsyncOutputPin.RequestAllocator(APreferred: IMemAllocator;
  272.   AProps: PAllocatorProperties; out AActual: IMemAllocator): HResult;
  273. var
  274.   Actual: TAllocatorProperties;
  275.   Alloc: IMemAllocator;
  276. begin
  277.   // we need to return an addrefed allocator, even if it is the preferred
  278.   // one, since he doesn't know whether it is the preferred one or not.
  279.   Assert(Assigned(FIO));
  280.   // we care about alignment but nothing else
  281.   if ((Not Boolean(AProps.cbAlign)) or
  282.     (Not FIo.IsAligned(AProps.cbAlign))) then
  283.     AProps.cbAlign := FIo.Alignment;
  284.   if Assigned(APreferred) then
  285.   begin
  286.     Result := APreferred.SetProperties(AProps^, Actual);
  287.     if (Succeeded(Result) and FIo.IsAligned(Actual.cbAlign)) then
  288.     begin
  289.         AActual := APreferred;
  290.         Result := S_OK;
  291.         Exit;
  292.     end;
  293.   end;
  294.   // create our own allocator
  295.   Result := InitAllocator(Alloc);
  296.   if Failed(Result) then
  297.     Exit;
  298.   //...and see if we can make it suitable
  299.   Result := Alloc.SetProperties(AProps^, Actual);
  300.   if (Succeeded(Result) and FIo.IsAligned(Actual.cbAlign)) then
  301.   begin
  302.     // we need to release our refcount on pAlloc, and addref
  303.     // it to pass a refcount to the caller - this is a net nothing.
  304.     AActual := Alloc;
  305.     Result := S_OK;
  306.     Exit;
  307.   end;
  308.   // failed to find a suitable allocator
  309.   Alloc._Release;
  310.   // if we failed because of the IsAligned test, the error code will
  311.   // not be failure
  312.   if Succeeded(Result) then
  313.     Result := VFW_E_BADALIGN;
  314. end;
  315. function TBCAsyncOutputPin.Request(ASample: IMediaSample; AUser: DWord): HResult;
  316. var
  317.   Start, Stop: TReferenceTime;
  318.   Pos, Total, Available: LONGLONG;
  319.   Length, Align: Integer;
  320.   Buffer: PByte;
  321. begin
  322.   // queue an aligned read request. call WaitForNext to get
  323.   // completion.
  324.   Result := ASample.GetTime(Start, Stop);
  325.   if Failed(Result) then
  326.     Exit;
  327.   Pos := Start div UNITS;
  328.   Length := (Stop - Start) div UNITS;
  329.   Total := 0;
  330.   Available := 0;
  331.   FIO.Length(Total, Available);
  332.   if (Pos + Length > Total) then
  333.   begin
  334.     // the end needs to be aligned, but may have been aligned
  335.     // on a coarser alignment.
  336.     FIo.Alignment(Align);
  337.     Total := (Total + Align -1) and (Not (Align-1));
  338.     if (Pos + Length > Total) then
  339.     begin
  340.       Length := Total - Pos;
  341.       // must be reducing this!
  342.       Assert((Total * UNITS) <= Stop);
  343.       Stop := Total * UNITS;
  344.       ASample.SetTime(@Start, @Stop);
  345.     end;
  346.   end;
  347.   Result := ASample.GetPointer(Buffer);
  348.   if Failed(Result) then
  349.     Exit;
  350.   Result := FIO.Request(Pos, Length, True, Buffer, Pointer(ASample), AUser);
  351. end;
  352. function TBCAsyncOutputPin.WaitForNext(ATimeout: DWord; out ASample: IMediaSample;
  353.   out AUser: DWord): HResult;
  354. var
  355.   Actual: Integer;
  356.   Sample: IMediaSample;
  357. begin
  358.   Sample := nil;
  359.   Result := FIo.WaitForNext(ATimeout, @Sample, AUser, Actual);
  360.   if Succeeded(Result) then
  361.     Sample.SetActualDataLength(Actual);
  362.   ASample := Sample;
  363. end;
  364. function TBCAsyncOutputPin.SyncReadAligned(ASample: IMediaSample): HResult;
  365. var
  366.   Start, Stop: TReferenceTime;
  367.   Pos, Total, Available: LONGLONG;
  368.   Length, Align, Actual: Integer;
  369.   Buffer: PByte;
  370. begin
  371.   Result := ASample.GetTime(Start, Stop);
  372.   if Failed(Result) then
  373.     Exit;
  374.   Pos := Start div UNITS;
  375.   Length := (Stop - Start) div UNITS;
  376.   FIo.Length(Total, Available);
  377.   if (Pos + Length > Total) then
  378.   begin
  379.     // the end needs to be aligned, but may have been aligned
  380.     // on a coarser alignment.
  381.     FIo.Alignment(Align);
  382.     Total := (Total + Align - 1) and (Not (Align - 1));
  383.     if (Pos + Length > Total) then
  384.     begin
  385.         Length := Total - Pos;
  386.         // must be reducing this!
  387.         Assert((Total * UNITS) <= Stop);
  388.         Stop := Total * UNITS;
  389.         ASample.SetTime(@Start, @Stop);
  390.     end;
  391.   end;
  392.   Result := ASample.GetPointer(Buffer);
  393.   if Failed(Result) then
  394.     Exit;
  395.   Result := FIO.SyncReadAligned(Pos, Length, Buffer, Actual, Pointer(ASample));
  396.   ASample.SetActualDataLength(Actual);
  397. end;
  398. function TBCAsyncOutputPin.SyncRead(APosition: Int64; ALength: Longint;
  399.   ABuffer: Pbyte): HResult;
  400. begin
  401.   Result := FIO.SyncRead(APosition, ALength, ABuffer);
  402. end;
  403. function TBCAsyncOutputPin.Length(out ATotal, AAvailable: int64): HResult;
  404. begin
  405.   Result := FIO.Length(ATotal, AAvailable);
  406. end;
  407. function TBCAsyncOutputPin.BeginFlush: HResult;
  408. begin
  409.   Result := FIO.BeginFlush;
  410. end;
  411. function TBCAsyncOutputPin.EndFlush: HResult;
  412. begin
  413.   Result := FIO.EndFlush;
  414. end;
  415. end.