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

Delphi控件源码

开发平台:

Delphi

  1.     (*********************************************************************
  2.      *  DSPack 2.3.3                                                     *
  3.      *  DirectShow BaseClass                                             *
  4.      *                                                                   *
  5.      * home page : http://www.progdigy.com                               *
  6.      * email     : hgourvest@progdigy.com                                *
  7.      *                                                                   *
  8.      * date      : 21-02-2003                                            *
  9.      *                                                                   *
  10.      * The contents of this file are used with permission, subject to    *
  11.      * the Mozilla Public License Version 1.1 (the "License"); you may   *
  12.      * not use this file except in compliance with the License. You may  *
  13.      * obtain a copy of the License at                                   *
  14.      * http://www.mozilla.org/MPL/MPL-1.1.html                           *
  15.      *                                                                   *
  16.      * Software distributed under the License is distributed on an       *
  17.      * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or    *
  18.      * implied. See the License for the specific language governing      *
  19.      * rights and limitations under the License.                         *
  20.      *                                                                   *
  21.      *  Contributor(s)                                                   *
  22.      *    Andriy Nevhasymyy <a.n@email.com>                              *
  23.      *    Milenko Mitrovic  <dcoder@dsp-worx.de>                         *
  24.      *    Michael Andersen  <michael@mechdata.dk>                        *
  25.      *    Martin Offenwanger <coder@dsplayer.de>                         *
  26.      *                                                                   *
  27.      *********************************************************************)
  28. {.$DEFINE DEBUG}      // Debug Log
  29. {.$DEFINE TRACE}      // Trace Criteral Section (DEBUG must be ON)
  30. {.$DEFINE MESSAGE}    // Use OutputDebugString instead of a File (DEBUG must be ON)
  31. {.$DEFINE PERF}       // Show Performace Counter
  32. {.$DEFINE VTRANSPERF} // Show additional TBCVideoTransformFilter Performace Counter (PERF must be ON)
  33. {$MINENUMSIZE 4}
  34. {$ALIGN ON}
  35. unit BaseClass;
  36. {$IFDEF VER150}
  37.   {$WARN UNSAFE_CODE OFF}
  38.   {$WARN UNSAFE_TYPE OFF}
  39.   {$WARN UNSAFE_CAST OFF}
  40. {$ENDIF}
  41. interface
  42. uses Windows, SysUtils, Classes, Math, ActiveX, Forms, Messages, Controls,
  43.   DirectShow9, dialogs, ComObj, mmsystem, DSUtil;
  44. const
  45.   OATRUE  = -1;
  46.   OAFALSE = 0;
  47.   DEFAULTCACHE = 10; // Default node object cache size
  48. type
  49.   TBCCritSec = class
  50.   private
  51.     FCritSec : TRTLCriticalSection;
  52.   {$IFDEF DEBUG}
  53.     FcurrentOwner: Longword;
  54.     FlockCount   : Longword;
  55.   {$ENDIF}
  56.   public
  57.     constructor Create;
  58.     destructor Destroy; override;
  59.     procedure Lock;
  60.     procedure UnLock;
  61.     function CritCheckIn: boolean;
  62.     function CritCheckOut: boolean;
  63.   end;
  64.   TBCBaseObject = class(TObJect)
  65.   private
  66.     FName: string;
  67.   public
  68.     constructor Create(Name: string);
  69.     destructor Destroy; override;
  70.     class function NewInstance: TObject; override;
  71.     procedure FreeInstance; override;
  72.     class function ObjectsActive: integer;
  73.   end;
  74.   TBCClassFactory = Class;
  75.   TBCUnknown = class(TBCBaseObject, IUnKnown)
  76.   private
  77.     FRefCount: integer;
  78.     FOwner   : Pointer;
  79.   protected
  80.     function IUnknown.QueryInterface = NonDelegatingQueryInterface;
  81.     function IUnknown._AddRef = NonDelegatingAddRef;
  82.     function IUnknown._Release = NonDelegatingRelease;
  83.     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  84.   public
  85.     function _AddRef: Integer; stdcall;
  86.     function _Release: Integer; stdcall;
  87.     constructor Create(name: string; Unk: IUnknown);
  88.     constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); virtual;
  89.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
  90.     function NonDelegatingAddRef: Integer; virtual; stdcall;
  91.     function NonDelegatingRelease: Integer; virtual; stdcall;
  92.     function GetOwner: IUnKnown;
  93.   end;
  94.   TBCUnknownClass = Class of TBCUnknown;
  95.   TFormPropertyPage = class;
  96.   TFormPropertyPageClass = class of TFormPropertyPage;
  97.   TBCBaseFilter = class;
  98.   TBCBaseFilterClass = class of TBCBaseFilter;
  99.   TBCClassFactory = class(TObject, IUnKnown, IClassFactory)
  100.   private
  101.    FNext     : TBCClassFactory;
  102.    FComClass : TBCUnknownClass;
  103.    FPropClass: TFormPropertyPageClass;
  104.    FName     : String;
  105.    FClassID  : TGUID;
  106.    FCategory : TGUID;
  107.    FMerit    : LongWord;
  108.    FPinCount : Cardinal;
  109.    FPins     : PRegFilterPins;
  110.    function RegisterFilter(FilterMapper: IFilterMapper; Register: Boolean): boolean; overload;
  111.    function RegisterFilter(FilterMapper: IFilterMapper2; Register: Boolean): boolean; overload;
  112.    procedure UpdateRegistry(Register: Boolean); overload;
  113.   protected
  114.     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  115.     function _AddRef: Integer; stdcall;
  116.     function _Release: Integer; stdcall;
  117.     function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
  118.       out Obj): HResult; stdcall;
  119.     function LockServer(fLock: BOOL): HResult; stdcall;
  120.   public
  121.     constructor CreateFilter(ComClass: TBCUnknownClass; Name: string;
  122.       const ClassID: TGUID; const Category: TGUID; Merit: LongWord;
  123.       PinCount: Cardinal; Pins: PRegFilterPins);
  124.     constructor CreatePropertyPage(ComClass: TFormPropertyPageClass; const ClassID: TGUID);
  125.     property Name: String read FName;
  126.     property ClassID: TGUID read FClassID;
  127.   end;
  128.   TBCFilterTemplate = class
  129.   private
  130.     FFactoryList : TBCClassFactory;
  131.     procedure AddObjectFactory(Factory: TBCClassFactory);
  132.   public
  133.     constructor Create;
  134.     destructor Destroy; override;
  135.     function RegisterServer(Register: Boolean): boolean;
  136.     function GetFactoryFromClassID(const CLSID: TGUID): TBCClassFactory;
  137.   end;
  138.   TBCMediaType = object
  139.     MediaType: PAMMediaType;
  140.     function Equal(mt: TBCMediaType): boolean; overload;
  141.     function Equal(mt: PAMMediaType): boolean; overload;
  142.     function MatchesPartial(Partial: PAMMediaType): boolean;
  143.     function IsPartiallySpecified: boolean;
  144.     function IsValid: boolean;
  145.     procedure InitMediaType;
  146.     function FormatLength: Cardinal;
  147.   end;
  148.   TBCBasePin = class;
  149.   TBCBaseFilter = class(TBCUnknown, IBaseFilter, IAMovieSetup)
  150.   protected
  151.     FState : TFilterState;     // current state: running, paused
  152.     FClock : IReferenceClock;   // this graph's ref clock
  153.     FStart : TReferenceTime;   // offset from stream time to reference time
  154.     FCLSID : TGUID;             // This filters clsid used for serialization
  155.     FLock  : TBCCritSec;          // Object we use for locking
  156.     FFilterName : WideString;   // Full filter name
  157.     FGraph : IFilterGraph;      // Graph we belong to
  158.     FSink  : IMediaEventSink;   // Called with notify events
  159.     FPinVersion: Integer;       // Current pin version
  160.   public
  161.     constructor Create(Name: string;           // Object description
  162.                        Unk : IUnKnown;         // IUnknown of delegating object
  163.                        Lock: TBCCritSec;       // Object who maintains lock
  164.                        const clsid: TGUID      // The clsid to be used to serialize this filter
  165.                        ); overload;
  166.     constructor Create(Name: string;           // Object description
  167.                        Unk : IUnKnown;         // IUnknown of delegating object
  168.                        Lock: TBCCritSec;       // Object who maintains lock
  169.                        const clsid: TGUID;     // The clsid to be used to serialize this filter
  170.                        out hr: HRESULT         // General OLE return code
  171.                        ); overload;
  172.     constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); override;
  173.     destructor destroy; override;
  174.     // --- IPersist method ---
  175.     function GetClassID(out classID: TCLSID): HResult; stdcall;
  176.     // --- IMediaFilter methods ---
  177.     // override Stop and Pause so we can activate the pins.
  178.     // Note that Run will call Pause first if activation needed.
  179.     // Override these if you want to activate your filter rather than
  180.     // your pins.
  181.     function Stop: HRESULT; virtual; stdcall;
  182.     function Pause: HRESULT; virtual; stdcall;
  183.     // the start parameter is the difference to be added to the
  184.     // sample's stream time to get the reference time for
  185.     // its presentation
  186.     function Run(tStart: TReferenceTime): HRESULT; virtual; stdcall;
  187.     function GetState(dwMilliSecsTimeout: DWORD; out State: TFilterState): HRESULT; virtual; stdcall;
  188.     function SetSyncSource(pClock: IReferenceClock): HRESULT; stdcall;
  189.     function GetSyncSource(out pClock: IReferenceClock): HRESULT; stdcall;
  190.     // --- helper methods ---
  191.     // return the current stream time - ie find out what
  192.     // stream time should be appearing now
  193.     function StreamTime(out rtStream: TReferenceTime): HRESULT; virtual;
  194.     // Is the filter currently active?
  195.     function IsActive: boolean;
  196.     // Is this filter stopped (without locking)
  197.     function IsStopped: boolean;
  198.     // --- IBaseFilter methods ---
  199.     // pin enumerator
  200.     function EnumPins(out ppEnum: IEnumPins): HRESULT; stdcall;
  201.     // default behaviour of FindPin assumes pin ids are their names
  202.     function FindPin(Id: PWideChar; out Pin: IPin): HRESULT; virtual; stdcall;
  203.     function QueryFilterInfo(out pInfo: TFilterInfo): HRESULT; stdcall;
  204. // milenko start (added virtual to be able to override it in the renderers)
  205.     function JoinFilterGraph(pGraph: IFilterGraph; pName: PWideChar): HRESULT; virtual; stdcall;
  206. // milenko end    
  207.     // return a Vendor information string. Optional - may return E_NOTIMPL.
  208.     // memory returned should be freed using CoTaskMemFree
  209.     // default implementation returns E_NOTIMPL
  210.     function QueryVendorInfo(out pVendorInfo: PWideChar): HRESULT; stdcall;
  211.     // --- helper methods ---
  212.     // send an event notification to the filter graph if we know about it.
  213.     // returns S_OK if delivered, S_FALSE if the filter graph does not sink
  214.     // events, or an error otherwise.
  215.     function NotifyEvent(EventCode, EventParam1, EventParam2: LongInt): HRESULT;
  216.     // return the filter graph we belong to
  217.     function GetFilterGraph: IFilterGraph;
  218.     // Request reconnect
  219.     // pPin is the pin to reconnect
  220.     // pmt is the type to reconnect with - can be NULL
  221.     // Calls ReconnectEx on the filter graph
  222.     function ReconnectPin(Pin: IPin; pmt: PAMMediaType): HRESULT;
  223.     // find out the current pin version (used by enumerators)
  224.     function GetPinVersion: LongInt; virtual;
  225.     procedure IncrementPinVersion;
  226.     // you need to supply these to access the pins from the enumerator
  227.     // and for default Stop and Pause/Run activation.
  228.     function GetPinCount: integer; virtual; abstract;
  229.     function GetPin(n: Integer): TBCBasePin; virtual; abstract;
  230.     // --- IAMovieSetup methods ---
  231. {nev: start 04/16/04 added "virtual"}
  232.     function Register: HRESULT; virtual; stdcall;
  233.     function Unregister: HRESULT; virtual; stdcall;
  234. {nev: end}
  235.     property State: TFilterState read FState;
  236.     property GRaph : IFilterGraph read FGRaph;
  237.   end;
  238.  { NOTE The implementation of this class calls the CUnknown constructor with
  239.    a NULL outer unknown pointer. This has the effect of making us a self
  240.    contained class, ie any QueryInterface, AddRef or Release calls will be
  241.    routed to the class's NonDelegatingUnknown methods. You will typically
  242.    find that the classes that do this then override one or more of these
  243.    virtual functions to provide more specialised behaviour. A good example
  244.    of this is where a class wants to keep the QueryInterface internal but
  245.    still wants its lifetime controlled by the external object }
  246.   TBCBasePin = class(TBCUnknown, IPin, IQualityControl)
  247.   protected
  248.     FPinName: WideString;
  249.     FConnected             : IPin;             // Pin we have connected to
  250.     Fdir                   : TPinDirection;   // Direction of this pin
  251.     FLock                  : TBCCritSec;       // Object we use for locking
  252.     FRunTimeError          : boolean;          // Run time error generated
  253.     FCanReconnectWhenActive: boolean;          // OK to reconnect when active
  254.     FTryMyTypesFirst       : boolean;          // When connecting enumerate
  255.                                                // this pin's types first
  256.     FFilter                : TBCBaseFilter;    // Filter we were created by
  257.     FQSink                 : IQualityControl;  // Target for Quality messages
  258.     FTypeVersion           : LongInt;          // Holds current type version
  259.     Fmt                    : TAMMediaType;   // Media type of connection
  260.     FStart                 : TReferenceTime;  // time from NewSegment call
  261.     FStop                  : TReferenceTime;  // time from NewSegment
  262.     FRate                  : double;           // rate from NewSegment
  263.     FRef                   : LongInt;
  264.     function GetCurrentMediaType: TBCMediaType;
  265.     function GetAMMediaType: PAMMediaType;
  266.   protected
  267.     procedure DisplayPinInfo(ReceivePin: IPin);
  268.     procedure DisplayTypeInfo(Pin: IPin; pmt: PAMMediaType);
  269.     // used to agree a media type for a pin connection
  270.     // given a specific media type, attempt a connection (includes
  271.     // checking that the type is acceptable to this pin)
  272.     function AttemptConnection(
  273.        ReceivePin: IPin;      // connect to this pin
  274.        pmt       : PAMMediaType // using this type
  275.        ): HRESULT;
  276.     // try all the media types in this enumerator - for each that
  277.     // we accept, try to connect using ReceiveConnection.
  278.     function TryMediaTypes(
  279.                ReceivePin: IPin;           // connect to this pin
  280.                pmt       : PAMMediaType;     // proposed type from Connect
  281.                Enum      : IEnumMediaTypes // try this enumerator
  282.                ): HRESULT;
  283.     // establish a connection with a suitable mediatype. Needs to
  284.     // propose a media type if the pmt pointer is null or partially
  285.     // specified - use TryMediaTypes on both our and then the other pin's
  286.     // enumerator until we find one that works.
  287.     function AgreeMediaType(
  288.                ReceivePin: IPin;      // connect to this pin
  289.                pmt       : PAMMediaType // proposed type from Connect
  290.                ): HRESULT;
  291.     function DisconnectInternal: HRESULT; stdcall;
  292.   public
  293.     function NonDelegatingAddRef: Integer; override; stdcall;
  294.     function NonDelegatingRelease: Integer; override; stdcall;
  295.     constructor Create(
  296.                   ObjectName: string;           // Object description
  297.                   Filter    : TBCBaseFilter;      // Owning filter who knows about pins
  298.                   Lock      : TBCCritSec;         // Object who implements the lock
  299.                   out hr    : HRESULT;          // General OLE return code
  300.                   Name      : WideString;       // Pin name for us
  301.                   dir       : TPinDirection);  // Either PINDIR_INPUT or PINDIR_OUTPUT
  302.     destructor destroy; override;
  303.     // --- IPin methods ---
  304.     // take lead role in establishing a connection. Media type pointer
  305.     // may be null, or may point to partially-specified mediatype
  306.     // (subtype or format type may be GUID_NULL).
  307.     function Connect(pReceivePin: IPin; const pmt: PAMMediaType): HRESULT; virtual; stdcall;
  308.     // (passive) accept a connection from another pin
  309.     function ReceiveConnection(pConnector: IPin; const pmt: TAMMediaType): HRESULT; virtual; stdcall;
  310.     function Disconnect: HRESULT; virtual; stdcall;
  311.     function ConnectedTo(out pPin: IPin): HRESULT; virtual; stdcall;
  312.     function ConnectionMediaType(out pmt: TAMMediaType): HRESULT; virtual; stdcall;
  313.     function QueryPinInfo(out pInfo: TPinInfo): HRESULT; virtual; stdcall;
  314.     function QueryDirection(out pPinDir: TPinDirection): HRESULT; stdcall;
  315.     function QueryId(out Id: PWideChar): HRESULT; virtual; stdcall;
  316.     // does the pin support this media type
  317.     function QueryAccept(const pmt: TAMMediaType): HRESULT; virtual; stdcall;
  318.     // return an enumerator for this pins preferred media types
  319.     function EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT; virtual; stdcall;
  320.     // return an array of IPin* - the pins that this pin internally connects to
  321.     // All pins put in the array must be AddReffed (but no others)
  322.     // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE
  323.     // Default: return E_NOTIMPL
  324.     // The filter graph will interpret NOT_IMPL as any input pin connects to
  325.     // all visible output pins and vice versa.
  326.     // apPin can be NULL if nPin==0 (not otherwise).
  327.     function QueryInternalConnections(out apPin: IPin; var nPin: ULONG): HRESULT; virtual; stdcall;
  328.     // Called when no more data will be sent
  329.     function EndOfStream: HRESULT; virtual; stdcall;
  330.     function BeginFlush: HRESULT; virtual; stdcall; abstract;
  331.     function EndFlush: HRESULT; virtual; stdcall; abstract;
  332.     // Begin/EndFlush still PURE
  333.     // NewSegment notifies of the start/stop/rate applying to the data
  334.     // about to be received. Default implementation records data and
  335.     // returns S_OK.
  336.     // Override this to pass downstream.
  337.     function NewSegment(tStart, tStop: TReferenceTime; dRate: double): HRESULT; virtual; stdcall;
  338.     // --- IQualityControl methods ---
  339.     function Notify(pSelf: IBaseFilter; q: TQuality): HRESULT; virtual; stdcall;
  340.     function SetSink(piqc: IQualityControl): HRESULT; virtual; stdcall;
  341.     // --- helper methods ---
  342.     // Returns True if the pin is connected. false otherwise.
  343.     function IsConnected: boolean;
  344.     // Return the pin this is connected to (if any)
  345.     property GetConnected: IPin read FConnected;
  346.     // Check if our filter is currently stopped
  347.     function IsStopped: boolean;
  348.     // find out the current type version (used by enumerators)
  349.     function GetMediaTypeVersion: longint; virtual;
  350.     procedure IncrementTypeVersion;
  351.     // switch the pin to active (paused or running) mode
  352.     // not an error to call this if already active
  353.     function Active: HRESULT; virtual;
  354.     // switch the pin to inactive state - may already be inactive
  355.     function Inactive: HRESULT; virtual;
  356.     // Notify of Run() from filter
  357.     function Run(Start: TReferenceTime): HRESULT; virtual;
  358.     // check if the pin can support this specific proposed type and format
  359.     function CheckMediaType(mt: PAMMediaType): HRESULT; virtual; abstract;
  360.     // set the connection to use this format (previously agreed)
  361.     function SetMediaType(mt: PAMMediaType): HRESULT; virtual;
  362.     // check that the connection is ok before verifying it
  363.     // can be overridden eg to check what interfaces will be supported.
  364.     function CheckConnect(Pin: IPin): HRESULT; virtual;
  365.     // Set and release resources required for a connection
  366.     function BreakConnect: HRESULT; virtual;
  367.     function CompleteConnect(ReceivePin: IPin): HRESULT; virtual;
  368.     // returns the preferred formats for a pin
  369.     function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; virtual;
  370.     // access to NewSegment values
  371.     property CurrentStopTime: TReferenceTime read FStop;
  372.     property CurrentStartTime: TReferenceTime read FStart;
  373.     property CurrentRate: double read FRate;
  374.     //  Access name
  375.     property Name: WideString read FPinName;
  376.     property CanReconnectWhenActive: boolean read FCanReconnectWhenActive write FCanReconnectWhenActive;
  377.     // Media type
  378.     property CurrentMediaType: TBCMediaType read GetCurrentMediaType;
  379.     property AMMediaType: PAMMediaType read GetAMMediaType;
  380.   end;
  381.   TBCEnumPins = class(TInterfacedObject, IEnumPins)
  382.   private
  383.     FPosition: integer;   // Current ordinal position
  384.     FPinCount: integer;   // Number of pins available
  385.     FFilter: TBCBaseFilter; // The filter who owns us
  386.     FVersion: LongInt;    // Pin version information
  387.     // These pointers have not been AddRef'ed and
  388.     // so they should not be dereferenced.  They are
  389.     // merely kept to ID which pins have been enumerated.
  390.     FPinCache: TList;
  391.     { If while we are retrieving a pin for example from the filter an error
  392.       occurs we assume that our internal state is stale with respect to the
  393.       filter (someone may have deleted all the pins). We can check before
  394.       starting whether or not the operation is likely to fail by asking the
  395.       filter what it's current version number is. If the filter has not
  396.       overriden the GetPinVersion method then this will always match }
  397.     function AreWeOutOfSync: boolean;
  398.     (* This method performs the same operations as Reset, except is does not clear
  399.        the cache of pins already enumerated. *)
  400.     function Refresh: HRESULT; stdcall;
  401.   public
  402.     constructor Create(Filter: TBCBaseFilter; EnumPins: TBCEnumPins);
  403.     destructor Destroy; override;
  404.     function Next(cPins: ULONG;  // place this many pins...
  405.       out ppPins: IPin;          // ...in this array of IPin*
  406.       pcFetched: PULONG          // actual count passed returned here
  407.       ): HRESULT; stdcall;
  408.     function Skip(cPins: ULONG): HRESULT; stdcall;
  409.     function Reset: HRESULT; stdcall;
  410.     function Clone(out ppEnum: IEnumPins): HRESULT; stdcall;
  411.   end;
  412.   TBCEnumMediaTypes = class(TInterfacedObject, IEnumMediaTypes)
  413.   private
  414.    FPosition: Cardinal;   // Current ordinal position
  415.    FPin     : TBCBasePin; // The pin who owns us
  416.    FVersion : LongInt;    // Media type version value
  417.    function AreWeOutOfSync: boolean;
  418.   public
  419.     constructor Create(Pin: TBCBasePin; EnumMediaTypes: TBCEnumMediaTypes);
  420.     destructor Destroy; override;
  421.     function Next(cMediaTypes: ULONG; out ppMediaTypes: PAMMediaType;
  422.       pcFetched: PULONG): HRESULT; stdcall;
  423.     function Skip(cMediaTypes: ULONG): HRESULT; stdcall;
  424.     function Reset: HRESULT; stdcall;
  425.     function Clone(out ppEnum: IEnumMediaTypes): HRESULT; stdcall;
  426.   end;
  427.   TBCBaseOutputPin = class(TBCBasePin)
  428.   protected
  429.     FAllocator: IMemAllocator;
  430.     // interface on the downstreaminput pin, set up in CheckConnect when we connect.
  431.     FInputPin : IMemInputPin;
  432.   public
  433.     constructor Create(ObjectName: string; Filter: TBCBaseFilter; Lock: TBCCritSec;
  434.       out hr: HRESULT; const Name: WideString);
  435.     // override CompleteConnect() so we can negotiate an allocator
  436.     function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  437.     // negotiate the allocator and its buffer size/count and other properties
  438.     // Calls DecideBufferSize to set properties
  439.     function DecideAllocator(Pin: IMemInputPin; out Alloc: IMemAllocator): HRESULT; virtual;
  440.     // override this to set the buffer size and count. Return an error
  441.     // if the size/count is not to your liking.
  442.     // The allocator properties passed in are those requested by the
  443.     // input pin - use eg the alignment and prefix members if you have
  444.     // no preference on these.
  445.     function DecideBufferSize(Alloc: IMemAllocator; propInputRequest: PAllocatorProperties): HRESULT; virtual;
  446.     // returns an empty sample buffer from the allocator
  447.     function GetDeliveryBuffer(out Sample: IMediaSample; StartTime: PReferenceTime;
  448.       EndTime: PReferenceTime; Flags: Longword): HRESULT; virtual;
  449.     // deliver a filled-in sample to the connected input pin
  450.     // note - you need to release it after calling this. The receiving
  451.     // pin will addref the sample if it needs to hold it beyond the
  452.     // call.
  453.     function Deliver(Sample: IMediaSample): HRESULT; virtual;
  454.     // override this to control the connection
  455.     function InitAllocator(out Alloc: IMemAllocator): HRESULT; virtual;
  456.     function CheckConnect(Pin: IPin): HRESULT; override;
  457.     function BreakConnect: HRESULT; override;
  458.     // override to call Commit and Decommit
  459.     function Active: HRESULT; override;
  460.     function Inactive: HRESULT; override;
  461.     // we have a default handling of EndOfStream which is to return
  462.     // an error, since this should be called on input pins only
  463.     function EndOfStream: HRESULT; override; stdcall;
  464.     // called from elsewhere in our filter to pass EOS downstream to
  465.     // our connected input pin
  466.     function DeliverEndOfStream: HRESULT; virtual;
  467.     // same for Begin/EndFlush - we handle Begin/EndFlush since it
  468.     // is an error on an output pin, and we have Deliver methods to
  469.     // call the methods on the connected pin
  470.     function BeginFlush: HRESULT; override; stdcall;
  471.     function EndFlush: HRESULT; override; stdcall;
  472.     function DeliverBeginFlush: HRESULT; virtual;
  473.     function DeliverEndFlush: HRESULT; virtual;
  474.     // deliver NewSegment to connected pin - you will need to
  475.     // override this if you queue any data in your output pin.
  476.     function DeliverNewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; virtual;
  477.   end;
  478.   TBCBaseInputPin = class(TBCBasePin, IMemInputPin)
  479.   protected
  480.     FAllocator: IMemAllocator;    // Default memory allocator
  481.     // allocator is read-only, so received samples
  482.     // cannot be modified (probably only relevant to in-place
  483.     // transforms
  484.     FReadOnly: boolean;
  485.     //private:  this should really be private... only the MPEG code
  486.     // currently looks at it directly and it should use IsFlushing().
  487.     // in flushing state (between BeginFlush and EndFlush)
  488.     // if True, all Receives are returned with S_FALSE
  489.     FFlushing: boolean;
  490.     // Sample properties - initalized in Receive
  491.     FSampleProps: TAMSample2Properties;
  492.   public
  493.     constructor Create(ObjectName: string; Filter: TBCBaseFilter;
  494.       Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  495.     destructor Destroy; override;
  496.     // ----------IMemInputPin--------------
  497.     // return the allocator interface that this input pin
  498.     // would like the output pin to use
  499.     function GetAllocator(out ppAllocator: IMemAllocator): HRESULT; stdcall;
  500.     // tell the input pin which allocator the output pin is actually
  501.     // going to use.
  502.     function NotifyAllocator(pAllocator: IMemAllocator; bReadOnly: BOOL): HRESULT; stdcall;
  503.     // this method is optional (can return E_NOTIMPL).
  504.     // default implementation returns E_NOTIMPL. Override if you have
  505.     // specific alignment or prefix needs, but could use an upstream
  506.     // allocator
  507.     function GetAllocatorRequirements(out pProps: TAllocatorProperties): HRESULT; stdcall;
  508.     // do something with this media sample
  509.     function Receive(pSample: IMediaSample): HRESULT; virtual; stdcall;
  510.     // do something with these media samples
  511.     function ReceiveMultiple(var pSamples: IMediaSample; nSamples: Longint;
  512.         out nSamplesProcessed: Longint): HRESULT; stdcall;
  513.      // See if Receive() blocks
  514.     function ReceiveCanBlock: HRESULT; stdcall;
  515.     //-----------Helper-------------
  516.     // Default handling for BeginFlush - call at the beginning
  517.     // of your implementation (makes sure that all Receive calls
  518.     // fail). After calling this, you need to free any queued data
  519.     // and then call downstream.
  520.     function BeginFlush: HRESULT; override; stdcall;
  521.     // default handling for EndFlush - call at end of your implementation
  522.     // - before calling this, ensure that there is no queued data and no thread
  523.     // pushing any more without a further receive, then call downstream,
  524.     // then call this method to clear the m_bFlushing flag and re-enable
  525.     // receives
  526.     function EndFlush: HRESULT; override; stdcall;
  527.     // Release the pin's allocator.
  528.     function BreakConnect: HRESULT; override;
  529.     // helper method to check the read-only flag
  530.     property IsReadOnly: boolean read FReadOnly;
  531.     // helper method to see if we are flushing
  532.     property IsFlushing: boolean read FFlushing;
  533.     //  Override this for checking whether it's OK to process samples
  534.     //  Also call this from EndOfStream.
  535.     function CheckStreaming: HRESULT; virtual;
  536.     // Pass a Quality notification on to the appropriate sink
  537.     function PassNotify(const q: TQuality): HRESULT;
  538.     //================================================================================
  539.     // IQualityControl methods (from CBasePin)
  540.     //================================================================================
  541.     function Notify(pSelf: IBaseFilter; q: TQuality): HRESULT; override; stdcall;
  542.     // no need to override:
  543.     // STDMETHODIMP SetSink(IQualityControl * piqc);
  544.     // switch the pin to inactive state - may already be inactive
  545.     function Inactive: HRESULT; override;
  546.     // Return sample properties pointer
  547.     function SampleProps: PAMSample2Properties;
  548.   end;
  549. // milenko start (added TBCDynamicOutputPin conversion)
  550.   TBLOCK_STATE = (NOT_BLOCKED, PENDING, BLOCKED);
  551.   TBCDynamicOutputPin = class(TBCBaseOutputPin, IPinFlowControl)
  552.   public
  553.     constructor Create(ObjectName: WideString; Filter: TBCBaseFilter;
  554.                        Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  555.     destructor Destroy; override;
  556.     // IUnknown Methods
  557.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override;
  558.     // IPin Methods
  559.     function Disconnect: HRESULT; override; stdcall;
  560.     // IPinFlowControl Methods
  561.     function Block(dwBlockFlags: DWORD; hEvent: THandle): HResult; stdcall;
  562.     //  Set graph config info
  563.     procedure SetConfigInfo(GraphConfig: IGraphConfig; StopEvent: THandle);
  564.     {$IFDEF DEBUG}
  565.     function Deliver(Sample: IMediaSample): HRESULT; override;
  566.     function DeliverEndOfStream: HRESULT; override;
  567.     function DeliverNewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; override;
  568.     {$ENDIF} // DEBUG
  569.     function DeliverBeginFlush: HRESULT; override;
  570.     function DeliverEndFlush: HRESULT; override;
  571.     function Active: HRESULT; override;
  572.     function Inactive: HRESULT; override;
  573.     function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  574.     function StartUsingOutputPin: HRESULT; virtual;
  575.     procedure StopUsingOutputPin; virtual;
  576.     function StreamingThreadUsingOutputPin: Boolean; virtual;
  577.     function ChangeOutputFormat(const pmt: PAMMediaType; tSegmentStart, tSegmentStop:
  578.                                 TreferenceTime; dSegmentRate: Double): HRESULT;
  579.     function ChangeMediaType(const pmt: PAMMEdiaType): HRESULT;
  580.     function DynamicReconnect(const pmt: PAMMediaType): HRESULT;
  581.   protected
  582.     // This lock should be held when the following class members are
  583.     // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState,
  584.     // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers.
  585.     FBlockStateLock: TBCCritSec;
  586.     // This event should be signaled when the output pin is
  587.     // not blocked.  This is a manual reset event.  For more
  588.     // information on events, see the documentation for
  589.     // CreateEvent() in the Windows SDK.
  590.     FUnblockOutputPinEvent: THandle;
  591.     // This event will be signaled when block operation succeedes or
  592.     // when the user cancels the block operation.  The block operation
  593.     // can be canceled by calling IPinFlowControl2::Block( 0, NULL )
  594.     // while the block operation is pending.
  595.     FNotifyCallerPinBlockedEvent: THandle;
  596.     // The state of the current block operation.
  597.     FBlockState: TBLOCK_STATE;
  598.     // The ID of the thread which last called IPinFlowControl::Block().
  599.     // For more information on thread IDs, see the documentation for
  600.     // GetCurrentThreadID() in the Windows SDK.
  601.     FBlockCallerThreadID: DWORD;
  602.     // The number of times StartUsingOutputPin() has been sucessfully
  603.     // called and a corresponding call to StopUsingOutputPin() has not
  604.     // been made.  When this variable is greater than 0, the streaming
  605.     // thread is calling IPin::NewSegment(), IPin::EndOfStream(),
  606.     // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple().  The
  607.     // streaming thread could also be calling: DynamicReconnect(),
  608.     // ChangeMediaType() or ChangeOutputFormat().  The output pin cannot
  609.     // be blocked while the output pin is being used.
  610.     FNumOutstandingOutputPinUsers: DWORD;
  611.     // This event should be set when the IMediaFilter::Stop() is called.
  612.     // This is a manual reset event.  It is also set when the output pin
  613.     // delivers a flush to the connected input pin.
  614.     FStopEvent: THandle;
  615.     FGraphConfig: IGraphConfig;
  616.     // TRUE if the output pin's allocator's samples are read only.
  617.     // Otherwise FALSE.  For more information, see the documentation
  618.     // for IMemInputPin::NotifyAllocator().
  619.     FPinUsesReadOnlyAllocator: Boolean;
  620.     function SynchronousBlockOutputPin: HRESULT;
  621.     function AsynchronousBlockOutputPin(NotifyCallerPinBlockedEvent: THandle): HRESULT;
  622.     function UnblockOutputPin: HRESULT;
  623.     procedure BlockOutputPin;
  624.     procedure ResetBlockState;
  625.     class function WaitEvent(Event: THandle): HRESULT;
  626.   private
  627.     function Initialize: HRESULT;
  628.     function ChangeMediaTypeHelper(const pmt: PAMMediaType): HRESULT;
  629.     {$IFDEF DEBUG}
  630.     procedure AssertValid;
  631.     {$ENDIF} // DEBUG
  632.   end;
  633. // milenko end
  634.   TBCTransformOutputPin = class;
  635.   TBCTransformInputPin  = class;
  636.   TBCTransformFilter = class(TBCBaseFilter)
  637.   protected
  638.     FEOSDelivered  : boolean; // have we sent EndOfStream
  639.     FSampleSkipped : boolean; // Did we just skip a frame
  640.     FQualityChanged: boolean; // Have we degraded?
  641.     // critical section protecting filter state.
  642.     FcsFilter: TBCCritSec;
  643.     // critical section stopping state changes (ie Stop) while we're
  644.     // processing a sample.
  645.     //
  646.     // This critical section is held when processing
  647.     // events that occur on the receive thread - Receive() and EndOfStream().
  648.     //
  649.     // If you want to hold both m_csReceive and m_csFilter then grab
  650.     // m_csFilter FIRST - like CTransformFilter::Stop() does.
  651.     FcsReceive: TBCCritSec;
  652.     // these hold our input and output pins
  653.     FInput : TBCTransformInputPin;
  654.     FOutput: TBCTransformOutputPin;
  655.   public
  656.     // map getpin/getpincount for base enum of pins to owner
  657.     // override this to return more specialised pin objects
  658.     function GetPinCount: integer; override;
  659.     function GetPin(n: integer): TBCBasePin; override;
  660.     function FindPin(Id: PWideChar; out ppPin: IPin): HRESULT; override; stdcall;
  661.     // override state changes to allow derived transform filter
  662.     // to control streaming start/stop
  663.     function Stop: HRESULT; override; stdcall;
  664.     function Pause: HRESULT; override; stdcall;
  665.     constructor Create(ObjectName: string; unk: IUnKnown; const clsid: TGUID);
  666.     constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); override;
  667.     destructor destroy; override;
  668.     // =================================================================
  669.     // ----- override these bits ---------------------------------------
  670.     // =================================================================
  671.     // These must be supplied in a derived class
  672.     function Transform(msIn, msout: IMediaSample): HRESULT; virtual;
  673.     // check if you can support mtIn
  674.     function CheckInputType(mtIn: PAMMediaType): HRESULT; virtual; abstract;
  675.     // check if you can support the transform from this input to this output
  676.     function CheckTransform(mtIn, mtOut: PAMMediaType): HRESULT; virtual; abstract;
  677.     // this goes in the factory template table to create new instances
  678.     // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
  679.     // call the SetProperties function with appropriate arguments
  680.     function DecideBufferSize(Allocator: IMemAllocator; prop: PAllocatorProperties): HRESULT; virtual; abstract;
  681.     // override to suggest OUTPUT pin media types
  682.     function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; virtual; abstract;
  683.     // =================================================================
  684.     // ----- Optional Override Methods           -----------------------
  685.     // =================================================================
  686.     // you can also override these if you want to know about streaming
  687.     function StartStreaming: HRESULT; virtual;
  688.     function StopStreaming: HRESULT; virtual;
  689.     // override if you can do anything constructive with quality notifications
  690.     function AlterQuality(const q: TQuality): HRESULT; virtual;
  691.     // override this to know when the media type is actually set
  692.     function SetMediaType(direction: TPinDirection; pmt: PAMMediaType): HRESULT; virtual;
  693.     // chance to grab extra interfaces on connection
  694.     function CheckConnect(dir: TPinDirection; Pin: IPin): HRESULT; virtual;
  695.     function BreakConnect(dir: TPinDirection): HRESULT; virtual;
  696.     function CompleteConnect(direction: TPinDirection; ReceivePin: IPin): HRESULT; virtual;
  697.     // chance to customize the transform process
  698.     function Receive(Sample: IMediaSample): HRESULT; virtual;
  699.     // Standard setup for output sample
  700.     function InitializeOutputSample(Sample: IMediaSample; out OutSample: IMediaSample): HRESULT; virtual;
  701.     // if you override Receive, you may need to override these three too
  702.     function EndOfStream: HRESULT; virtual;
  703.     function BeginFlush: HRESULT; virtual;
  704.     function EndFlush: HRESULT; virtual;
  705.     function NewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; virtual;
  706.     property Input: TBCTransformInputPin read FInput write FInput;
  707.     property Output: TBCTransformOutputPin read FOutPut write FOutput;
  708.   end;
  709.   TBCTransformInputPin = class(TBCBaseInputPin)
  710.   private
  711.     FTransformFilter: TBCTransformFilter;
  712.   public
  713.     constructor Create(ObjectName: string; TransformFilter: TBCTransformFilter;
  714.       out hr: HRESULT; Name: WideString);
  715.     destructor destroy; override;
  716.     function QueryId(out id: PWideChar): HRESULT; override; stdcall;
  717.     // Grab and release extra interfaces if required
  718.     function CheckConnect(Pin: IPin): HRESULT; override;
  719.     function BreakConnect: HRESULT; override;
  720.     function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  721.     // check that we can support this output type
  722.     function CheckMediaType(mtIn: PAMMediaType): HRESULT; override;
  723.     // set the connection media type
  724.     function SetMediaType(mt: PAMMediaType): HRESULT; override;
  725.     // --- IMemInputPin -----
  726.     // here's the next block of data from the stream.
  727.     // AddRef it yourself if you need to hold it beyond the end
  728.     // of this call.
  729.     function Receive(pSample: IMediaSample): HRESULT; override; stdcall;
  730.     // provide EndOfStream that passes straight downstream
  731.     // (there is no queued data)
  732.     function EndOfStream: HRESULT; override; stdcall;
  733.     // passes it to CTransformFilter::BeginFlush
  734.     function BeginFlush: HRESULT; override; stdcall;
  735.     // passes it to CTransformFilter::EndFlush
  736.     function EndFlush: HRESULT; override; stdcall;
  737.     function NewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; override; stdcall;
  738.     // Check if it's OK to process samples
  739.     function CheckStreaming: HRESULT; override;
  740.   end;
  741.   TBCTransformOutputPin = class(TBCBaseOutputPin)
  742.   protected
  743.     FTransformFilter: TBCTransformFilter;
  744.     // implement IMediaPosition by passing upstream
  745.     FPosition: IUnknown;
  746.   public
  747.     constructor Create(ObjectName: string; TransformFilter: TBCTransformFilter;
  748.       out hr: HRESULT; Name: WideString);
  749.     destructor destroy; override;
  750.     // override to expose IMediaPosition
  751.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override;
  752.     // --- TBCBaseOutputPin ------------
  753.     function QueryId(out Id: PWideChar): HRESULT; override; stdcall;
  754.     // Grab and release extra interfaces if required
  755.     function CheckConnect(Pin: IPin): HRESULT; override;
  756.     function BreakConnect: HRESULT; override;
  757.     function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  758.     // check that we can support this output type
  759.     function CheckMediaType(mtOut: PAMMediaType): HRESULT; override;
  760.     // set the connection media type
  761.     function SetMediaType(pmt: PAMMediaType): HRESULT; override;
  762.     // called from CBaseOutputPin during connection to ask for
  763.     // the count and size of buffers we need.
  764.     function DecideBufferSize(Alloc: IMemAllocator; Prop: PAllocatorProperties): HRESULT; override;
  765.     // returns the preferred formats for a pin
  766.     function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; override;
  767.     // inherited from IQualityControl via CBasePin
  768.     function Notify(Sendr: IBaseFilter; q: TQuality): HRESULT; override; stdcall;
  769.   end;
  770. // milenko start (added TBCVideoTransformFilter conversion)
  771.   TBCVideoTransformFilter = class(TBCTransformFilter)
  772.   public
  773.     constructor Create(Name: WideString; Unk: IUnknown; clsid: TGUID);
  774.     destructor Destroy; override;
  775.     function EndFlush: HRESULT; override;
  776.     // =================================================================
  777.     // ----- override these bits ---------------------------------------
  778.     // =================================================================
  779.     // The following methods are in CTransformFilter which is inherited.
  780.     // They are mentioned here for completeness
  781.     //
  782.     // These MUST be supplied in a derived class
  783.     //
  784.     // NOTE:
  785.     // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
  786.     // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
  787.     // virtual HRESULT CheckTransform
  788.     //     (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
  789.     // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
  790.     // virtual HRESULT DecideBufferSize
  791.     //     (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
  792.     // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
  793.     //
  794.     // These MAY also be overridden
  795.     //
  796.     // virtual HRESULT StopStreaming();
  797.     // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
  798.     // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
  799.     // virtual HRESULT BreakConnect(PIN_DIRECTION dir);
  800.     // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
  801.     // virtual HRESULT EndOfStream(void);
  802.     // virtual HRESULT BeginFlush(void);
  803.     // virtual HRESULT EndFlush(void);
  804.     // virtual HRESULT NewSegment
  805.     //     (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
  806.   {$IFDEF PERF}
  807.     // If you override this - ensure that you register all these ids
  808.     // as well as any of your own,
  809.     procedure RegisterPerfId; virtual;
  810.   {$ENDIF}
  811.   protected
  812.     // =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
  813.     // Frames are assumed to come in three types:
  814.     // Type 1: an AVI key frame or an MPEG I frame.
  815.     //        This frame can be decoded with no history.
  816.     //        Dropping this frame means that no further frame can be decoded
  817.     //        until the next type 1 frame.
  818.     //        Type 1 frames are sync points.
  819.     // Type 2: an AVI non-key frame or an MPEG P frame.
  820.     //        This frame cannot be decoded unless the previous type 1 frame was
  821.     //        decoded and all type 2 frames since have been decoded.
  822.     //        Dropping this frame means that no further frame can be decoded
  823.     //        until the next type 1 frame.
  824.     // Type 3: An MPEG B frame.
  825.     //        This frame cannot be decoded unless the previous type 1 or 2 frame
  826.     //        has been decoded AND the subsequent type 1 or 2 frame has also
  827.     //        been decoded.  (This requires decoding the frames out of sequence).
  828.     //        Dropping this frame affects no other frames.  This implementation
  829.     //        does not allow for these.  All non-sync-point frames are treated
  830.     //        as being type 2.
  831.     //
  832.     // The spacing of frames of type 1 in a file is not guaranteed.  There MUST
  833.     // be a type 1 frame at (well, near) the start of the file in order to start
  834.     // decoding at all.  After that there could be one every half second or so,
  835.     // there could be one at the start of each scene (aka "cut", "shot") or
  836.     // there could be no more at all.
  837.     // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
  838.     // without losing all the rest of the movie.  There is no way to tell whether
  839.     // this is the case, so we find that we are in the gambling business.
  840.     // To try to improve the odds, we record the greatest interval between type 1s
  841.     // that we have seen and we bet on things being no worse than this in the
  842.     // future.
  843.     // You can tell if it's a type 1 frame by calling IsSyncPoint().
  844.     // there is no architected way to test for a type 3, so you should override
  845.     // the quality management here if you have B-frames.
  846.     FKeyFramePeriod: integer; // the largest observed interval between type 1 frames
  847.                               // 1 means every frame is type 1, 2 means every other.
  848.     FFramesSinceKeyFrame: integer; // Used to count frames since the last type 1.
  849.                                    // becomes the new m_nKeyFramePeriod if greater.
  850.     FSkipping: Boolean;           // we are skipping to the next type 1 frame
  851.   {$IFDEF PERF}
  852.     FidFrameType: integer;          // MSR id Frame type.  1=Key, 2="non-key"
  853.     FidSkip: integer;               // MSR id skipping
  854.     FidLate: integer;               // MSR id lateness
  855.     FidTimeTillKey: integer;        // MSR id for guessed time till next key frame.
  856.   {$ENDIF}
  857.     FitrLate: integer;          // lateness from last Quality message
  858.                                 // (this overflows at 214 secs late).
  859.     FtDecodeStart: integer;     // timeGetTime when decode started.
  860.     FitrAvgDecode: integer;     // Average decode time in reference units.
  861.     FNoSkip: Boolean;            // debug - no skipping.
  862.     // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
  863.     // We send one when we start degrading, not one for every frame, this means
  864.     // we track whether we've sent one yet.
  865.     FQualityChanged: Boolean;
  866.     // When non-zero, don't pass anything to renderer until next keyframe
  867.     // If there are few keys, give up and eventually draw something
  868.     FWaitForKey: integer;
  869.     function AbortPlayback(hr: HRESULT): HRESULT;  // if something bad happens
  870.     function ShouldSkipFrame(pIn: IMediaSample): Boolean;
  871.   public
  872.     function StartStreaming: HRESULT; override;
  873.     function Receive(Sample: IMediaSample): HRESULT; override;
  874.     function AlterQuality(const q: TQuality): HRESULT; override;
  875.   end;
  876. // milenko end
  877.   TBCTransInPlaceOutputPin = class;
  878.   TBCTransInPlaceInputPin  = class;
  879.   TBCTransInPlaceFilter = class(TBCTransformFilter)
  880.   public
  881.     // map getpin/getpincount for base enum of pins to owner
  882.     // override this to return more specialised pin objects
  883.     function GetPin(n: integer): TBCBasePin; override;
  884.     //  Set bModifiesData == false if your derived filter does
  885.     //  not modify the data samples (for instance it's just copying
  886.     //  them somewhere else or looking at the timestamps).
  887.     constructor Create(ObjectName: string; unk: IUnKnown; clsid: TGUID;
  888.       out hr: HRESULT; ModifiesData: boolean = True);
  889.     constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); override;
  890.     // The following are defined to avoid undefined pure virtuals.
  891.     // Even if they are never called, they will give linkage warnings/errors
  892.     // We override EnumMediaTypes to bypass the transform class enumerator
  893.     // which would otherwise call this.
  894.     function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; override;
  895.     // This is called when we actually have to provide out own allocator.
  896.     function DecideBufferSize(Alloc: IMemAllocator; propInputRequest: PAllocatorProperties): HRESULT; override;
  897.     // The functions which call this in CTransform are overridden in this
  898.     // class to call CheckInputType with the assumption that the type
  899.     // does not change.  In Debug builds some calls will be made and
  900.     // we just ensure that they do not assert.
  901.     function CheckTransform(mtIn, mtOut: PAMMediaType): HRESULT; override;
  902.     // =================================================================
  903.     // ----- You may want to override this -----------------------------
  904.     // =================================================================
  905.     function CompleteConnect(dir: TPinDirection; ReceivePin: IPin): HRESULT; override;
  906.     // chance to customize the transform process
  907.     function Receive(Sample: IMediaSample): HRESULT; override;
  908.     // =================================================================
  909.     // ----- You MUST override these -----------------------------------
  910.     // =================================================================
  911.     function Transform(Sample: IMediaSample): HRESULT; reintroduce; virtual; abstract;
  912.     // this goes in the factory template table to create new instances
  913.     // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
  914.   protected
  915.     FModifiesData: boolean; // Does this filter change the data?
  916.     function Copy(Source: IMediaSample): IMediaSample;
  917.     // these hold our input and output pins
  918.     function InputPin: TBCTransInPlaceInputPin;
  919.     function OutputPin: TBCTransInPlaceOutputPin;
  920.     //  Helper to see if the input and output types match
  921.     function TypesMatch: boolean;
  922.     //  Are the input and output allocators different?
  923.     function UsingDifferentAllocators: boolean;
  924.   end;
  925.   TBCTransInPlaceInputPin = class(TBCTransformInputPin)
  926.   protected
  927.     FTIPFilter: TBCTransInPlaceFilter; // our filter
  928.     FReadOnly : boolean;               // incoming stream is read only
  929.   public
  930.     constructor Create(ObjectName: string; Filter: TBCTransInPlaceFilter;
  931.       out hr: HRESULT; Name: WideString);
  932.     // --- IMemInputPin -----
  933.     // Provide an enumerator for media types by getting one from downstream
  934.     function EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT; override; stdcall;
  935.     // Say whether media type is acceptable.
  936.     function CheckMediaType(pmt: PAMMediaType): HRESULT; override;
  937.     // Return our upstream allocator
  938.     function GetAllocator(out Allocator: IMemAllocator): HRESULT; stdcall;
  939.     // get told which allocator the upstream output pin is actually
  940.     // going to use.
  941.     function NotifyAllocator(Allocator: IMemAllocator; ReadOnly: BOOL): HRESULT; stdcall;
  942.     // Allow the filter to see what allocator we have
  943.     // N.B. This does NOT AddRef
  944.     function PeekAllocator: IMemAllocator;
  945.     // Pass this on downstream if it ever gets called.
  946.     function GetAllocatorRequirements(props: PAllocatorProperties): HRESULT; stdcall;
  947.     property ReadOnly: Boolean read FReadOnly;
  948.   end;
  949. // ==================================================
  950. // Implements the output pin
  951. // ==================================================
  952.   TBCTransInPlaceOutputPin = class(TBCTransformOutputPin)
  953.   protected
  954.     // m_pFilter points to our CBaseFilter
  955.     FTIPFilter: TBCTransInPlaceFilter;
  956.   public
  957.     constructor Create(ObjectName: string; Filter: TBCTransInPlaceFilter;
  958.       out hr: HRESULT; Name: WideString);
  959.     // --- CBaseOutputPin ------------
  960.     // negotiate the allocator and its buffer size/count
  961.     // Insists on using our own allocator.  (Actually the one upstream of us).
  962.     // We don't override this - instead we just agree the default
  963.     // then let the upstream filter decide for itself on reconnect
  964.     // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
  965.     // Provide a media type enumerator.  Get it from upstream.
  966.     function EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT; override; stdcall;
  967.     // Say whether media type is acceptable.
  968.     function CheckMediaType(pmt: PAMMediaType): HRESULT; override;
  969.     //  This just saves the allocator being used on the output pin
  970.     //  Also called by input pin's GetAllocator()
  971.     procedure SetAllocator(Allocator: IMemAllocator);
  972.     function ConnectedIMemInputPin: IMemInputPin;
  973.     // Allow the filter to see what allocator we have
  974.     // N.B. This does NOT AddRef
  975.     function PeekAllocator: IMemAllocator;
  976.   end;
  977.   TBCBasePropertyPage = class(TBCUnknown, IPropertyPage)
  978.   private
  979.     FObjectSet: boolean;          // SetObject has been called or not.
  980.   protected
  981.     FPageSite: IPropertyPageSite; // Details for our property site
  982.     FDirty: boolean;              // Has anything been changed
  983.     FForm: TFormPropertyPage;
  984.   public
  985.     constructor Create(Name: String; Unk: IUnKnown; Form: TFormPropertyPage);
  986.     destructor  Destroy; override;
  987.     procedure SetPageDirty;
  988.     { IPropertyPage }
  989.     function SetPageSite(const pageSite: IPropertyPageSite): HResult; stdcall;
  990.     function Activate(hwndParent: HWnd; const rc: TRect; bModal: BOOL): HResult; stdcall;
  991.     function Deactivate: HResult; stdcall;
  992.     function GetPageInfo(out pageInfo: TPropPageInfo): HResult; stdcall;
  993.     function SetObjects(cObjects: Longint; pUnkList: PUnknownList): HResult; stdcall;
  994.     function Show(nCmdShow: Integer): HResult; stdcall;
  995.     function Move(const rect: TRect): HResult; stdcall;
  996.     function IsPageDirty: HResult; stdcall;
  997.     function Apply: HResult; stdcall;
  998.     function Help(pszHelpDir: POleStr): HResult; stdcall;
  999.     function TranslateAccelerator(msg: PMsg): HResult; stdcall;
  1000.   end;
  1001.   TOnConnect = procedure(sender: Tobject; Unknown: IUnknown) of object;
  1002.   TFormPropertyPage = class(TForm, IUnKnown, IPropertyPage)
  1003.   private
  1004.     FPropertyPage: TBCBasePropertyPage;
  1005.     procedure MyWndProc(var aMsg: TMessage);
  1006.   public
  1007.     constructor Create(AOwner: TComponent); override;
  1008.   published
  1009.     function OnConnect(Unknown: IUnknown): HRESULT; virtual;
  1010.     function OnDisconnect: HRESULT; virtual;
  1011.     function OnApplyChanges: HRESULT; virtual;
  1012.     property PropertyPage   : TBCBasePropertyPage read FPropertyPage implements IUnKnown, IPropertyPage;
  1013.   end;
  1014.   TBCBaseDispatch = class{IDispatch}
  1015.   protected
  1016.     FTI: ITypeInfo;
  1017.   public
  1018.     // IDispatch methods
  1019.     function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1020.     function GetTypeInfo(const iid: TGUID; info: Cardinal; lcid: LCID; out tinfo): HRESULT; stdcall;
  1021.     function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1022.       NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1023.   end;
  1024.   TBCMediaControl = class(TBCUnknown, IDispatch)
  1025.   public
  1026.     FBaseDisp: TBCBaseDispatch;
  1027.     constructor Create(name: string; unk: IUnknown);
  1028.     destructor Destroy; override;
  1029.     // IDispatch methods
  1030.     function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1031.     function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  1032.     function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1033.       NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1034.     function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1035.       Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  1036.   end;
  1037.   TBCMediaEvent = class(TBCUnknown, IDisPatch{,IMediaEventEx})
  1038.   protected
  1039.     FBasedisp: TBCBaseDispatch;
  1040.   public
  1041.     constructor Create(Name: string; Unk: IUnknown);
  1042.     destructor destroy; override;
  1043.     // IDispatch methods
  1044.     function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1045.     function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  1046.     function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1047.       NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1048.     function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1049.       Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  1050.   end;
  1051.   TBCMediaPosition = class(TBCUnknown, IDispatch {IMediaPosition})
  1052.   protected
  1053.     FBaseDisp: TBCBaseDispatch;
  1054.   public
  1055.     constructor Create(Name: String; Unk: IUnknown); overload;
  1056.     constructor Create(Name: String; Unk: IUnknown; out hr: HRESULT); overload;
  1057.     destructor Destroy; override;
  1058.     // IDispatch methods
  1059.     function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1060.     function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  1061.     function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1062.       NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1063.     function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1064.       Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  1065.   end;
  1066. // A utility class that handles IMediaPosition and IMediaSeeking on behalf
  1067. // of single-input pin renderers, or transform filters.
  1068. //
  1069. // Renderers will expose this from the filter; transform filters will
  1070. // expose it from the output pin and not the renderer.
  1071. //
  1072. // Create one of these, giving it your IPin* for your input pin, and delegate
  1073. // all IMediaPosition methods to it. It will query the input pin for
  1074. // IMediaPosition and respond appropriately.
  1075. //
  1076. // Call ForceRefresh if the pin connection changes.
  1077. //
  1078. // This class no longer caches the upstream IMediaPosition or IMediaSeeking
  1079. // it acquires it on each method call. This means ForceRefresh is not needed.
  1080. // The method is kept for source compatibility and to minimise the changes
  1081. // if we need to put it back later for performance reasons.
  1082.   TBCPosPassThru = class(TBCMediaPosition, IMediaSeeking)
  1083.   protected
  1084.     FPin: IPin;
  1085.     function GetPeer(out MP: IMediaPosition): HRESULT;
  1086.     function GetPeerSeeking(out MS: IMediaSeeking): HRESULT;
  1087.   public
  1088.     constructor Create(name: String; Unk: IUnknown; out hr: HRESULT; Pin: IPin);
  1089.     function ForceRefresh: HRESULT;{return S_OK;}
  1090.     // override to return an accurate current position
  1091.     function GetMediaTime(out StartTime, EndTime: int64): HRESULT; virtual;
  1092.     // IMediaSeeking methods
  1093.     function GetCapabilities(out pCapabilities: DWORD): HRESULT; stdcall;
  1094.     function CheckCapabilities(var pCapabilities: DWORD): HRESULT; stdcall;
  1095.     function IsFormatSupported(const pFormat: TGUID): HRESULT; stdcall;
  1096.     function QueryPreferredFormat(out pFormat: TGUID): HRESULT; stdcall;
  1097.     function GetTimeFormat(out pFormat: TGUID): HRESULT; stdcall;
  1098.     function IsUsingTimeFormat(const pFormat: TGUID): HRESULT; stdcall;
  1099.     function SetTimeFormat(const pFormat: TGUID): HRESULT; stdcall;
  1100.     function GetDuration(out pDuration: int64): HRESULT; stdcall;
  1101.     function GetStopPosition(out pStop: int64): HRESULT; stdcall;
  1102.     function GetCurrentPosition(out pCurrent: int64): HRESULT; stdcall;
  1103.     function ConvertTimeFormat(out pTarget: int64; pTargetFormat: PGUID;
  1104.                Source: int64; pSourceFormat: PGUID): HRESULT; stdcall;
  1105.     function SetPositions(var pCurrent: int64; dwCurrentFlags: DWORD;
  1106.                var pStop: int64; dwStopFlags: DWORD): HRESULT; stdcall;
  1107.     function GetPositions(out pCurrent, pStop: int64): HRESULT; stdcall;
  1108.     function GetAvailable(out pEarliest, pLatest: int64): HRESULT; stdcall;
  1109.     function SetRate(dRate: double): HRESULT; stdcall;
  1110.     function GetRate(out pdRate: double): HRESULT; stdcall;
  1111.     function GetPreroll(out pllPreroll: int64): HRESULT; stdcall;
  1112.     // IMediaPosition properties
  1113.     function get_Duration(out plength: TRefTime): HResult; stdcall;
  1114.     function put_CurrentPosition(llTime: TRefTime): HResult; stdcall;
  1115.     function get_CurrentPosition(out pllTime: TRefTime): HResult; stdcall;
  1116.     function get_StopTime(out pllTime: TRefTime): HResult; stdcall;
  1117.     function put_StopTime(llTime: TRefTime): HResult; stdcall;
  1118.     function get_PrerollTime(out pllTime: TRefTime): HResult; stdcall;
  1119.     function put_PrerollTime(llTime: TRefTime): HResult; stdcall;
  1120.     function put_Rate(dRate: double): HResult; stdcall;
  1121.     function get_Rate(out pdRate: double): HResult; stdcall;
  1122.     function CanSeekForward(out pCanSeekForward: Longint): HResult; stdcall;
  1123.     function CanSeekBackward(out pCanSeekBackward: Longint): HResult; stdcall;
  1124.   end;
  1125.   TBCRendererPosPassThru = class(TBCPosPassThru)
  1126.   protected
  1127.     FPositionLock: TBCCritSec; // Locks access to our position
  1128.     FStartMedia  : Int64;      // Start media time last seen
  1129.     FEndMedia    : Int64;      // And likewise the end media
  1130.     FReset       : boolean;    // Have media times been set
  1131.   public
  1132.     // Used to help with passing media times through graph
  1133.     constructor Create(name: String; Unk: IUnknown; out hr: HRESULT; Pin: IPin); reintroduce;
  1134.     destructor destroy; override;
  1135.     function RegisterMediaTime(MediaSample: IMediaSample): HRESULT; overload;
  1136.     function RegisterMediaTime(StartTime, EndTime: int64): HRESULT; overload;
  1137.     function GetMediaTime(out StartTime, EndTime: int64): HRESULT; override;
  1138.     function ResetMediaTime: HRESULT;
  1139.     function EOS: HRESULT;
  1140.   end;
  1141.   // wrapper for event objects
  1142.   TBCAMEvent = class
  1143.   protected
  1144.     FEvent: THANDLE;
  1145.   public
  1146.     constructor Create(ManualReset: boolean = false);
  1147.     destructor destroy; override;
  1148.     property Handle: THandle read FEvent;
  1149.     procedure SetEv;
  1150.     function Wait(Timeout: Cardinal = INFINITE): boolean;
  1151.     procedure Reset;
  1152.     function Check: boolean;
  1153.   end;
  1154.   TBCTimeoutEvent = TBCAMEvent;
  1155.   // wrapper for event objects that do message processing
  1156.   // This adds ONE method to the CAMEvent object to allow sent
  1157.   // messages to be processed while waiting
  1158.   TBCAMMsgEvent = class(TBCAMEvent)
  1159.   public
  1160.     // Allow SEND messages to be processed while waiting
  1161.     function WaitMsg(Timeout: DWord = INFINITE): boolean;
  1162.   end;
  1163.   // support for a worker thread
  1164.   // simple thread class supports creation of worker thread, synchronization
  1165.   // and communication. Can be derived to simplify parameter passing
  1166.   TThreadProc = function: DWORD of object;
  1167.   TBCAMThread = class
  1168.   private
  1169.     FEventSend: TBCAMEvent;
  1170.     FEventComplete: TBCAMEvent;
  1171.     FParam: DWord;
  1172.     FReturnVal: DWord;
  1173.     FThreadProc: TThreadProc;
  1174.   protected
  1175.     FThread: THandle;
  1176.     // thread will run this function on startup
  1177.     // must be supplied by derived class
  1178.     function ThreadProc: DWord; virtual;
  1179.   public
  1180.     FAccessLock: TBCCritSec; // locks access by client threads
  1181.     FWorkerLock: TBCCritSec; // locks access to shared objects
  1182.     constructor Create;
  1183.     destructor Destroy; override;
  1184.     // thread initially runs this. param is actually 'this'. function
  1185.     // just gets this and calls ThreadProc
  1186.     function InitialThreadProc(p: Pointer): DWORD; virtual; stdcall;  // WINAPI;
  1187.     // start thread running  - error if already running
  1188.     function Create_: boolean;
  1189.     // signal the thread, and block for a response
  1190.     //
  1191.     function CallWorker(Param: DWORD): DWORD;
  1192.     // accessor thread calls this when done with thread (having told thread
  1193.     // to exit)
  1194.     procedure Close;
  1195.     // ThreadExists
  1196.     // Return True if the thread exists. FALSE otherwise
  1197.     function ThreadExists: boolean; // const
  1198.     // wait for the next request
  1199.     function GetRequest: DWORD;
  1200.     // is there a request?
  1201.     function CheckRequest(Param: PDWORD): boolean;
  1202.     // reply to the request
  1203.     procedure Reply(v: DWORD);
  1204.     // If you want to do WaitForMultipleObjects you'll need to include
  1205.     // this handle in your wait list or you won't be responsive
  1206.     function GetRequestHandle: THANDLE;
  1207.     // Find out what the request was
  1208.     function GetRequestParam: DWORD;
  1209.     // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if
  1210.     // available. S_FALSE means it's not available.
  1211.     class function CoInitializeHelper: HRESULT;
  1212.   end;
  1213.   TBCRenderedInputPin = class(TBCBaseInputPin)
  1214.   private
  1215.     procedure DoCompleteHandling;
  1216.   protected
  1217.     // Member variables to track state
  1218.     FAtEndOfStream    : boolean; // Set by EndOfStream
  1219.     FCompleteNotified : boolean; // Set when we notify for EC_COMPLETE
  1220.   public
  1221.     constructor Create(ObjectName: string; Filter: TBCBaseFilter;
  1222.       Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  1223.     // Override methods to track end of stream state
  1224.     function EndOfStream: HRESULT; override; stdcall;
  1225.     function EndFlush: HRESULT; override; stdcall;
  1226.     function Active: HRESULT; override;
  1227.     function Run(Start: TReferenceTime): HRESULT; override;
  1228.   end;
  1229. (* A generic list of pointers to objects.
  1230.    No storage management or copying is done on the objects pointed to.
  1231.    Objectives: avoid using MFC libraries in ndm kernel mode and
  1232.    provide a really useful list type.
  1233.    The class is thread safe in that separate threads may add and
  1234.    delete items in the list concurrently although the application
  1235.    must ensure that constructor and destructor access is suitably
  1236.    synchronised. An application can cause deadlock with operations
  1237.    which use two lists by simultaneously calling
  1238.    list1->Operation(list2) and list2->Operation(list1).  So don't!
  1239.    The names must not conflict with MFC classes as an application
  1240.    may use both.
  1241.    *)
  1242.    (* A POSITION represents (in some fashion that's opaque) a cursor
  1243.       on the list that can be set to identify any element.  NULL is
  1244.       a valid value and several operations regard NULL as the position
  1245.       "one step off the end of the list".  (In an n element list there
  1246.       are n+1 places to insert and NULL is that "n+1-th" value).
  1247.       The POSITION of an element in the list is only invalidated if
  1248.       that element is deleted.  Move operations may mean that what
  1249.       was a valid POSITION in one list is now a valid POSITION in
  1250.       a different list.
  1251.       Some operations which at first sight are illegal are allowed as
  1252.       harmless no-ops.  For instance RemoveHead is legal on an empty
  1253.       list and it returns NULL.  This allows an atomic way to test if
  1254.       there is an element there, and if so, get it.  The two operations
  1255.       AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper).
  1256.       Single element operations return POSITIONs, non-NULL means it worked.
  1257.       whole list operations return a BOOL.  True means it all worked.
  1258.       This definition is the same as the POSITION type for MFCs, so we must
  1259.       avoid defining it twice.
  1260.    *)
  1261.   Position = Pointer;
  1262. {$ifdef DEBUG}
  1263.   TBCNode = class(TBCBaseObject)
  1264. {$else}
  1265.   TBCNode = class
  1266. {$endif}
  1267.   private
  1268.     FPrev: TBCNode;    // Previous node in the list
  1269.     FNext: TBCNode;    // Next node in the list
  1270.     FObject: Pointer;  // Pointer to the object
  1271.   public
  1272.     // Constructor - initialise the object's pointers
  1273. {$ifdef DEBUG}
  1274.     constructor Create;
  1275. {$endif}
  1276.     // Return the previous node before this one
  1277.     property Prev: TBCNode read FPrev write FPrev;
  1278.     // Return the next node after this one
  1279.     property Next: TBCNode read FNext write FNext;
  1280.     // Get the pointer to the object for this node */
  1281.     property Data: Pointer read FObject write FObject;
  1282.   end;
  1283.   TBCNodeCache = class
  1284.   private
  1285.     FCacheSize: Integer;
  1286.     FUsed: Integer;
  1287.     FHead: TBCNode;
  1288.   public
  1289.     constructor Create(CacheSize: Integer);
  1290.     destructor Destroy; override;
  1291.     procedure AddToCache(Node: TBCNode);
  1292.     function RemoveFromCache: TBCNode;
  1293.   end;
  1294. (* A class representing one node in a list.
  1295.    Each node knows a pointer to it's adjacent nodes and also a pointer
  1296.    to the object that it looks after.
  1297.    All of these pointers can be retrieved or set through member functions.
  1298. *)
  1299.   TBCBaseList = class
  1300. {$ifdef DEBUG}
  1301.     (TBCBaseObject)
  1302. {$endif}
  1303.     (* Making these classes inherit from CBaseObject does nothing
  1304.        functionally but it allows us to check there are no memory
  1305.        leaks in debug builds.
  1306.     *)
  1307.   protected
  1308.     FFirst: TBCNode; // Pointer to first node in the list
  1309.     FLast: TBCNode; // Pointer to the last node in the list
  1310.     FCount: LongInt;   // Number of nodes currently in the list
  1311.   private
  1312.     FCache: TBCNodeCache; // Cache of unused node pointers
  1313.   public
  1314.     constructor Create(Name: string; Items: Integer = DEFAULTCACHE);
  1315.     destructor Destroy; override;
  1316.     // Remove all the nodes from self i.e. make the list empty
  1317.     procedure RemoveAll;
  1318.     // Return a cursor which identifies the first element of self
  1319.     function GetHeadPositionI: Position;
  1320.     /// Return a cursor which identifies the last element of self
  1321.     function GetTailPositionI: Position;
  1322.     // Return the number of objects in self
  1323.     function GetCountI: Integer;
  1324.   protected
  1325.     (* Return the pointer to the object at rp,
  1326.        Update rp to the next node in self
  1327.        but make it nil if it was at the end of self.
  1328.        This is a wart retained for backwards compatibility.
  1329.        GetPrev is not implemented.
  1330.        Use Next, Prev and Get separately.
  1331.     *)
  1332.     function GetNextI(var rp: Position): Pointer;
  1333.     (* Return a pointer to the object at p
  1334.        Asking for the object at nil will return nil harmlessly.
  1335.     *)
  1336.     function GetI(p: Position): Pointer;
  1337.   public
  1338.     (* return the next / prev position in self
  1339.        return NULL when going past the end/start.
  1340.        Next(nil) is same as GetHeadPosition()
  1341.        Prev(nil) is same as GetTailPosition()
  1342.        An n element list therefore behaves like a n+1 element
  1343.        cycle with nil at the start/end.
  1344.        !!WARNING!! - This handling of nil is DIFFERENT from GetNext.
  1345.        Some reasons are:
  1346.        1. For a list of n items there are n+1 positions to insert
  1347.           These are conveniently encoded as the n POSITIONs and nil.
  1348.        2. If you are keeping a list sorted (fairly common) and you
  1349.           search forward for an element to insert before and don't
  1350.           find it you finish up with nil as the element before which
  1351.           to insert.  You then want that nil to be a valid POSITION
  1352.           so that you can insert before it and you want that insertion
  1353.           point to mean the (n+1)-th one that doesn't have a POSITION.
  1354.           (symmetrically if you are working backwards through the list).
  1355.        3. It simplifies the algebra which the methods generate.
  1356.           e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x)
  1357.           in ALL cases.  All the other arguments probably are reflections
  1358.           of the algebraic point.
  1359.     *)
  1360.     function Next(pos: Position): Position;
  1361.     function Prev(pos: Position): Position;
  1362.     (* Return the first position in self which holds the given
  1363.        pointer.  Return nil if the pointer was not not found.
  1364.     *)
  1365.   protected
  1366.     function FindI(Obj: Pointer): Position;
  1367.     (* Remove the first node in self (deletes the pointer to its
  1368.        object from the list, does not free the object itself).
  1369.        Return the pointer to its object.
  1370.        If self was already empty it will harmlessly return nil.
  1371.     *)
  1372.     function RemoveHeadI: Pointer;
  1373.     (* Remove the last node in self (deletes the pointer to its
  1374.        object from the list, does not free the object itself).
  1375.        Return the pointer to its object.
  1376.        If self was already empty it will harmlessly return nil.
  1377.     *)
  1378.     function RemoveTailI: Pointer;
  1379.     (* Remove the node identified by p from the list (deletes the pointer
  1380.        to its object from the list, does not free the object itself).
  1381.        Asking to Remove the object at nil will harmlessly return nil.
  1382.        Return the pointer to the object removed.
  1383.     *)
  1384.     function RemoveI(pos: Position): Pointer;
  1385.     (* Add single object *pObj to become a new last element of the list.
  1386.        Return the new tail position, nil if it fails.
  1387.        If you are adding a COM objects, you might want AddRef it first.
  1388.        Other existing POSITIONs in self are still valid
  1389.     *)
  1390.     function AddTailI(Obj: Pointer): Position;
  1391.   public
  1392.     (* Add all the elements in *pList to the tail of self.
  1393.        This duplicates all the nodes in *pList (i.e. duplicates
  1394.        all its pointers to objects).  It does not duplicate the objects.
  1395.        If you are adding a list of pointers to a COM object into the list
  1396.        it's a good idea to AddRef them all  it when you AddTail it.
  1397.        Return True if it all worked, FALSE if it didn't.
  1398.        If it fails some elements may have been added.
  1399.        Existing POSITIONs in self are still valid
  1400.        If you actually want to MOVE the elements, use MoveToTail instead.
  1401.     *)
  1402.     function AddTail(List: TBCBaseList): boolean;
  1403.     // Mirror images of AddHead:
  1404.     (* Add single object to become a new first element of the list.
  1405.        Return the new head position, nil if it fails.
  1406.        Existing POSITIONs in self are still valid
  1407.     *)
  1408.   protected
  1409.     function AddHeadI(Obj: Pointer): Position;
  1410.   public
  1411.     (* Add all the elements in *pList to the head of self.
  1412.        Same warnings apply as for AddTail.
  1413.        Return True if it all worked, FALSE if it didn't.
  1414.        If it fails some of the objects may have been added.
  1415.        If you actually want to MOVE the elements, use MoveToHead instead.
  1416.     *)
  1417.     function AddHead(List: TBCBaseList): BOOL;
  1418.     (* Add the object *pObj to self after position p in self.
  1419.        AddAfter(nil,x) adds x to the start - equivalent to AddHead
  1420.        Return the position of the object added, nil if it failed.
  1421.        Existing POSITIONs in self are undisturbed, including p.
  1422.     *)
  1423.   protected
  1424.     function AddAfterI(pos: Position; Obj: Pointer): Position;
  1425.   public
  1426.     (* Add the list *pList to self after position p in self
  1427.        AddAfter(nil,x) adds x to the start - equivalent to AddHead
  1428.        Return True if it all worked, FALSE if it didn't.
  1429.        If it fails, some of the objects may be added
  1430.        Existing POSITIONs in self are undisturbed, including p.
  1431.     *)
  1432.     function AddAfter(p: Position; List: TBCBaseList): BOOL;
  1433.     (* Mirror images:
  1434.        Add the object *pObj to this-List after position p in self.
  1435.        AddBefore(nil,x) adds x to the end - equivalent to AddTail
  1436.        Return the position of the new object, nil if it fails
  1437.        Existing POSITIONs in self are undisturbed, including p.
  1438.     *)
  1439.   protected
  1440.     function AddBeforeI(pos: Position; Obj: Pointer): Position;
  1441.   public
  1442.     (* Add the list *pList to self before position p in self
  1443.        AddAfter(nil,x) adds x to the start - equivalent to AddHead
  1444.        Return True if it all worked, FALSE if it didn't.
  1445.        If it fails, some of the objects may be added
  1446.        Existing POSITIONs in self are undisturbed, including p.
  1447.     *)
  1448.     function AddBefore(p: Position; List: TBCBaseList): BOOL;
  1449.     (* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x)
  1450.        even in cases where p is nil or Next(p) is nil.
  1451.        Similarly for mirror images etc.
  1452.        This may make it easier to argue about programs.
  1453.     *)
  1454.     (* The following operations do not copy any elements.
  1455.        They move existing blocks of elements around by switching pointers.
  1456.        They are fairly efficient for long lists as for short lists.
  1457.        (Alas, the Count slows things down).
  1458.        They split the list into two parts.
  1459.        One part remains as the original list, the other part
  1460.        is appended to the second list.  There are eight possible
  1461.        variations:
  1462.        Split the list {after/before} a given element
  1463.        keep the {head/tail} portion in the original list
  1464.        append the rest to the {head/tail} of the new list.
  1465.        Since After is strictly equivalent to Before Next
  1466.        we are not in serious need of the Before/After variants.
  1467.        That leaves only four.
  1468.        If you are processing a list left to right and dumping
  1469.        the bits that you have processed into another list as
  1470.        you go, the Tail/Tail variant gives the most natural result.
  1471.        If you are processing in reverse order, Head/Head is best.
  1472.        By using nil positions and empty lists judiciously either
  1473.        of the other two can be built up in two operations.
  1474.        The definition of nil (see Next/Prev etc) means that
  1475.        degenerate cases include
  1476.           "move all elements to new list"
  1477.           "Split a list into two lists"
  1478.           "Concatenate two lists"
  1479.           (and quite a few no-ops)
  1480.        !!WARNING!! The type checking won't buy you much if you get list
  1481.        positions muddled up - e.g. use a POSITION that's in a different
  1482.        list and see what a mess you get!
  1483.     *)
  1484.     (* Split self after position p in self
  1485.        Retain as self the tail portion of the original self
  1486.        Add the head portion to the tail end of *pList
  1487.        Return True if it all worked, FALSE if it didn't.
  1488.        e.g.
  1489.           foo->MoveToTail(foo->GetHeadPosition(), bar);
  1490.               moves one element from the head of foo to the tail of bar
  1491.           foo->MoveToTail(nil, bar);
  1492.               is a no-op, returns nil
  1493.           foo->MoveToTail(foo->GetTailPosition, bar);
  1494.               concatenates foo onto the end of bar and empties foo.
  1495.        A better, except excessively long name might be
  1496.            MoveElementsFromHeadThroughPositionToOtherTail
  1497.     *)
  1498.     function MoveToTail(pos: Position; List: TBCBaseList): boolean;
  1499.     (* Mirror image:
  1500.        Split self before position p in self.
  1501.        Retain in self the head portion of the original self
  1502.        Add the tail portion to the start (i.e. head) of *pList
  1503.        e.g.
  1504.           foo->MoveToHead(foo->GetTailPosition(), bar);
  1505.               moves one element from the tail of foo to the head of bar
  1506.           foo->MoveToHead(nil, bar);
  1507.               is a no-op, returns nil
  1508.           foo->MoveToHead(foo->GetHeadPosition, bar);
  1509.               concatenates foo onto the start of bar and empties foo.
  1510.     *)
  1511.     function MoveToHead(pos: Position; List: TBCBaseList): boolean;
  1512.     (* Reverse the order of the [pointers to] objects in self *)
  1513.     procedure Reverse;
  1514.   end;
  1515. // Desc: DirectShow base classes - defines classes to simplify creation of
  1516. //       ActiveX source filters that support continuous generation of data.
  1517. //       No support is provided for IMediaControl or IMediaPosition.
  1518. //
  1519. // Derive your source filter from CSource.
  1520. // During construction either:
  1521. //    Create some CSourceStream objects to manage your pins
  1522. //    Provide the user with a means of doing so eg, an IPersistFile interface.
  1523. //
  1524. // CSource provides:
  1525. //    IBaseFilter interface management
  1526. //    IMediaFilter interface management, via CBaseFilter
  1527. //    Pin counting for CBaseFilter
  1528. //
  1529. // Derive a class from CSourceStream to manage your output pin types
  1530. //  Implement GetMediaType/1 to return the type you support. If you support multiple
  1531. //   types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
  1532. //  Implement Fillbuffer() to put data into one buffer.
  1533. //
  1534. // CSourceStream provides:
  1535. //    IPin management via CBaseOutputPin
  1536. //    Worker thread management
  1537. // Override construction to provide a means of creating
  1538. // CSourceStream derived objects - ie a way of creating pins.
  1539.   TBCSourceStream = class;
  1540.   TStreamArray = array of TBCSourceStream;
  1541.   TBCSource = class(TBCBaseFilter)
  1542.   protected
  1543.     FPins: Integer;  // The number of pins on this filter. Updated by CSourceStream
  1544.     FStreams: Pointer; // the pins on this filter.
  1545.     FStateLock: TBCCritSec;
  1546.   public
  1547.     constructor Create(const Name: string; unk: IUnknown; const clsid: TGUID; out hr: HRESULT); overload;
  1548.     constructor Create(const Name: string; unk: IUnknown; const clsid: TGUID); overload;
  1549.     destructor Destroy; override;
  1550.     function GetPinCount: Integer; override;
  1551.     function GetPin(n: Integer): TBCBasePin; override;
  1552.     // -- Utilities --
  1553.     property StateLock: TBCCritSec read FStateLock; // provide our critical section
  1554.     function AddPin(Stream: TBCSourceStream): HRESULT;
  1555.     function RemovePin(Stream: TBCSourceStream): HRESULT;
  1556.     function FindPin(Id: PWideChar; out Pin: IPin): HRESULT; override;
  1557.     function FindPinNumber(Pin: IPin): Integer;
  1558.   end;
  1559. //
  1560. // CSourceStream
  1561. //
  1562. // Use this class to manage a stream of data that comes from a
  1563. // pin.
  1564. // Uses a worker thread to put data on the pin.
  1565.   TThreadCommand = (
  1566.     CMD_INIT,
  1567.     CMD_PAUSE,
  1568.     CMD_RUN,
  1569.     CMD_STOP,
  1570.     CMD_EXIT
  1571.   );
  1572.   TBCSourceStream = class(TBCBaseOutputPin)
  1573.   public
  1574.     constructor Create(const ObjectName: string; out hr: HRESULT;
  1575.       Filter: TBCSource; const Name: WideString);
  1576.     destructor Destroy; override;
  1577.   protected
  1578.     FThread: TBCAMThread;
  1579.     FFilter: TBCSource; // The parent of this stream
  1580.     // *
  1581.     // * Data Source
  1582.     // *
  1583.     // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
  1584.     // * called from within the ThreadProc. They are used in the creation of
  1585.     // * the media samples this pin will provide
  1586.     // *
  1587.     // Override this to provide the worker thread a means
  1588.     // of processing a buffer
  1589.     function FillBuffer(Samp: IMediaSample): HRESULT; virtual; abstract;
  1590.     // Called as the thread is created/destroyed - use to perform
  1591.     // jobs such as start/stop streaming mode
  1592.     // If OnThreadCreate returns an error the thread will exit.
  1593.     function OnThreadCreate: HRESULT; virtual;
  1594.     function OnThreadDestroy: HRESULT; virtual;
  1595.     function OnThreadStartPlay: HRESULT; virtual;
  1596.   public
  1597.     // *
  1598.     // * Worker Thread
  1599.     // *
  1600.     function Active: HRESULT; override;    // Starts up the worker thread
  1601.     function Inactive: HRESULT; override;  // Exits the worker thread.
  1602.     // thread commands
  1603.     function Init: HRESULT;
  1604.     function Exit_: HRESULT;
  1605.     function Run: HRESULT; reintroduce;
  1606.     function Pause: HRESULT;
  1607.     function Stop: HRESULT;
  1608.     // *
  1609.     // * AM_MEDIA_TYPE support
  1610.     // *
  1611.     // If you support more than one media type then override these 2 functions
  1612.     function CheckMediaType(MediaType: PAMMediaType): HRESULT; override;
  1613.     function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; overload; override; // List pos. 0-n
  1614.     // If you support only one type then override this fn.
  1615.     // This will only be called by the default implementations
  1616.     // of CheckMediaType and GetMediaType(int, CMediaType*)
  1617.     // You must override this fn. or the above 2!
  1618.     function GetMediaType(MediaType: PAMMediaType): HRESULT; reintroduce; overload; virtual;
  1619.     function QueryId(out id: PWideChar): HRESULT; override;
  1620.   protected
  1621.     function GetRequest: TThreadCommand;
  1622.     function CheckRequest(var com: TThreadCommand): boolean;
  1623.     // override these if you want to add thread commands
  1624.     function ThreadProc: DWORD; virtual; // the thread function
  1625.     function DoBufferProcessingLoop: HRESULT; virtual; // the loop executed whilst running
  1626.   end;
  1627.   TBCBaseRenderer = class;
  1628.   TBCRendererInputPin = class;
  1629.   // This is our input pin class that channels calls to the renderer
  1630.   TBCRendererInputPin = class(TBCBaseInputPin)
  1631.   protected
  1632.     FRenderer: TBCBaseRenderer;
  1633.   public
  1634.     constructor Create(Renderer: TBCBaseRenderer; out hr: HResult;
  1635.       Name: PWideChar);
  1636.     // Overriden from the base pin classes
  1637.     function BreakConnect: HResult; override;
  1638.     function CompleteConnect(ReceivePin: IPin): HResult; override;
  1639.     function SetMediaType(MediaType: PAMMediaType): HResult; override;
  1640.     function CheckMediaType(MediaType: PAMMediaType): HResult; override;
  1641.     function Active: HResult; override;
  1642.     function Inactive: HResult; override;
  1643.     // Add rendering behaviour to interface functions
  1644.     function QueryId(out Id: PWideChar): HResult; override; stdcall;
  1645.     function EndOfStream: HResult; override; stdcall;
  1646.     function BeginFlush: HResult; override; stdcall;
  1647.     function EndFlush: HResult; override; stdcall;
  1648.     function Receive(MediaSample: IMediaSample): HResult; override; stdcall;
  1649.     function InheritedReceive(MediaSample: IMediaSample): HResult;
  1650.       virtual; stdcall;
  1651.   end;
  1652.   // Main renderer class that handles synchronisation and state changes
  1653.   TBCBaseRenderer = class(TBCBaseFilter)
  1654.   protected
  1655.     // friend class CRendererInputPin;
  1656.     //FEndOfStreamTimerCB: TFNTimeCallBack;
  1657.     // Media seeking pass by object
  1658.     FPosition: TBCRendererPosPassThru;
  1659.     //FPosition: IUnknown;
  1660.     // Used to signal timer events
  1661.     FRenderEvent: TBCAMEvent;
  1662.     // Signalled to release worker thread
  1663.     FThreadSignal: TBCAMEvent;
  1664.     // Signalled when state complete
  1665.     FCompleteEvent: TBCAMEvent;
  1666.     // Stop us from rendering more data
  1667.     FAbort: Boolean;
  1668.     // Are we currently streaming
  1669.     FIsStreaming: Boolean;
  1670.     // Timer advise cookie
  1671.     FAdvisedCookie: DWord;
  1672.     // Current image media sample
  1673.     FMediaSample: IMediaSample;
  1674.     // Any more samples in the stream
  1675.     FIsEOS: Boolean;
  1676.     // Have we delivered an EC_COMPLETE
  1677.     FIsEOSDelivered: Boolean;
  1678.     // Our renderer input pin object
  1679.     FInputPin: TBCRendererInputPin;
  1680.     // Critical section for interfaces
  1681.     FInterfaceLock: TBCCritSec;
  1682.     // Controls access to internals
  1683.     FRendererLock: TBCCritSec;
  1684.     // QualityControl sink
  1685.     FQSink: IQualityControl;
  1686.     // Can we signal an EC_REPAINT
  1687.     FRepaintStatus: Boolean;
  1688.     //  Avoid some deadlocks by tracking filter during stop
  1689.     // Inside Receive between PrepareReceive and actually processing the sample
  1690.     FInReceive: Boolean;
  1691.     // Time when we signal EC_COMPLETE
  1692.     FSignalTime: TReferenceTime;
  1693.     // Used to signal end of stream
  1694.     FEndOfStreamTimer: DWord;
  1695.     // This lock protects the creation and of FPosition and FInputPin.
  1696.     // It ensures that two threads cannot create either object simultaneously.
  1697.     FObjectCreationLock: TBCCritSec;
  1698. // Milenko start (must be outside of the class and with stdcall; or it will crash)
  1699. //    procedure EndOfStreamTimer(
  1700. //      uID: UINT;      // Timer identifier
  1701. //      uMsg: UINT;     // Not currently used
  1702. //      dwUser: DWord;  // User information
  1703. //      dw1: DWord;     // Windows reserved
  1704. //      dw2: DWord      // Is also reserved
  1705. //    ); stdcall;
  1706. // Milenko end
  1707.   public
  1708. {$IFDEF PERF}
  1709.     // Just before we started drawing
  1710.     // Set in OnRenderStart, Used in OnRenderEnd
  1711.     FRenderStart: TReferenceTime;
  1712.     // MSR_id for frame time stamp
  1713.     FBaseStamp: Integer;
  1714.     // MSR_id for true wait time
  1715.     FBaseRenderTime: Integer;
  1716.     // MSR_id for time frame is late (int)
  1717.     FBaseAccuracy: Integer;
  1718. {$ENDIF}
  1719.     constructor Create(
  1720.       // CLSID for this renderer
  1721.       RendererClass: TGUID;
  1722.       // Debug ONLY description
  1723.       Name: PChar;
  1724.       // Aggregated owner object
  1725.       Unk: IUnknown;
  1726.       // General OLE return code
  1727.       hr: HResult);
  1728.     destructor Destroy; override;
  1729. // milenko start (added as a workaround for the TBCRendererPosPAssThru/FPosition and Renderer destructor)
  1730.     function JoinFilterGraph(pGraph: IFilterGraph; pName: PWideChar): HRESULT; override;
  1731. // milenko end
  1732.     // Overriden to say what interfaces we support and where
  1733.     function GetMediaPositionInterface(IID: TGUID; out Obj): HResult;
  1734.       virtual;
  1735.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult;
  1736.       override; stdcall;
  1737.     function SourceThreadCanWait(CanWait: Boolean): HResult; virtual;
  1738. {$IFDEF DEBUG}
  1739.     // Debug only dump of the renderer state
  1740.     procedure DisplayRendererState;
  1741. {$ENDIF}
  1742.     function WaitForRenderTime: HResult; virtual;
  1743.     function CompleteStateChange(OldState: TFilterState): HResult; virtual;
  1744.     // Return internal information about this filter
  1745.     property IsEndOfStream: Boolean read FIsEOS;
  1746.     property IsEndOfStreamDelivered: Boolean read FIsEOSDelivered;
  1747.     property IsStreaming: Boolean read FIsStreaming;
  1748.     procedure SetAbortSignal(Abort_: Boolean);
  1749.     procedure OnReceiveFirstSample(MediaSample: IMediaSample); virtual;
  1750.     property RenderEvent: TBCAMEvent read FRenderEvent;
  1751.     // Permit access to the transition state
  1752.     procedure Ready;
  1753.     procedure NotReady;
  1754.     function CheckReady: Boolean;
  1755.     function GetPinCount: Integer; override;
  1756.     function GetPin(n: integer): TBCBasePin; override;
  1757.     function GetRealState: TFilterState;
  1758.     procedure SendRepaint;
  1759.     procedure SendNotifyWindow(Pin: IPin; Handle: HWND);
  1760.     function OnDisplayChange: Boolean;
  1761.     procedure SetRepaintStatus(Repaint: Boolean);
  1762.     // Override the filter and pin interface functions
  1763.     function Stop: HResult; override; stdcall;
  1764.     function Pause: HResult; override; stdcall;
  1765.     function Run(StartTime: TReferenceTime): HResult; override; stdcall;
  1766.     function GetState(MSecs: DWord; out State: TFilterState): HResult;
  1767.       override; stdcall;
  1768.     function FindPin(id: PWideChar; out Pin: IPin): HResult;
  1769.       override; stdcall;
  1770.     // These are available for a quality management implementation
  1771.     procedure OnRenderStart(MediaSample: IMediaSample); virtual;
  1772.     procedure OnRenderEnd(MediaSample: IMediaSample); virtual;
  1773.     function OnStartStreaming: HResult; virtual;
  1774.     function OnStopStreaming: HResult; virtual;
  1775.     procedure OnWaitStart; virtual;
  1776.     procedure OnWaitEnd; virtual;
  1777.     procedure PrepareRender; virtual;
  1778.     // Quality management implementation for scheduling rendering
  1779.     function ScheduleSample(MediaSample: IMediaSample): Boolean; virtual;
  1780.     function GetSampleTimes(MediaSample: IMediaSample;
  1781.       out StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  1782.       virtual;
  1783.     function ShouldDrawSampleNow(MediaSample: IMediaSample;
  1784.       StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult; virtual;
  1785.     // Lots of end of stream complexities
  1786.     procedure TimerCallback;
  1787.     procedure ResetEndOfStreamTimer;
  1788.     function NotifyEndOfStream: HResult;
  1789.     function SendEndOfStream: HResult; virtual;
  1790.     function ResetEndOfStream: HResult; virtual;
  1791.     function EndOfStream: HResult; virtual;
  1792.     // Rendering is based around the clock
  1793.     procedure SignalTimerFired;
  1794.     function CancelNotification: HResult; virtual;
  1795.     function ClearPendingSample: HResult; virtual;
  1796.     // Called when the filter changes state
  1797.     function Active: HResult; virtual;
  1798.     function Inactive: HResult; virtual;
  1799.     function StartStreaming: HResult; virtual;
  1800.     function StopStreaming: HResult; virtual;
  1801.     function BeginFlush: HResult; virtual;
  1802.     function EndFlush: HResult; virtual;
  1803.     // Deal with connections and type changes
  1804.     function BreakConnect: HResult; virtual;
  1805.     function SetMediaType(MediaType: PAMMediaType): HResult; virtual; 
  1806.     function CompleteConnect(ReceivePin: IPin): HResult; virtual;
  1807.     // These look after the handling of data samples
  1808.     function PrepareReceive(MediaSample: IMediaSample): HResult; virtual;
  1809.     function Receive(MediaSample: IMediaSample): HResult; virtual;
  1810.     function HaveCurrentSample: Boolean; virtual;
  1811.     function GetCurrentSample: IMediaSample; virtual;
  1812.     function Render(MediaSample: IMediaSample): HResult; virtual;
  1813.     // Derived classes MUST override these
  1814.     function DoRenderSample(MediaSample: IMediaSample): HResult;
  1815.       virtual; abstract;
  1816.     function CheckMediaType(MediaType: PAMMediaType): HResult;
  1817.       virtual; abstract;
  1818.     // Helper
  1819.     procedure WaitForReceiveToComplete;
  1820. (*
  1821.     // callback
  1822.     property EndOfStreamTimerCB: TFNTimeCallBack read FEndOfStreamTimerCB
  1823.       write FEndOfStreamTimerCB;
  1824. *)
  1825.   end;
  1826. const
  1827.   AVGPERIOD = 4;
  1828. type
  1829.   // CBaseVideoRenderer is a renderer class (see its ancestor class) and
  1830.   // it handles scheduling of media samples so that they are drawn at the
  1831.   // correct time by the reference clock.  It implements a degradation
  1832.   // strategy.  Possible degradation modes are:
  1833.   //    Drop frames here (only useful if the drawing takes significant time)
  1834.   //    Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
  1835.   //    Signal supplier to change the frame rate - i.e. ongoing skipping.
  1836.   //    Or any combination of the above.
  1837.   // In order to determine what's useful to try we need to know what's going
  1838.   // on.  This is done by timing various operations (including the supplier).
  1839.   // This timing is done by using timeGetTime as it is accurate enough and
  1840.   // usually cheaper than calling the reference clock.  It also tells the
  1841.   // truth if there is an audio break and the reference clock stops.
  1842.   // We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
  1843.   // which the rest of the renderer calls at significant moments.  These do
  1844.   // the timing.
  1845.   // the number of frames that the sliding averages are averaged over.
  1846.   // the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
  1847.   // #define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
  1848.   // Spot the bug in this macro - I can't. but it doesn't work!
  1849.   TBCBaseVideoRenderer = class(
  1850.       // Base renderer class
  1851.       TBCBaseRenderer,
  1852.       // Property page guff
  1853.       IQualProp,
  1854.       // Allow throttling
  1855.       IQualityControl)
  1856.   protected
  1857.     //******************************************************************
  1858.     // State variables to control synchronisation
  1859.     //******************************************************************
  1860.     // Control of sending Quality messages.  We need to know whether
  1861.     // we are in trouble (e.g. frames being dropped) and where the time
  1862.     // is being spent.
  1863.     // When we drop a frame we play the next one early.
  1864.     // The frame after that is likely to wait before drawing and counting this
  1865.     // wait as spare time is unfair, so we count it as a zero wait.
  1866.     // We therefore need to know whether we are playing frames early or not.
  1867.     // The number of consecutive frames drawn at their normal time (not early)
  1868.     // -1 means we just dropped a frame.
  1869.     FNormal: Integer;
  1870. {$IFDEF PERF}
  1871.     // Don't drop any frames (debug and I'm not keen on people using it!)
  1872.     FDrawLateFrames: Bool;
  1873. {$ENDIF}
  1874.     // The response to Quality messages says our supplier is handling things.
  1875.     // We will allow things to go extra late before dropping frames.
  1876.     // We will play very early after he has dropped one.
  1877.     FSupplierHandlingQuality: Boolean;
  1878.     // Control of scheduling, frame dropping etc.
  1879.     // We need to know where the time is being spent so as to tell whether
  1880.     // we should be taking action here, signalling supplier or what.
  1881.     // The variables are initialised to a mode of NOT dropping frames.
  1882.     // They will tell the truth after a few frames.
  1883.     // We typically record a start time for an event, later we get the time
  1884.     // again and subtract to get the elapsed time, and we average this over
  1885.     // a few frames.  The average is used to tell what mode we are in.
  1886.     // Although these are reference times (64 bit) they are all DIFFERENCES
  1887.     // between times which are small.  An int will go up to 214 secs before
  1888.     // overflow.  Avoiding 64 bit multiplications and divisions seems
  1889.     // worth while.
  1890.     // Audio-video throttling.  If the user has turned up audio quality
  1891.     // very high (in principle it could be any other stream, not just audio)
  1892.     // then we can receive cries for help via the graph manager.  In this case
  1893.     // we put in a wait for some time after rendering each frame.
  1894.     FThrottle: Integer;
  1895.     // The time taken to render (i.e. BitBlt) frames controls which component
  1896.     // needs to degrade.  If the blt is expensive, the renderer degrades.
  1897.     // If the blt is cheap it's done anyway and the supplier degrades.
  1898.     // Time frames are taking to blt
  1899.     FRenderAvg: Integer;
  1900.     // Time for last frame blt
  1901.     FRenderLast: Integer;
  1902.     // Just before we started drawing (mSec) derived from timeGetTime.
  1903.     FRenderStart: Integer;
  1904.     // When frames are dropped we will play the next frame as early as we can.
  1905.     // If it was a false alarm and the machine is fast we slide gently back to
  1906.     // normal timing.  To do this, we record the offset showing just how early
  1907.     // we really are.  This will normally be negative meaning early or zero.
  1908.     FEarliness: Integer;
  1909.     // Target provides slow long-term feedback to try to reduce the
  1910.     // average sync offset to zero.  Whenever a frame is actually rendered
  1911.     // early we add a msec or two, whenever late we take off a few.
  1912.     // We add or take off 1/32 of the error time.
  1913.     // Eventually we should be hovering around zero.  For a really bad case
  1914.     // where we were (say) 300mSec off, it might take 100 odd frames to
  1915.     // settle down.  The rate of change of this is intended to be slower
  1916.     // than any other mechanism in Quartz, thereby avoiding hunting.
  1917.     FTarget: Integer;
  1918.     // The proportion of time spent waiting for the right moment to blt
  1919.     // controls whether we bother to drop a frame or whether we reckon that
  1920.     // we're doing well enough that we can stand a one-frame glitch.
  1921.     // Average of last few wait times (actually we just average how early we were).
  1922.     // Negative here means LATE.
  1923.     FWaitAvg: Integer;
  1924.     // The average inter-frame time.
  1925.     // This is used to calculate the proportion of the time used by the
  1926.     // three operations (supplying us, waiting, rendering)
  1927.     // Average inter-frame time
  1928.     FFrameAvg: Integer;
  1929.     // duration of last frame.
  1930.     FDuration: Integer;
  1931. {$IFDEF PERF}
  1932.     // Performance logging identifiers
  1933.     // MSR_id for frame time stamp
  1934.     FTimeStamp: Integer;
  1935.     // MSR_id for true wait time
  1936.     FWaitReal: Integer;
  1937.     // MSR_id for wait time recorded
  1938.     FWait: Integer;
  1939.     // MSR_id for time frame is late (int)
  1940.     FFrameAccuracy: Integer;
  1941.     // MSR_id for lateness at scheduler
  1942.     FSchLateTime: Integer;
  1943.     // MSR_id for Quality rate requested
  1944.     FQualityRate: Integer;
  1945.     // MSR_id for Quality time requested
  1946.     FQualityTime: Integer;
  1947.     // MSR_id for decision code
  1948.     FDecision: Integer;
  1949.     // MSR_id for trace style debugging
  1950.     FDebug: Integer;
  1951.     // MSR_id for timing the notifications per se
  1952.     FSendQuality: Integer;
  1953. {$ENDIF}
  1954.     // original time stamp of frame with no earliness fudges etc.
  1955.     FRememberStampforPerf: TReferenceTime;
  1956. {$IFDEF PERF}
  1957.     // time when previous frame rendered
  1958.     FRememberFrameForPerf: TReferenceTime;
  1959. {$ENDIF}
  1960.     // PROPERTY PAGE
  1961.     // This has edit fields that show the user what's happening
  1962.     // These member variables hold these counts.
  1963.     // cumulative frames dropped IN THE RENDERER
  1964.     FFramesDropped: Integer;
  1965.     // Frames since streaming started seen BY THE RENDERER
  1966.     // (some may be dropped upstream)
  1967.     FFramesDrawn: Integer;
  1968.     // Next two support average sync offset and standard deviation of sync offset.
  1969.     // Sum of accuracies in mSec
  1970.     FTotAcc: Int64;
  1971.     // Sum of squares of (accuracies in mSec)
  1972.     FSumSqAcc: Int64;
  1973.     // Next two allow jitter calculation.  Jitter is std deviation of frame time.
  1974.     // Time of prev frame (for inter-frame times)
  1975.     FLastDraw: TReferenceTime;
  1976.     // Sum of squares of (inter-frame time in mSec)
  1977.     FSumSqFrameTime: Int64;
  1978.     // Sum of inter-frame times in mSec
  1979.     FSumFrameTime: Int64;
  1980.     // To get performance statistics on frame rate, jitter etc, we need
  1981.     // to record the lateness and inter-frame time.  What we actually need are the
  1982.     // data above (sum, sum of squares and number of entries for each) but the data
  1983.     // is generated just ahead of time and only later do we discover whether the
  1984.     // frame was actually drawn or not.  So we have to hang on to the data
  1985.     // hold onto frame lateness
  1986.     FLate: Integer;
  1987.     // hold onto inter-frame time
  1988.     FFrame: Integer;
  1989.     // if streaming then time streaming started
  1990.     // else time of last streaming session
  1991.     // used for property page statistics
  1992.     FStreamingStart: Integer;
  1993. {$IFDEF PERF}
  1994.     // timeGetTime*10000+m_llTimeOffset==ref time
  1995.     FTimeOffset: Int64;
  1996. {$ENDIF}
  1997.   public
  1998.     constructor Create(
  1999.       // CLSID for this renderer
  2000.       RenderClass: TGUID;
  2001.       // Debug ONLY description
  2002.       Name: PChar;
  2003.       // Aggregated owner object
  2004.       Unk: IUnknown;
  2005.       // General OLE return code
  2006.       hr: HResult);
  2007.     destructor Destroy; override;
  2008.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult;
  2009.       override; stdcall;
  2010.     // IQualityControl methods - Notify allows audio-video throttling
  2011.     function SetSink(QualityControl: IQualityControl): HResult; stdcall;
  2012.     function Notify(Filter: IBaseFilter; q: TQuality): HResult; stdcall;
  2013.     // These provide a full video quality management implementation
  2014.     procedure OnRenderStart(MediaSample: IMediaSample); override;
  2015.     procedure OnRenderEnd(MediaSample: IMediaSample); override;
  2016.     procedure OnWaitStart; reintroduce;
  2017.     procedure OnWaitEnd; reintroduce;
  2018.     function OnStartStreaming: HResult; reintroduce;
  2019.     function OnStopStreaming: HResult; reintroduce;
  2020.     procedure ThrottleWait;
  2021.     // Handle the statistics gathering for our quality management
  2022.     procedure PreparePerformanceData(Late, Frame: Integer);
  2023.     procedure RecordFrameLateness(Late, Frame: Integer); virtual;
  2024.     procedure OnDirectRender(MediaSample: IMediaSample); virtual;
  2025.     function ResetStreamingTimes: HResult; virtual;
  2026.     function ScheduleSample(MediaSample: IMediaSample): Boolean; override;
  2027.     function ShouldDrawSampleNow(MediaSample: IMediaSample;
  2028.       StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  2029.       override;
  2030.     function SendQuality(Late, RealStream: TReferenceTime): HResult; virtual;
  2031. // milenko start (TBCBaseFilter made virtual, so just add override here)
  2032.     function JoinFilterGraph(Graph: IFilterGraph; Name: PWideChar): HResult; override;
  2033. // milenko end
  2034.     //
  2035.     //  Do estimates for standard deviations for per-frame
  2036.     //  statistics
  2037.     //
  2038.     //  *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
  2039.     //                            (m_cFramesDrawn - 2)
  2040.     //  or 0 if m_cFramesDrawn <= 3
  2041.     //
  2042.     function GetStdDev(Samples: Integer; out Res: Integer;
  2043.       SumSq, Tot: Int64): HResult;
  2044.     // IQualProp property page support
  2045.     // ??? out <- var   function get_FramesDroppedInRenderer(out pcFrames : Integer) : HResult; stdcall;
  2046.     function get_FramesDroppedInRenderer(var FramesDropped: Integer): HResult;
  2047.       stdcall;
  2048.     function get_FramesDrawn(out FramesDrawn: Integer): HResult; stdcall;
  2049.     function get_AvgFrameRate(out AvgFrameRate: Integer): HResult; stdcall;
  2050.     function get_Jitter(out Jitter: Integer): HResult; stdcall;
  2051.     function get_AvgSyncOffset(out Avg: Integer): HResult; stdcall;
  2052.     function get_DevSyncOffset(out Dev: Integer): HResult; stdcall;
  2053.   end;
  2054. // milenko start (added TBCPullPin)
  2055. //
  2056. // CPullPin
  2057. //
  2058. // object supporting pulling data from an IAsyncReader interface.
  2059. // Given a start/stop position, calls a pure Receive method with each
  2060. // IMediaSample received.
  2061. //
  2062. // This is essentially for use in a MemInputPin when it finds itself
  2063. // connected to an IAsyncReader pin instead of a pushing pin.
  2064. //
  2065.   TThreadMsg = (
  2066.     TM_Pause,       // stop pulling and wait for next message
  2067.     TM_Start,       // start pulling
  2068.     TM_Exit         // stop and exit
  2069.   );
  2070.   TBCPullPin = class(TBCAMThread)
  2071.   private
  2072.     FReader: IAsyncReader;
  2073.     FStart: TReferenceTime;
  2074.     FStop: TReferenceTime;
  2075.     FDuration: TReferenceTime;
  2076.     FSync: Boolean;
  2077.     FState: TThreadMsg;
  2078.     // running pull method (check m_bSync)
  2079.     procedure Process;
  2080.     // clean up any cancelled i/o after a flush
  2081.     procedure CleanupCancelled;
  2082.     // suspend thread from pulling, eg during seek
  2083.     function PauseThread: HRESULT;
  2084.     // start thread pulling - create thread if necy
  2085.     function StartThread: HRESULT;
  2086.     // stop and close thread
  2087.     function StopThread: HRESULT;
  2088.     // called from ProcessAsync to queue and collect requests
  2089.     function QueueSample(var tCurrent: TReferenceTime; tAlignStop: TReferenceTime; bDiscontinuity: Boolean): HRESULT;
  2090.     function CollectAndDeliver(tStart,tStop: TReferenceTime): HRESULT;
  2091.     function DeliverSample(pSample: IMediaSample; tStart,tStop: TReferenceTime): HRESULT;
  2092.   protected
  2093.     FAlloc: IMemAllocator;
  2094.     // override pure thread proc from CAMThread
  2095.     function ThreadProc: DWord; override;
  2096.   public
  2097.     constructor Create;
  2098.     destructor Destroy; override;
  2099.     // returns S_OK if successfully connected to an IAsyncReader interface
  2100.     // from this object
  2101.     // Optional allocator should be proposed as a preferred allocator if
  2102.     // necessary
  2103.     // bSync is TRUE if we are to use sync reads instead of the
  2104.     // async methods.
  2105.     function Connect(pUnk: IUnknown; pAlloc: IMemAllocator; bSync: Boolean): HRESULT;
  2106.     // disconnect any connection made in Connect
  2107.     function Disconnect: HRESULT;
  2108.     // agree an allocator using RequestAllocator - optional
  2109.     // props param specifies your requirements (non-zero fields).
  2110.     // returns an error code if fail to match requirements.
  2111.     // optional IMemAllocator interface is offered as a preferred allocator
  2112.     // but no error occurs if it can't be met.
  2113.     function DecideAllocator(pAlloc: IMemAllocator; pProps: PAllocatorProperties): HRESULT;
  2114.     // set start and stop position. if active, will start immediately at
  2115.     // the new position. Default is 0 to duration
  2116.     function Seek(tStart, tStop: TReferenceTime): HRESULT;
  2117.     // return the total duration
  2118.     function Duration(out ptDuration: TReferenceTime): HRESULT;
  2119.     // start pulling data
  2120.     function Active: HRESULT;
  2121.     // stop pulling data
  2122.     function Inactive: HRESULT;
  2123.     // helper functions
  2124.     function AlignDown(ll: Int64; lAlign: LongInt): Int64;
  2125.     function AlignUp(ll: Int64; lAlign: LongInt): Int64;
  2126.     // GetReader returns the (addrefed) IAsyncReader interface
  2127.     // for SyncRead etc
  2128.     function GetReader: IAsyncReader;
  2129.     // -- pure --
  2130.     // override this to handle data arrival
  2131.     // return value other than S_OK will stop data
  2132.     function Receive(Sample: IMediaSample): HRESULT; virtual; abstract;
  2133.     // override this to handle end-of-stream
  2134.     function EndOfStream: HRESULT; virtual; abstract;
  2135.     // called on runtime errors that will have caused pulling
  2136.     // to stop
  2137.     // these errors are all returned from the upstream filter, who
  2138.     // will have already reported any errors to the filtergraph.
  2139.     procedure OnError(hr: HRESULT); virtual; abstract;
  2140.     // flush this pin and all downstream
  2141.     function BeginFlush: HRESULT; virtual; abstract;
  2142.     function EndFlush: HRESULT; virtual; abstract;
  2143.   end;
  2144. // milenko end
  2145. // milenko start (needed to access functions outside. usefull for Filter Development)
  2146. function CreateMemoryAllocator(out Allocator: IMemAllocator): HRESULT;
  2147. function AMGetWideString(Source: WideString; out Dest: PWideChar): HRESULT;
  2148. function CreatePosPassThru(Agg: IUnknown; Renderer: boolean; Pin: IPin; out PassThru: IUnknown): HRESULT; stdcall;
  2149. // milenko end
  2150. // milenko start reftime implementation
  2151. //------------------------------------------------------------------------------
  2152. // File: RefTime.h
  2153. //
  2154. // Desc: DirectShow base classes - defines CRefTime, a class that manages
  2155. //       reference times.
  2156. //
  2157. // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
  2158. //------------------------------------------------------------------------------
  2159. //
  2160. // CRefTime
  2161. //
  2162. // Manage reference times.
  2163. // Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
  2164. // functions providing simple comparison, conversion and arithmetic.
  2165. //
  2166. // A reference time (at the moment) is a unit of seconds represented in
  2167. // 100ns units as is used in the Win32 FILETIME structure. BUT the time
  2168. // a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
  2169. // will either be stream time or reference time depending upon context
  2170. //
  2171. // This class provides simple arithmetic operations on reference times
  2172. //
  2173. // keep non-virtual otherwise the data layout will not be the same as
  2174. // REFERENCE_TIME
  2175. // -----
  2176. // note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
  2177. // you will need to do so explicitly
  2178. // -----
  2179. type
  2180.   TBCRefTime = object
  2181.   public
  2182.     // *MUST* be the only data member so that this class is exactly
  2183.     // equivalent to a REFERENCE_TIME.
  2184.     // Also, must be *no virtual functions*
  2185.     FTime: TReferenceTime;
  2186.     // DCODER: using Create_ as contructor replacement ...
  2187.     procedure Create_; overload;
  2188.     procedure Create_(msecs: Longint); overload;
  2189.     // delphi 5 doesn't like "const rt: TBCRefTime" ???
  2190.     function SetTime(var rt: TBCRefTime): TBCRefTime; overload;
  2191.     function SetTime(var ll: LONGLONG): TBCRefTime; overload;
  2192.     function AddTime(var rt: TBCRefTime): TBCRefTime; overload;
  2193.     function SubstractTime(var rt: TBCRefTime): TBCRefTime; overload;
  2194.     function Millisecs: Longint;
  2195.     function GetUnits: LONGLONG;
  2196.   end;
  2197. // milenko end;
  2198. // milenko start schedule implementation
  2199. //------------------------------------------------------------------------------
  2200. // File: Schedule.cpp
  2201. //
  2202. // Desc: DirectShow base classes.
  2203. //
  2204. // Copyright (c) 1996-2002 Microsoft Corporation.  All rights reserved.
  2205. //------------------------------------------------------------------------------
  2206. type
  2207.   TBCAdvisePacket = class
  2208.   public
  2209.     FNext        : TBCAdvisePacket;
  2210.     FAdviseCookie: DWORD;
  2211.     FEventTime   : TReferenceTime; // Time at which event should be set
  2212.     FPeriod      : TReferenceTime; // Periodic time
  2213.     FNotify      : THandle;        // Handle to event or semephore
  2214.     FPeriodic    : Boolean;        // TRUE => Periodic event
  2215.     constructor Create; overload;
  2216.     constructor Create(Next: TBCAdvisePacket; Time: LONGLONG); overload;
  2217.     procedure InsertAfter(Packet: TBCAdvisePacket);
  2218.     // That is, is it the node that represents the end of the list
  2219.     function IsZ: Boolean;
  2220.     function RemoveNext: TBCAdvisePacket;
  2221.     procedure DeleteNext;
  2222.     function Next: TBCAdvisePacket;
  2223.     function Cookie: DWORD;
  2224.   end;
  2225.   TBCAMSchedule = class(TBCBaseObject)
  2226.   private
  2227.     // Structure is:
  2228.     // head -> elmt1 -> elmt2 -> z -> null
  2229.     // So an empty list is:       head -> z -> null
  2230.     // Having head & z as links makes insertaion,
  2231.     // deletion and shunting much easier.
  2232.     FHead,
  2233.     FZ          : TBCAdvisePacket; // z is both a tail and a sentry
  2234.     FNextCookie : DWORD;     // Strictly increasing
  2235.     FAdviseCount: DWORD;    // Number of elements on list
  2236.     FSerialize  : TBCCritSec;
  2237.     // Event that we should set if the packed added above will be the next to fire.
  2238.     FEvent      : THandle;
  2239.     // Rather than delete advise packets, we cache them for future use
  2240.     FAdviseCache: TBCAdvisePacket;
  2241.     FCacheCount : DWORD;
  2242.     // AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
  2243.     function AddAdvisePacket(Packet: TBCAdvisePacket): DWORD; overload;
  2244.     // A Shunt is where we have changed the first element in the
  2245.     // list and want it re-evaluating (i.e. repositioned) in
  2246.     // the list.
  2247.     procedure ShuntHead;
  2248.     procedure Delete(Packet: TBCAdvisePacket);// This "Delete" will cache the Link
  2249.   public
  2250.     // ev is the event we should fire if the advise time needs re-evaluating
  2251.     constructor Create(Event: THandle);
  2252.     destructor Destroy; override;
  2253.     function GetAdviseCount: DWORD;
  2254.     function GetNextAdviseTime: TReferenceTime;
  2255.     // We need a method for derived classes to add advise packets, we return the cookie
  2256.     function AddAdvisePacket(const Time1, Time2: TReferenceTime; h: THandle;
  2257.       Periodic: Boolean): DWORD; overload;
  2258.     // And a way to cancel
  2259.     function Unadvise(AdviseCookie: DWORD): HRESULT;
  2260.     // Tell us the time please, and we'll dispatch the expired events.
  2261.     // We return the time of the next event.
  2262.     // NB: The time returned will be "useless" if you start adding extra Advises.
  2263.     // But that's the problem of
  2264.     // whoever is using this helper class (typically a clock).
  2265.     function Advise(const Time_: TReferenceTime): TReferenceTime;
  2266.     // Get the event handle which will be set if advise time requires re-evaluation.
  2267.     function GetEvent: THandle;
  2268.     procedure DumpLinkedList;
  2269.   end;
  2270. // milenko end
  2271. // milenko start refclock implementation
  2272. //------------------------------------------------------------------------------
  2273. // File: RefClock.h
  2274. //
  2275. // Desc: DirectShow base classes - defines the IReferenceClock interface.
  2276. //
  2277. // Copyright (c) 1992-2002 Microsoft Corporation.  All rights reserved.
  2278. //------------------------------------------------------------------------------
  2279. (* This class hierarchy will support an IReferenceClock interface so
  2280.    that an audio card (or other externally driven clock) can update the
  2281.    system wide clock that everyone uses.
  2282.    The interface will be pretty thin with probably just one update method
  2283.    This interface has not yet been defined.
  2284.  *)
  2285. (* This abstract base class implements the IReferenceClock
  2286.  * interface.  Classes that actually provide clock signals (from
  2287.  * whatever source) have to be derived from this class.
  2288.  *
  2289.  * The abstract class provides implementations for:
  2290.  *  CUnknown support
  2291.  *      locking support (CCritSec)
  2292.  * client advise code (creates a thread)
  2293.  *
  2294.  * Question: what can we do about quality?  Change the timer
  2295.  * resolution to lower the system load?  Up the priority of the
  2296.  * timer thread to force more responsive signals?
  2297.  *
  2298.  * During class construction we create a worker thread that is destroyed during
  2299.  * destuction.  This thread executes a series of WaitForSingleObject calls,
  2300.  * waking up when a command is given to the thread or the next wake up point
  2301.  * is reached.  The wakeup points are determined by clients making Advise
  2302.  * calls.
  2303.  *
  2304.  * Each advise call defines a point in time when they wish to be notified.  A
  2305.  * periodic advise is a series of these such events.  We maintain a list of
  2306.  * advise links and calculate when the nearest event notification is due for.
  2307.  * We then call WaitForSingleObject with a timeout equal to this time.  The
  2308.  * handle we wait on is used by the class to signal that something has changed
  2309.  * and that we must reschedule the next event.  This typically happens when
  2310.  * someone comes in and asks for an advise link while we are waiting for an
  2311.  * event to timeout.
  2312.  *
  2313.  * While we are modifying the list of advise requests we
  2314.  * are protected from interference through a critical section.  Clients are NOT
  2315.  * advised through callbacks.  One shot clients have an event set, while
  2316.  * periodic clients have a semaphore released for each event notification.  A
  2317.  * semaphore allows a client to be kept up to date with the number of events
  2318.  * actually triggered and be assured that they can't miss multiple events being
  2319.  * set.
  2320.  *
  2321.  * Keeping track of advises is taken care of by the CAMSchedule class.
  2322.  *)
  2323. type
  2324.   TBCBaseReferenceClock = class(TBCUnknown, IReferenceClock)
  2325.   private
  2326.     FLock           : TBCCritSec;
  2327.     FAbort          : Boolean;        // Flag used for thread shutdown
  2328.     FThread         : THandle;        // Thread handle
  2329.     FPrivateTime    : TReferenceTime; // Current best estimate of time
  2330.     FPrevSystemTime : DWORD;          // Last vaule we got from timeGetTime
  2331.     FLastGotTime    : TReferenceTime; // Last time returned by GetTime
  2332.     FNextAdvise     : TReferenceTime; // Time of next advise
  2333.     FTimerResolution: DWORD;
  2334.   {$IFDEF PERF}
  2335.     FGetSystemTime  : integer;
  2336.   {$ENDIF}
  2337.     function AdviseThread: HRESULT;  // Method in which the advise thread runs
  2338.   protected
  2339.     FSchedule       : TBCAMSchedule;
  2340.   public
  2341.     constructor Create(Name: String; Unk: IUnknown; out hr: HRESULT; Sched:
  2342.        TBCAMSchedule = nil);
  2343.     destructor Destroy; override; // Don't let me be created on the stack!
  2344.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override; stdcall;
  2345.     // IReferenceClock methods
  2346.     // Derived classes must implement GetPrivateTime().  All our GetTime
  2347.     // does is call GetPrivateTime and then check so that time does not
  2348.     // go backwards.  A return code of S_FALSE implies that the internal
  2349.     // clock has gone backwards and GetTime time has halted until internal
  2350.     // time has caught up. (Don't know if this will be much use to folk,
  2351.     // but it seems odd not to use the return code for something useful.)
  2352.     function GetTime(out Time: int64): HResult; stdcall;
  2353.     // When this is called, it sets m_rtLastGotTime to the time it returns.
  2354.     // Provide standard mechanisms for scheduling events
  2355.     // Ask for an async notification that a time has elapsed */
  2356.     function AdviseTime(
  2357.         BaseTime,                       // base reference time
  2358.         StreamTime: int64;    // stream offset time
  2359.         Event: THandle;                  // advise via this event
  2360.         out AdviseCookie: DWORD        // where your cookie goes
  2361.     ): HResult; stdcall;
  2362.     // Ask for an asynchronous periodic notification that a time has elapsed
  2363.     function AdvisePeriodic(
  2364.         const StartTime,                // starting at this time
  2365.         PeriodTime: int64;    // time between notifications
  2366.         Semaphore: THandle;              // advise via a semaphore
  2367.          out AdviseCookie: DWORD       // where your cookie goes
  2368.     ): HResult; stdcall;
  2369.     (* Cancel a request for notification(s) - if the notification was
  2370.      * a one shot timer then this function doesn't need to be called
  2371.      * as the advise is automatically cancelled, however it does no
  2372.      * harm to explicitly cancel a one-shot advise.  It is REQUIRED that
  2373.      * clients call Unadvise to clear a Periodic advise setting.
  2374.      *)
  2375.     function Unadvise(AdviseCookie: DWORD): HResult; stdcall;
  2376.     // Methods for the benefit of derived classes or outer objects
  2377.     // GetPrivateTime() is the REAL clock.  GetTime is just a cover for
  2378.     // it.  Derived classes will probably override this method but not
  2379.     // GetTime() itself.
  2380.     // The important point about GetPrivateTime() is it's allowed to go
  2381.     // backwards.  Our GetTime() will keep returning the LastGotTime
  2382.     // until GetPrivateTime() catches up.
  2383.     function GetPrivateTime: TReferenceTime; virtual;
  2384.     // Provide a method for correcting drift
  2385.     function SetTimeDelta(const TimeDelta: TReferenceTime): HRESULT; stdcall;
  2386.     function GetSchedule: TBCAMSchedule;
  2387.     // Thread stuff
  2388.     // Wakes thread up.  Need to do this if time to next advise needs reevaluating.
  2389.     procedure TriggerThread;
  2390.   end;
  2391. // milenko end
  2392. // milenko start sysclock implementation
  2393. //------------------------------------------------------------------------------
  2394. // File: SysClock.h
  2395. //
  2396. // Desc: DirectShow base classes - defines a system clock implementation of
  2397. //       IReferenceClock.
  2398. //
  2399. // Copyright (c) 1992-2002 Microsoft Corporation.  All rights reserved.
  2400. //------------------------------------------------------------------------------
  2401. const
  2402.   IID_IPersist : TGUID = '{0000010C-0000-0000-C000-000000000046}';
  2403. type
  2404.   TBCSystemClock = class(TBCBaseReferenceClock, IAMClockAdjust, IPersist)
  2405.   public
  2406.     constructor Create(Name: WideString; Unk : IUnknown; out hr : HRESULT);
  2407.     function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override; stdcall;
  2408.     // Yield up our class id so that we can be persisted
  2409.     // Implement required Ipersist method
  2410.     function GetClassID(out classID: TCLSID): HResult; stdcall;
  2411.     //  IAMClockAdjust methods
  2412.     function SetClockDelta(rtDelta: TReferenceTime): HResult; stdcall;
  2413.   end;
  2414. {$IFDEF DEBUG}
  2415.   procedure DbgLog(obj: TBCBaseObJect; const msg: string); overload;
  2416.   procedure DbgLog(const msg: string); overload;
  2417.   procedure DbgAssert(const Message, Filename: string; LineNumber: Integer;
  2418.     ErrorAddr: Pointer);
  2419. {$ENDIF}
  2420.   function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;
  2421.   function DllCanUnloadNow: HResult; stdcall;
  2422.   function DllRegisterServer: HResult; stdcall;
  2423.   function DllUnregisterServer: HResult; stdcall;
  2424. (* milenko start (needed for TBCBaseReferenceClock and TBCVideoTransformFilter ) *)
  2425. {$IFDEF PERF}
  2426.   procedure MSR_START(Id_: Integer);
  2427.   procedure MSR_STOP(Id_: Integer);
  2428.   procedure MSR_INTEGER(Id_, i: Integer);
  2429.   function MSR_REGISTER(s: String): Integer;
  2430. {$ENDIF}
  2431. (* milenko end *)
  2432. implementation
  2433. var
  2434.   ObjectCount  : Integer;
  2435.   FactoryCount : Integer;
  2436.   TemplatesVar : TBCFilterTemplate;
  2437. // milenko start (added global variables instead of local constants)
  2438.   IsCheckedVersion: Bool = False;
  2439.   IsTimeKillSynchronousFlagAvailable: Bool = False;
  2440.   MsgId: Cardinal = 0;
  2441. // milenko end
  2442. {$IFDEF DEBUG}
  2443.  {$IFNDEF MESSAGE}
  2444.   DebugFile : TextFile;
  2445.  {$ENDIF}
  2446.   procedure DbgLog(obj: TBCBaseObJect; const msg: string);
  2447.   begin
  2448.   {$IFNDEF MESSAGE}
  2449.     if (obj = nil) then
  2450.       Writeln(DebugFile, TimeToStr(time) +' > '+ msg) else
  2451.       Writeln(DebugFile, TimeToStr(time) +' > '+ format('Object: %s, msg: %s.',[obj.FName, msg]));
  2452.     Flush(DebugFile);
  2453.   {$ELSE}
  2454.     if (obj = nil) then OutputDebugString(PChar(TimeToStr(time) +' > '+ msg)) else
  2455.       OutputDebugString(PChar(TimeToStr(time) +' > '+ format('Object: %s, msg: %s.',[obj.FName, msg])));
  2456.   {$ENDIF}
  2457.   end;
  2458.   procedure DbgLog(const msg: string); overload;
  2459.   begin
  2460.   {$IFNDEF MESSAGE}
  2461.     Writeln(DebugFile, TimeToStr(time) +' > '+ msg);
  2462.     Flush(DebugFile);
  2463.   {$ELSE}
  2464.     OutputDebugString(PChar(TimeToStr(time) +' > '+ msg));
  2465.   {$ENDIF}
  2466.   end;
  2467.   procedure DbgAssert(const Message, Filename: string; LineNumber: Integer;
  2468.     ErrorAddr: Pointer);
  2469.   begin
  2470.     DbgLog(format('[ASSERT] %s (%s) line: %d, adr: $%x',
  2471.       [Message, Filename, LineNumber, Integer(ErrorAddr)]));
  2472.   end;
  2473. {$ENDIF}
  2474. // -----------------------------------------------------------------------------
  2475. //  TBCMediaType
  2476. // -----------------------------------------------------------------------------
  2477.   function TBCMediaType.Equal(mt: TBCMediaType): boolean;
  2478.   begin
  2479.     result := ((IsEqualGUID(Mediatype.majortype,mt.MediaType.majortype) = True) and
  2480.         (IsEqualGUID(Mediatype.subtype,mt.MediaType.subtype) = True) and
  2481.         (IsEqualGUID(Mediatype.formattype,mt.MediaType.formattype) = True) and
  2482.         (Mediatype.cbFormat = mt.MediaType.cbFormat) and
  2483.         ( (Mediatype.cbFormat = 0) or
  2484.           (CompareMem(Mediatype.pbFormat, mt.MediaType.pbFormat, Mediatype.cbFormat))));
  2485.   end;
  2486.   function TBCMediaType.Equal(mt: PAMMediaType): boolean;
  2487.   begin
  2488.     result := ((IsEqualGUID(Mediatype.majortype,mt.majortype) = True) and
  2489.         (IsEqualGUID(Mediatype.subtype,mt.subtype) = True) and
  2490.         (IsEqualGUID(Mediatype.formattype,mt.formattype) = True) and
  2491.         (Mediatype.cbFormat = mt.cbFormat) and
  2492.         ( (Mediatype.cbFormat = 0) or
  2493.           (CompareMem(Mediatype.pbFormat, mt.pbFormat, Mediatype.cbFormat))));
  2494.   end;
  2495.   function TBCMediaType.MatchesPartial(Partial: PAMMediaType): boolean;
  2496.   begin
  2497.     result := false;
  2498.     if (not IsEqualGUID(partial.majortype, GUID_NULL) and
  2499.         not IsEqualGUID(MediaType.majortype, partial.majortype)) then exit;
  2500.     if (not IsEqualGUID(partial.subtype, GUID_NULL) and
  2501.         not IsEqualGUID(MediaType.subtype, partial.subtype)) then exit;
  2502.     if not IsEqualGUID(partial.formattype, GUID_NULL) then
  2503.     begin
  2504.       if not IsEqualGUID(MediaType.formattype, partial.formattype) then exit;
  2505.       if (MediaType.cbFormat <> partial.cbFormat) then exit;
  2506.       if ((MediaType.cbFormat <> 0) and
  2507.           (CompareMem(MediaType.pbFormat, partial.pbFormat, MediaType.cbFormat) <> false)) then exit;
  2508.     end;
  2509.     result := True;
  2510.   end;
  2511.   function TBCMediaType.IsPartiallySpecified: boolean;
  2512.   begin
  2513.     if (IsEqualGUID(Mediatype.majortype, GUID_NULL) or
  2514.         IsEqualGUID(Mediatype.formattype, GUID_NULL)) then result := True
  2515.                                                else result := false;
  2516.   end;
  2517.   function TBCMediaType.IsValid: boolean;
  2518.   begin
  2519.     result := not IsEqualGUID(MediaType.majortype,GUID_NULL);
  2520.   end;
  2521.   procedure TBCMediaType.InitMediaType;
  2522.   begin
  2523.     ZeroMemory(MediaType, sizeof(TAMMediaType));
  2524.     MediaType.lSampleSize := 1;
  2525.     MediaType.bFixedSizeSamples := True;
  2526.   end;
  2527.   function TBCMediaType.FormatLength: Cardinal;
  2528.   begin
  2529.     result := MediaType.cbFormat
  2530.   end;
  2531. // -----------------------------------------------------------------------------
  2532. // milenko start
  2533.   function AMGetWideString(Source: WideString; out Dest: PWideChar): HRESULT;
  2534.   var NameLen: Cardinal;
  2535.   begin
  2536.     if not assigned(@Dest) then
  2537.     begin
  2538.       Result := E_POINTER;
  2539.       Exit;
  2540.     end;
  2541.     nameLen := sizeof(WCHAR) * (length(source)+1);
  2542.     Dest := CoTaskMemAlloc(nameLen);
  2543.     if (Dest = nil) then
  2544.     begin
  2545.       Result := E_OUTOFMEMORY;
  2546.       Exit;
  2547.     end;
  2548.     CopyMemory(Dest, PWideChar(Source), nameLen);
  2549.     Result := NOERROR;
  2550.   end;
  2551. {
  2552.   function AMGetWideString(Source: WideString; out Dest: PWideChar): HRESULT;
  2553.   type TWideCharArray = array of WideChar;
  2554.   var NameLen: Cardinal;
  2555.   begin
  2556.     if Source = '' then
  2557.       begin
  2558.         dest := nil;
  2559.         result := S_OK;
  2560.         exit;
  2561.       end;
  2562.     assert(@dest <> nil);
  2563.     nameLen := (length(Source)+1)*2;
  2564.     Dest := CoTaskMemAlloc(nameLen);
  2565.     if(Dest = nil) then
  2566.     begin
  2567.       result := E_OUTOFMEMORY;
  2568.       exit;
  2569.     end;
  2570.     CopyMemory(dest, pointer(Source), nameLen-1);
  2571.     TWideCharArray(dest)[(nameLen div 2)-1] := #0;
  2572.     result := NOERROR;
  2573.   end;
  2574.   }
  2575. // milenko end
  2576. // -----------------------------------------------------------------------------
  2577. function CreateMemoryAllocator(out Allocator: IMemAllocator): HRESULT;
  2578. begin
  2579.   result := CoCreateInstance(CLSID_MemoryAllocator, nil, CLSCTX_INPROC_SERVER,
  2580.     IID_IMemAllocator, Allocator);
  2581. end;
  2582. //  Put this one here rather than in ctlutil.cpp to avoid linking
  2583. //  anything brought in by ctlutil.cpp
  2584. function CreatePosPassThru(Agg: IUnknown; Renderer: boolean; Pin: IPin; out PassThru: IUnknown): HRESULT; stdcall;
  2585. var
  2586.   UnkSeek: IUnknown;
  2587.   APassThru: ISeekingPassThru;
  2588. begin
  2589.   PassThru := nil;
  2590.   result := CoCreateInstance(CLSID_SeekingPassThru, Agg, CLSCTX_INPROC_SERVER,
  2591.     IUnknown, UnkSeek);
  2592.   if FAILED(result) then exit;
  2593.   result := UnkSeek.QueryInterface(IID_ISeekingPassThru, APassThru);
  2594.   if FAILED(result) then
  2595.     begin
  2596.       UnkSeek := nil;
  2597.       exit;
  2598.     end;
  2599.   result := APassThru.Init(Renderer, Pin);
  2600.   APassThru := nil;
  2601.   if FAILED(result) then
  2602.     begin
  2603.       UnkSeek := nil;
  2604.       exit;
  2605.     end;
  2606.   PassThru := UnkSeek;
  2607.   result := S_OK;
  2608. end;
  2609. // -----------------------------------------------------------------------------
  2610.   function Templates: TBCFilterTemplate;
  2611.   begin
  2612.     if TemplatesVar = nil then TemplatesVar := TBCFilterTemplate.Create;
  2613.     result := TemplatesVar;
  2614.   end;
  2615.   function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;
  2616.   var
  2617.     Factory: TBCClassFactory;
  2618.   begin
  2619.     Factory := Templates.GetFactoryFromClassID(CLSID);
  2620.     if Factory <> nil then
  2621.       if Factory.GetInterface(IID, Obj) then
  2622.         Result := S_OK
  2623.       else
  2624.         Result := E_NOINTERFACE
  2625.     else
  2626.     begin
  2627.       Pointer(Obj) := nil;
  2628.       Result := CLASS_E_CLASSNOTAVAILABLE;
  2629.     end;
  2630.   end;
  2631.   function DllCanUnloadNow: HResult; stdcall;
  2632.   begin
  2633.     if (ObjectCount = 0) and (FactoryCount = 0) then
  2634.       result := S_OK else result := S_FALSE;;
  2635.   end;
  2636.   function DllRegisterServer: HResult; stdcall;
  2637.   begin
  2638.     if Templates.RegisterServer(True) then result := S_OK else result := E_FAIL;
  2639.   end;
  2640.   function DllUnregisterServer: HResult; stdcall;
  2641.   begin
  2642.     if Templates.RegisterServer(false) then result := S_OK else result := E_FAIL;
  2643.   end;
  2644. { TBCClassFactory }
  2645. constructor TBCClassFactory.CreateFilter(ComClass: TBCUnknownClass; Name: string;
  2646.   const ClassID: TGUID; const Category: TGUID; Merit: LongWord;
  2647.   PinCount: Cardinal; Pins: PRegFilterPins);
  2648. begin
  2649.   Templates.AddObjectFactory(Self);
  2650.   FComClass := ComClass;
  2651.   FName     := Name;
  2652.   FClassID  := ClassID;
  2653.   FCategory := Category;
  2654.   FMerit    := Merit;
  2655.   FPinCount := PinCount;
  2656.   FPins     := Pins;
  2657. end;
  2658. constructor TBCClassFactory.CreatePropertyPage(ComClass: TFormPropertyPageClass; const ClassID: TGUID);
  2659. begin
  2660.   Templates.AddObjectFactory(Self);
  2661.   FPropClass := ComClass;
  2662.   FClassID   := ClassID;
  2663.   FCategory := ClassID;
  2664. end;
  2665. function TBCClassFactory.CreateInstance(const unkOuter: IUnKnown;
  2666.   const iid: TIID; out obj): HResult;
  2667. var
  2668.   ComObject: TBCUnknown;
  2669.   PropObject: TFormPropertyPage;
  2670. begin
  2671.   if @obj = nil then
  2672.   begin
  2673.     Result := E_POINTER;
  2674.     Exit;
  2675.   end;
  2676.   Pointer(obj) := nil;
  2677.   if FPropClass <> nil then
  2678.     begin
  2679.       PropObject := TFormPropertyPageClass(FPropClass).Create(nil);
  2680.       PropObject.FPropertyPage := TBCBasePropertyPage.Create('',nil, PropObject);
  2681.       Result := PropObject.QueryInterface(IID, obj);
  2682.     end
  2683.   else
  2684.     begin
  2685.       ComObject := TBCUnknownClass(FComClass).CreateFromFactory(self, unkOuter);
  2686.       Result := ComObject.QueryInterface(IID, obj);
  2687.       if ComObject.FRefCount = 0 then ComObject.Free;
  2688.     end;
  2689. end;
  2690. procedure TBCClassFactory.UpdateRegistry(Register: Boolean);
  2691. var
  2692.   FileName: array[0..MAX_PATH-1] of Char;
  2693.   ClassID, ServerKeyName: String;
  2694. begin
  2695.   ClassID := GUIDToString(FClassID);
  2696.   ServerKeyName := 'CLSID' + ClassID + '' + 'InprocServer32';
  2697.   if Register then
  2698.   begin
  2699.     CreateRegKey('CLSID' + ClassID, '', FName);
  2700.     GetModuleFileName(hinstance, FileName, MAX_PATH);
  2701.     CreateRegKey(ServerKeyName, '', FileName);
  2702.     CreateRegKey(ServerKeyName, 'ThreadingModel', 'Both');
  2703.   end else
  2704.   begin
  2705.     DeleteRegKey(ServerKeyName);
  2706.     DeleteRegKey('CLSID' + ClassID);
  2707.   end;
  2708. end;
  2709. function TBCClassFactory.RegisterFilter(FilterMapper: IFilterMapper; Register: Boolean): boolean;
  2710. type
  2711.   TDynArrayPins = array of TRegFilterPins;
  2712.   TDynArrayPinType = array of TRegPinTypes;
  2713. var
  2714.   i, j: integer;
  2715.   FilterGUID: TGUID;
  2716. begin
  2717.   result := Succeeded(FilterMapper.UnregisterFilter(FClassID));
  2718.   if Register  then
  2719.   begin
  2720.     result := Succeeded(FilterMapper.RegisterFilter(FClassID, StringToOleStr(FName), FMerit));
  2721.     if result then
  2722.     begin
  2723.       for i := 0 to FPinCount - 1 do
  2724.       begin
  2725.         if TDynArrayPins(FPins)[i].oFilter = nil then
  2726.           FilterGUID := GUID_NULL else
  2727.           FilterGUID := TDynArrayPins(FPins)[i].oFilter^;
  2728.         result := Succeeded(FilterMapper.RegisterPin(FClassID,
  2729.           TDynArrayPins(FPins)[i].strName,
  2730.           TDynArrayPins(FPins)[i].bRendered,
  2731.           TDynArrayPins(FPins)[i].bOutput,
  2732.           TDynArrayPins(FPins)[i].bZero,
  2733.           TDynArrayPins(FPins)[i].bMany,
  2734.           FilterGUID,
  2735.           TDynArrayPins(FPins)[i].strConnectsToPin));
  2736.         if result then
  2737.         begin
  2738.           for j := 0 to TDynArrayPins(FPins)[i].nMediaTypes - 1 do
  2739.           begin
  2740.             result := Succeeded(FilterMapper.RegisterPinType(FClassID,
  2741.                         TDynArrayPins(FPins)[i].strName,
  2742.                         TDynArrayPinType(TDynArrayPins(FPins)[i].lpMediaType)[j].clsMajorType^,
  2743.                         TDynArrayPinType(TDynArrayPins(FPins)[i].lpMediaType)[j].clsMinorType^));
  2744.             if not result then break;
  2745.           end;
  2746.           if not result then break;
  2747.         end;
  2748.         if not result then break;
  2749.       end;
  2750.     end;
  2751.   end;
  2752. end;
  2753. function TBCClassFactory.RegisterFilter(FilterMapper: IFilterMapper2; Register: Boolean): boolean;
  2754. var
  2755.   RegFilter: TRegFilter2;
  2756. begin
  2757.   result := Succeeded(FilterMapper.UnregisterFilter(FCategory, nil, FClassID));
  2758. // milenko start (bugfix for Windows 98)
  2759. // Windows 98 fails when unregistering a Property Page, so the whole
  2760. // DLLUnregisterServer function fails without unregistering the Filter.
  2761.   if not result and not Register and (FName = '') then Result := True;
  2762. // milenko end
  2763.   if Register then
  2764.   begin
  2765.     RegFilter.dwVersion := 1;
  2766.     RegFilter.dwMerit   := FMerit;
  2767.     RegFilter.cPins     := FPinCount;
  2768.     RegFilter.rgPins    := FPins;
  2769.     result := Succeeded(FilterMapper.RegisterFilter(FClassID, PWideChar(WideString(FName)),
  2770.       nil, @FCategory, nil, RegFilter));
  2771.   end;
  2772. end;
  2773. function TBCClassFactory._AddRef: Integer;
  2774. begin
  2775.   result := InterlockedIncrement(FactoryCount);
  2776. end;
  2777. function TBCClassFactory._Release: Integer;
  2778. begin
  2779.   result := InterlockedDecrement(FactoryCount);
  2780. end;
  2781. function TBCClassFactory.LockServer(fLock: BOOL): HResult;
  2782. begin
  2783.   Result := CoLockObjectExternal(Self, fLock, True);
  2784.   if flock then InterlockedIncrement(ObjectCount)
  2785.            else InterlockedDecrement(ObjectCount);
  2786. end;
  2787. function TBCClassFactory.QueryInterface(const IID: TGUID; out Obj): HResult;
  2788. begin
  2789.   if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE;
  2790. end;
  2791. { TBCFilterTemplate }
  2792. procedure TBCFilterTemplate.AddObjectFactory(Factory: TBCClassFactory);
  2793. begin
  2794.   Factory.FNext := FFactoryList;
  2795.   FFactoryList := Factory;
  2796. end;
  2797. constructor TBCFilterTemplate.Create;
  2798. begin
  2799.   FFactoryList := nil;
  2800. end;
  2801. destructor TBCFilterTemplate.Destroy;
  2802. var AFactory: TBCClassFactory;
  2803. begin
  2804.   while FFactoryList <> nil do
  2805.   begin
  2806.     AFactory := FFactoryList;
  2807.     FFactoryList := AFactory.FNext;
  2808.     AFactory.Free;
  2809.   end;
  2810.   inherited Destroy;
  2811. end;
  2812. function TBCFilterTemplate.GetFactoryFromClassID(const CLSID: TGUID): TBCClassFactory;
  2813. var AFactory: TBCClassFactory;
  2814. begin
  2815.   result := nil;
  2816.   AFactory := FFactoryList;
  2817.   while AFactory <> nil do
  2818.   begin
  2819.     if IsEqualGUID(CLSID, AFactory.FClassID) then
  2820.     begin
  2821.       result := AFactory;
  2822.       break;
  2823.     end;
  2824.     AFactory := AFactory.FNext;
  2825.   end;
  2826. end;
  2827. function TBCFilterTemplate.RegisterServer(Register: Boolean): boolean;
  2828.   var
  2829.   {$IFDEF DEBUG}
  2830.     Filename: array[0..MAX_PATH-1] of Char;
  2831.   {$ENDIF}
  2832.     FilterMapper : IFilterMapper;
  2833.     FilterMapper2: IFilterMapper2;
  2834.     Factory: TBCClassFactory;
  2835.   begin
  2836.     result := false;
  2837.   {$IFDEF DEBUG}
  2838.     GetModuleFileName(hinstance, Filename, sizeof(Filename));
  2839.     DbgLog('TBCFilterTemplate.RegisterServer in ' + Filename);
  2840.   {$ENDIF}
  2841.     if Failed(CoCreateInstance(CLSID_FilterMapper2, nil, CLSCTX_INPROC_SERVER, IFilterMapper2, FilterMapper2)) then
  2842.     if Failed(CoCreateInstance(CLSID_FilterMapper, nil, CLSCTX_INPROC_SERVER, IFilterMapper, FilterMapper)) then exit;
  2843.     Factory := FFactoryList;
  2844.     while Factory <> nil do
  2845.     begin
  2846.       Factory.UpdateRegistry(false);
  2847.         if FilterMapper2 <> nil then
  2848.              result := Factory.RegisterFilter(FilterMapper2, Register)
  2849.         else result := Factory.RegisterFilter(FilterMapper, Register);
  2850.         if not result then break else Factory.UpdateRegistry(register);
  2851.       Factory := Factory.FNext;
  2852.     end;
  2853.     FilterMapper := nil;
  2854.     FilterMapper2 := nil;
  2855.   end;
  2856. { TBCBaseObject }
  2857. constructor TBCBaseObject.Create(Name: string);
  2858. begin
  2859. {$IFDEF DEBUG}
  2860.   DbgLog('[' + ClassName + ': ' + Name + '] CREATE');
  2861. {$ENDIF}
  2862.   FName := name;
  2863. end;
  2864. destructor TBCBaseObject.Destroy;
  2865. begin
  2866. {$IFDEF DEBUG}
  2867.   DbgLog('[' + ClassName + ': ' + FName + '] FREE');
  2868. {$ENDIF}
  2869.   inherited;
  2870. end;
  2871. procedure TBCBaseObject.FreeInstance;
  2872. begin
  2873.   inherited;
  2874.   InterlockedDecrement(ObjectCount);
  2875. end;
  2876. class function TBCBaseObject.NewInstance: TObject;
  2877. begin
  2878.   result := inherited NewInstance;
  2879.   InterlockedIncrement(ObjectCount);
  2880. end;
  2881. class function TBCBaseObject.ObjectsActive: integer;
  2882. begin
  2883.   result := ObjectCount;
  2884. end;
  2885. { TBCUnknown }
  2886. function TBCUnknown.QueryInterface(const IID: TGUID; out Obj): HResult;
  2887. begin
  2888.   if FOwner <> nil then
  2889.     Result := IUnknown(FOwner).QueryInterface(IID, Obj)
  2890.   else
  2891.     Result := NonDelegatingQueryInterface(IID, Obj);
  2892. end;
  2893. function TBCUnknown._AddRef: Integer;
  2894. begin
  2895.   if FOwner <> nil then
  2896.     Result := IUnknown(FOwner)._AddRef else
  2897.     Result := NonDelegatingAddRef;
  2898. end;
  2899. function TBCUnknown._Release: Integer;
  2900. begin
  2901.   if FOwner <> nil then
  2902.     Result := IUnknown(FOwner)._Release else
  2903.     Result := NonDelegatingRelease;
  2904. end;
  2905. function TBCUnknown.NonDelegatingQueryInterface(const IID: TGUID;
  2906.   out Obj): HResult;
  2907. begin
  2908.   if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE;
  2909. end;
  2910. function TBCUnknown.NonDelegatingAddRef: Integer;
  2911. begin
  2912.   Result := InterlockedIncrement(FRefCount);
  2913. end;
  2914. function TBCUnknown.NonDelegatingRelease: Integer;
  2915. begin
  2916.   Result := InterlockedDecrement(FRefCount);
  2917.   if Result = 0 then Destroy;
  2918. end;
  2919. function TBCUnknown.GetOwner: IUnKnown;
  2920. begin
  2921.   result := IUnKnown(FOwner);
  2922. end;
  2923. constructor TBCUnknown.Create(name: string; Unk: IUnKnown);
  2924. begin
  2925.   inherited Create(name);
  2926.   FOwner := Pointer(Unk);
  2927. end;
  2928. constructor TBCUnknown.CreateFromFactory(Factory: TBCClassFactory;
  2929.   const Controller: IUnKnown);
  2930. begin
  2931.   Create(Factory.FName, Controller);
  2932. end;
  2933. { TBCBaseFilter }
  2934. constructor TBCBaseFilter.Create(Name: string; Unk: IUnKnown;
  2935.   Lock: TBCCritSec; const clsid: TGUID);
  2936. begin
  2937.     inherited Create(Name, Unk);
  2938.     FLock  := Lock;
  2939.     Fclsid := clsid;
  2940.     FState := State_Stopped;
  2941.     FClock := nil;
  2942.     FGraph := nil;
  2943.     FSink  := nil;
  2944.     FFilterName := '';
  2945.     FPinVersion := 1;
  2946.     Assert(FLock <> nil, 'Lock = nil !');
  2947. end;
  2948. constructor TBCBaseFilter.Create(Name: string; Unk: IUnKnown;
  2949.   Lock: TBCCritSec; const clsid: TGUID; out hr: HRESULT);
  2950. begin
  2951.   Create(Name, Unk, Lock, clsid);
  2952.   assert(@hr <> nil, 'Unreferenced parameter: hr');
  2953. end;
  2954. constructor TBCBaseFilter.CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown);
  2955. begin
  2956.   Create(Factory.FName,Controller, TBCCritSec.Create, Factory.FClassID);
  2957. end;
  2958. destructor TBCBaseFilter.destroy;
  2959. begin
  2960.   FFilterName := '';
  2961.   FClock := nil;
  2962.   FLock.Free;
  2963.   inherited;
  2964. end;
  2965. function TBCBaseFilter.EnumPins(out ppEnum: IEnumPins): HRESULT;
  2966. begin
  2967.   // Create a new ref counted enumerator
  2968.   ppEnum := TBCEnumPins.Create(self, nil);
  2969.   if ppEnum = nil then result := E_OUTOFMEMORY else result := NOERROR;
  2970. end;
  2971. function TBCBaseFilter.FindPin(Id: PWideChar; out Pin: IPin): HRESULT;
  2972. var
  2973.   i: integer;
  2974.   APin: TBCBasePin;
  2975. begin
  2976.   //  We're going to search the pin list so maintain integrity
  2977.   FLock.Lock;
  2978.   try
  2979.     for i := 0 to GetPinCount - 1 do
  2980.     begin
  2981.       APin := GetPin(i);
  2982.       ASSERT(APin <> nil);
  2983.       if (APin.FPinName = WideString(Id)) then
  2984.       begin
  2985.           //  Found one that matches
  2986.           //  AddRef() and return it
  2987.           Pin := APin;
  2988.           result := S_OK;
  2989.           exit;
  2990.       end;
  2991.     end;
  2992.     Pin := nil;
  2993.     result := VFW_E_NOT_FOUND;
  2994.   finally
  2995.     FLock.UnLock;
  2996.   end;
  2997. end;
  2998. function TBCBaseFilter.GetClassID(out classID: TCLSID): HResult;
  2999. begin
  3000.   classID := FCLSID;
  3001.   result  := NOERROR;
  3002. end;
  3003. function TBCBaseFilter.GetFilterGraph: IFilterGraph;
  3004. begin
  3005.   result := FGRaph;
  3006. end;
  3007. function TBCBaseFilter.GetPinVersion: LongInt;
  3008. begin
  3009.   result := FPinVersion;
  3010. end;
  3011. function TBCBaseFilter.GetState(dwMilliSecsTimeout: DWORD;
  3012.   out State: TFilterState): HRESULT;
  3013. begin
  3014.   State := FState;
  3015.   result := S_OK;
  3016. end;
  3017. function TBCBaseFilter.GetSyncSource(out pClock: IReferenceClock): HRESULT;
  3018. begin
  3019.   FLock.Lock;
  3020.   try
  3021.     pClock := FClock;
  3022.   finally
  3023.     result := NOERROR;
  3024.     FLock.UnLock;
  3025.   end;
  3026. end;
  3027. procedure TBCBaseFilter.IncrementPinVersion;
  3028. begin
  3029.   InterlockedIncrement(FPinVersion)
  3030. end;
  3031. function TBCBaseFilter.IsActive: boolean;
  3032. begin
  3033.   FLock.Lock;
  3034.   try
  3035.     result :=  ((FState = State_Paused) or (FState = State_Running));
  3036.   finally
  3037.     FLock.UnLock;
  3038.   end;
  3039. end;
  3040. function TBCBaseFilter.IsStopped: boolean;
  3041. begin
  3042.   result := (FState = State_Stopped);
  3043. end;
  3044. function TBCBaseFilter.JoinFilterGraph(pGraph: IFilterGraph;
  3045.   pName: PWideChar): HRESULT;
  3046. begin
  3047.   FLock.Lock;
  3048.   try
  3049.     //Henri: This implementation seem to be stupid but it's the exact conversion ?????
  3050.     // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink)
  3051.     Pointer(FGraph) := Pointer(pGraph);
  3052.     if (FGraph <> nil) then
  3053.     begin
  3054.       if FAILED(FGraph.QueryInterface(IID_IMediaEventSink, FSink)) then
  3055.            ASSERT(FSink = nil)
  3056.       else FSink._Release;        // we do NOT keep a reference on it.
  3057.     end
  3058.     else
  3059.     begin
  3060.         // if graph pointer is null, then we should
  3061.         // also release the IMediaEventSink on the same object - we don't
  3062.         // refcount it, so just set it to null
  3063.         Pointer(FSink) := nil;
  3064.     end;
  3065.     FFilterName := '';
  3066.     if assigned(pName) then FFilterName := WideString(pName);
  3067.     result := NOERROR;
  3068.   finally
  3069.     FLock.UnLock;
  3070.   end;
  3071. end;
  3072. function TBCBaseFilter.NotifyEvent(EventCode, EventParam1,
  3073.   EventParam2: Integer): HRESULT;
  3074. var
  3075.   Filter : IBaseFilter;
  3076. begin
  3077.   // Snapshot so we don't have to lock up
  3078.   if assigned(FSink) then
  3079.   begin
  3080.     QueryInterface(IID_IBaseFilter,Filter);
  3081.     if (EC_COMPLETE = EventCode) then EventParam2 := LongInt(Filter);
  3082.     result := FSink.Notify(EventCode, EventParam1, EventParam2);
  3083.     Filter := nil;
  3084.   end
  3085.   else
  3086.     result := E_NOTIMPL;
  3087. end;
  3088. function TBCBaseFilter.Pause: HRESULT;
  3089. var
  3090.   c: integer;
  3091.   pin: TBCBasePin;
  3092. begin
  3093.   FLock.Lock;
  3094.   try
  3095.     if FState = State_Stopped then
  3096.     begin
  3097.       for c := 0 to GetPinCount - 1 do
  3098.       begin
  3099.         Pin := GetPin(c);
  3100.         // Disconnected pins are not activated - this saves pins
  3101.         // worrying about this state themselves
  3102.         if Pin.IsConnected then
  3103.         begin
  3104.           result := Pin.Active;
  3105.           if FAILED(result) then exit;
  3106.         end;
  3107.       end;
  3108.     end;
  3109.     // notify all pins of the change to active state
  3110.     FState := State_Paused;
  3111.     result := S_OK;
  3112.   finally
  3113.     FLock.UnLock;
  3114.   end;
  3115. end;
  3116. function TBCBaseFilter.QueryFilterInfo(out pInfo: TFilterInfo): HRESULT;
  3117. var
  3118.   len: Integer;
  3119. begin
  3120.   len := Length(pInfo.achName)-1;
  3121.   if (Length(FFilterName) > 0) then
  3122.     if (Length(FFilterName) > len) then
  3123.     begin
  3124.       CopyMemory(@pInfo.achName, PWideChar(FFilterName), len * SizeOf(WCHAR));
  3125.       pInfo.achName[len] := #0;
  3126.     end
  3127.     else
  3128.       CopyMemory(@pInfo.achName, PWideChar(FFilterName), (Length(FFilterName)+1) * SizeOf(WCHAR))
  3129.   else
  3130.     pInfo.achName[0] := #0;
  3131.   pInfo.pGraph := FGraph;
  3132.   result := NOERROR;
  3133. end;
  3134. function TBCBaseFilter.QueryVendorInfo(out pVendorInfo: PWideChar): HRESULT;
  3135. begin
  3136.   result := E_NOTIMPL;
  3137. end;
  3138. function TBCBaseFilter.ReconnectPin(Pin: IPin; pmt: PAMMediaType): HRESULT;
  3139. var Graph2: IFilterGraph2;
  3140. begin
  3141.   if (FGraph <> nil) then
  3142.     begin
  3143.       result := FGraph.QueryInterface(IID_IFilterGraph2, Graph2);
  3144.       if Succeeded(result) then
  3145.         begin
  3146.           result := Graph2.ReconnectEx(Pin, pmt);
  3147.           Graph2 := nil;
  3148.         end
  3149.       else
  3150.         result := FGraph.Reconnect(Pin);
  3151.     end
  3152.   else
  3153.     result := E_NOINTERFACE;
  3154. end;
  3155. function TBCBaseFilter.Register: HRESULT;
  3156. var
  3157.   {$IFDEF DEBUG}
  3158.     Filename: array[0..MAX_PATH-1] of Char;
  3159.   {$ENDIF}
  3160.   FilterMapper : IFilterMapper;
  3161.   FilterMapper2: IFilterMapper2;
  3162.   Factory: TBCClassFactory;
  3163.   AResult : boolean;
  3164. begin
  3165.   Aresult := false;
  3166.   Result := S_FALSE;
  3167.   Factory := Templates.GetFactoryFromClassID(FCLSID);
  3168.   if Factory <> nil then
  3169.   begin
  3170.   {$IFDEF DEBUG}
  3171.     GetModuleFileName(hinstance, Filename, sizeof(Filename));
  3172.     DbgLog(Self,'Register in ' + Filename);
  3173.   {$ENDIF}
  3174.     if Failed(CoCreateInstance(CLSID_FilterMapper2, nil, CLSCTX_INPROC_SERVER, IFilterMapper2, FilterMapper2)) then
  3175.     if Failed(CoCreateInstance(CLSID_FilterMapper, nil, CLSCTX_INPROC_SERVER, IFilterMapper, FilterMapper)) then exit;
  3176.     Factory.UpdateRegistry(false);
  3177.     if FilterMapper2 <> nil then
  3178.          AResult := Factory.RegisterFilter(FilterMapper2, True)
  3179.     else AResult := Factory.RegisterFilter(FilterMapper, True);
  3180.     if Aresult then Factory.UpdateRegistry(True);
  3181.     FilterMapper := nil;
  3182.     FilterMapper2 := nil;
  3183.   end;
  3184.   if AResult then result := S_OK else result := S_False;
  3185. end;
  3186. function TBCBaseFilter.Run(tStart: TReferenceTime): HRESULT;
  3187. var
  3188.   c: integer;
  3189.   Pin: TBCBasePin;
  3190. begin
  3191.   FLock.Lock;
  3192.   try
  3193.     // remember the stream time offset
  3194.     FStart := tStart;
  3195.     if FState = State_Stopped then
  3196.     begin
  3197.       result := Pause;
  3198.       if FAILED(result) then exit;
  3199.     end;
  3200.     // notify all pins of the change to active state
  3201.     if (FState <> State_Running) then
  3202.     begin
  3203.       for c := 0 to GetPinCount - 1 do
  3204.       begin
  3205.         Pin := GetPin(c);
  3206.         // Disconnected pins are not activated - this saves pins
  3207.         // worrying about this state themselves
  3208.         if Pin.IsConnected then
  3209.         begin
  3210.           result := Pin.Run(tStart);
  3211.           if FAILED(result) then exit;
  3212.         end;
  3213.       end;
  3214.     end;
  3215.     FState := State_Running;
  3216.     result := S_OK;
  3217.   finally
  3218.     FLock.UnLock;
  3219.   end;
  3220. end;
  3221. function TBCBaseFilter.SetSyncSource(pClock: IReferenceClock): HRESULT;
  3222. begin
  3223.   FLock.Lock;
  3224.   try
  3225.     FClock := pClock;
  3226.   finally
  3227.     result := NOERROR;
  3228.     FLock.UnLock;
  3229.   end;
  3230. end;
  3231. function TBCBaseFilter.Stop: HRESULT;
  3232. var
  3233.   c: integer;
  3234.   Pin: TBCBasePin;
  3235.   hr: HResult;
  3236. begin
  3237.   FLock.Lock;
  3238.   try
  3239.     result := NOERROR;
  3240.     // notify all pins of the state change
  3241.     if (FState <> State_Stopped) then
  3242.     begin
  3243.       for c := 0 to GetPinCount - 1 do
  3244.       begin
  3245.         Pin := GetPin(c);
  3246.         // Disconnected pins are not activated - this saves pins worrying
  3247.         // about this state themselves. We ignore the return code to make
  3248.         // sure everyone is inactivated regardless. The base input pin
  3249.         // class can return an error if it has no allocator but Stop can
  3250.         // be used to resync the graph state after something has gone bad
  3251.         if Pin.IsConnected then
  3252.         begin
  3253.           hr := Pin.Inactive;
  3254.           if (Failed(hr) and SUCCEEDED(result)) then result := hr;
  3255.         end;
  3256.       end;
  3257.     end;
  3258.     FState := State_Stopped;
  3259.   finally
  3260.     FLock.UnLock;
  3261.   end;
  3262. end;
  3263. function TBCBaseFilter.StreamTime(out rtStream: TReferenceTime): HRESULT;
  3264. begin
  3265.   // Caller must lock for synchronization
  3266.   // We can't grab the filter lock because we want to be able to call
  3267.   // this from worker threads without deadlocking
  3268.   if FClock = nil then
  3269.   begin
  3270.     result := VFW_E_NO_CLOCK;
  3271.     exit;
  3272.   end;
  3273.   // get the current reference time
  3274.   result := FClock.GetTime(PInt64(@rtStream)^);
  3275.   if FAILED(result) then exit;
  3276.   // subtract the stream offset to get stream time
  3277.   rtStream := rtStream - FStart;
  3278.   result := S_OK;
  3279. end;
  3280. function TBCBaseFilter.Unregister: HRESULT;
  3281. var
  3282.   {$IFDEF DEBUG}
  3283.     Filename: array[0..MAX_PATH-1] of Char;
  3284.   {$ENDIF}
  3285.   FilterMapper : IFilterMapper;
  3286.   FilterMapper2: IFilterMapper2;
  3287.   Factory: TBCClassFactory;
  3288.   AResult : boolean;
  3289. begin
  3290.   Aresult := false;
  3291.   Result := S_FALSE;
  3292.   Factory := Templates.GetFactoryFromClassID(FCLSID);
  3293.   if Factory <> nil then
  3294.   begin
  3295.   {$IFDEF DEBUG}
  3296.     GetModuleFileName(hinstance, Filename, sizeof(Filename));
  3297.     DbgLog(Self,'Unregister in ' + Filename);
  3298.   {$ENDIF}
  3299.     if Failed(CoCreateInstance(CLSID_FilterMapper2, nil, CLSCTX_INPROC_SERVER, IFilterMapper2, FilterMapper2)) then
  3300.     if Failed(CoCreateInstance(CLSID_FilterMapper, nil, CLSCTX_INPROC_SERVER, IFilterMapper, FilterMapper)) then exit;
  3301.     Factory.UpdateRegistry(false);
  3302.     if FilterMapper2 <> nil then
  3303.          AResult := Factory.RegisterFilter(FilterMapper2, false)
  3304.     else AResult := Factory.RegisterFilter(FilterMapper, false);
  3305.     if Aresult then Factory.UpdateRegistry(false);
  3306.     FilterMapper := nil;
  3307.     FilterMapper2 := nil;
  3308.   end;
  3309.   if AResult then result := S_OK else result := S_False;
  3310. end;
  3311. { TBCEnumPins }
  3312. constructor TBCEnumPins.Create(Filter: TBCBaseFilter; EnumPins: TBCEnumPins);
  3313. var i: integer;
  3314. begin
  3315.   FPosition := 0;
  3316.   FPinCount := 0;
  3317.   FFilter   := Filter;
  3318.   FPinCache := TList.Create;
  3319.   // We must be owned by a filter derived from CBaseFilter
  3320.   ASSERT(FFilter <> nil);
  3321.   // Hold a reference count on our filter
  3322.   FFilter._AddRef;
  3323.   // Are we creating a new enumerator
  3324.   if (EnumPins = nil) then
  3325.     begin
  3326.       FVersion  := FFilter.GetPinVersion;
  3327.       FPinCount := FFilter.GetPinCount;
  3328.     end
  3329.   else
  3330.     begin
  3331.       ASSERT(FPosition <= FPinCount);
  3332.       FPosition := EnumPins.FPosition;
  3333.       FPinCount := EnumPins.FPinCount;
  3334.       FVersion  := EnumPins.FVersion;
  3335.       FPinCache.Clear;
  3336.       if EnumPins.FPinCache.Count > 0 then
  3337.         for i := 0 to EnumPins.FPinCache.Count - 1 do
  3338.           FPinCache.Add(EnumPins.FPinCache.Items[i]);
  3339.     end;
  3340. end;
  3341. destructor TBCEnumPins.Destroy;
  3342. begin
  3343.   FPinCache.Free;
  3344.   FFilter._Release;
  3345.   inherited Destroy;
  3346. end;
  3347. function TBCEnumPins.Clone(out ppEnum: IEnumPins): HRESULT;
  3348. begin
  3349.   result := NOERROR;
  3350.   // Check we are still in sync with the filter
  3351.   if AreWeOutOfSync then
  3352.     begin
  3353.       ppEnum := nil;
  3354.       result := VFW_E_ENUM_OUT_OF_SYNC;
  3355.     end
  3356.   else
  3357.   begin
  3358.     ppEnum := TBCEnumPins.Create(FFilter, self);
  3359.     if ppEnum = nil then result := E_OUTOFMEMORY;
  3360.   end;
  3361. end;
  3362. function TBCEnumPins.Next(cPins: ULONG; out ppPins: IPin;
  3363.   pcFetched: PULONG): HRESULT;
  3364. type
  3365.   TPointerDynArray = array of Pointer;
  3366.   TIPinDynArray = array of IPin;
  3367. var
  3368.   Fetched: cardinal;
  3369.   RealPins: integer;
  3370.   Pin: TBCBasePin;
  3371. begin
  3372.     if pcFetched <> nil then
  3373.       pcFetched^ := 0
  3374.     else
  3375.       if (cPins>1) then
  3376.       begin
  3377.         result := E_INVALIDARG;
  3378.         exit;
  3379.       end;
  3380.     Fetched := 0; // increment as we get each one.
  3381.     // Check we are still in sync with the filter
  3382.     // If we are out of sync, we should refresh the enumerator.
  3383.     // This will reset the position and update the other members, but
  3384.     // will not clear cache of pins we have already returned.
  3385.     if AreWeOutOfSync then
  3386.       Refresh;
  3387.     // Calculate the number of available pins
  3388.     RealPins := min(FPinCount - FPosition, cPins);
  3389.     if RealPins = 0 then
  3390.     begin
  3391.       result := S_FALSE;
  3392.       exit;
  3393.     end;
  3394.     {  Return each pin interface NOTE GetPin returns CBasePin * not addrefed
  3395.        so we must QI for the IPin (which increments its reference count)
  3396.        If while we are retrieving a pin from the filter an error occurs we
  3397.        assume that our internal state is stale with respect to the filter
  3398.        (for example someone has deleted a pin) so we
  3399.        return VFW_E_ENUM_OUT_OF_SYNC }
  3400.     while RealPins > 0 do
  3401.     begin
  3402.       // Get the next pin object from the filter */
  3403.       inc(FPosition);
  3404.       Pin := FFilter.GetPin(FPosition-1);
  3405.       if Pin = nil then
  3406.       begin
  3407.         // If this happend, and it's not the first time through, then we've got a problem,
  3408.         // since we should really go back and release the iPins, which we have previously
  3409.         // AddRef'ed.