123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- //------------------------------------------------------------------------------
- // File: RenBase.h
- //
- // Desc: DirectShow base classes - defines a generic ActiveX base renderer
- // class.
- //
- // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
- #ifndef __RENBASE__
- #define __RENBASE__
- // Forward class declarations
- class CBaseRenderer;
- class CBaseVideoRenderer;
- class CRendererInputPin;
- // This is our input pin class that channels calls to the renderer
- class CRendererInputPin : public CBaseInputPin
- {
- protected:
- CBaseRenderer *m_pRenderer;
- public:
- CRendererInputPin(__inout CBaseRenderer *pRenderer,
- __inout HRESULT *phr,
- __in_opt LPCWSTR Name);
- // Overriden from the base pin classes
- HRESULT BreakConnect();
- HRESULT CompleteConnect(IPin *pReceivePin);
- HRESULT SetMediaType(const CMediaType *pmt);
- HRESULT CheckMediaType(const CMediaType *pmt);
- HRESULT Active();
- HRESULT Inactive();
- // Add rendering behaviour to interface functions
- STDMETHODIMP QueryId(__deref_out LPWSTR *Id);
- STDMETHODIMP EndOfStream();
- STDMETHODIMP BeginFlush();
- STDMETHODIMP EndFlush();
- STDMETHODIMP Receive(IMediaSample *pMediaSample);
- // Helper
- IMemAllocator inline *Allocator() const {
- return m_pAllocator;
- }
- };
- // Main renderer class that handles synchronisation and state changes
- class CBaseRenderer : public CBaseFilter
- {
- protected:
- friend class CRendererInputPin;
- friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
- UINT uMsg, // Not currently used
- DWORD_PTR dwUser, // User information
- DWORD_PTR dw1, // Windows reserved
- DWORD_PTR dw2); // Is also reserved
- CRendererPosPassThru *m_pPosition; // Media seeking pass by object
- CAMEvent m_RenderEvent; // Used to signal timer events
- CAMEvent m_ThreadSignal; // Signalled to release worker thread
- CAMEvent m_evComplete; // Signalled when state complete
- BOOL m_bAbort; // Stop us from rendering more data
- BOOL m_bStreaming; // Are we currently streaming
- DWORD_PTR m_dwAdvise; // Timer advise cookie
- IMediaSample *m_pMediaSample; // Current image media sample
- BOOL m_bEOS; // Any more samples in the stream
- BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE
- CRendererInputPin *m_pInputPin; // Our renderer input pin object
- CCritSec m_InterfaceLock; // Critical section for interfaces
- CCritSec m_RendererLock; // Controls access to internals
- IQualityControl * m_pQSink; // QualityControl sink
- BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT
- // Avoid some deadlocks by tracking filter during stop
- volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive
- // And actually processing the sample
- REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE
- UINT m_EndOfStreamTimer; // Used to signal end of stream
- CCritSec m_ObjectCreationLock; // This lock protects the creation and
- // of m_pPosition and m_pInputPin. It
- // ensures that two threads cannot create
- // either object simultaneously.
- public:
- CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
- __in_opt LPCTSTR pName, // Debug ONLY description
- __inout_opt LPUNKNOWN pUnk, // Aggregated owner object
- __inout HRESULT *phr); // General OLE return code
- ~CBaseRenderer();
- // Overriden to say what interfaces we support and where
- virtual HRESULT GetMediaPositionInterface(REFIID riid, __deref_out void **ppv);
- STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **);
- virtual HRESULT SourceThreadCanWait(BOOL bCanWait);
- #ifdef DEBUG
- // Debug only dump of the renderer state
- void DisplayRendererState();
- #endif
- virtual HRESULT WaitForRenderTime();
- virtual HRESULT CompleteStateChange(FILTER_STATE OldState);
- // Return internal information about this filter
- BOOL IsEndOfStream() {
- return m_bEOS;
- };
- BOOL IsEndOfStreamDelivered() {
- return m_bEOSDelivered;
- };
- BOOL IsStreaming() {
- return m_bStreaming;
- };
- void SetAbortSignal(BOOL bAbort) {
- m_bAbort = bAbort;
- };
- virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { };
- CAMEvent *GetRenderEvent() {
- return &m_RenderEvent;
- };
- // Permit access to the transition state
- void Ready() {
- m_evComplete.Set();
- };
- void NotReady() {
- m_evComplete.Reset();
- };
- BOOL CheckReady() {
- return m_evComplete.Check();
- };
- virtual int GetPinCount();
- virtual CBasePin *GetPin(int n);
- FILTER_STATE GetRealState();
- void SendRepaint();
- void SendNotifyWindow(IPin *pPin,HWND hwnd);
- BOOL OnDisplayChange();
- void SetRepaintStatus(BOOL bRepaint);
- // Override the filter and pin interface functions
- STDMETHODIMP Stop();
- STDMETHODIMP Pause();
- STDMETHODIMP Run(REFERENCE_TIME StartTime);
- STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State);
- STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin);
- // These are available for a quality management implementation
- virtual void OnRenderStart(IMediaSample *pMediaSample);
- virtual void OnRenderEnd(IMediaSample *pMediaSample);
- virtual HRESULT OnStartStreaming() {
- return NOERROR;
- };
- virtual HRESULT OnStopStreaming() {
- return NOERROR;
- };
- virtual void OnWaitStart() { };
- virtual void OnWaitEnd() { };
- virtual void PrepareRender() { };
- #ifdef PERF
- REFERENCE_TIME m_trRenderStart; // Just before we started drawing
- // Set in OnRenderStart, Used in OnRenderEnd
- int m_idBaseStamp; // MSR_id for frame time stamp
- int m_idBaseRenderTime; // MSR_id for true wait time
- int m_idBaseAccuracy; // MSR_id for time frame is late (int)
- #endif
- // Quality management implementation for scheduling rendering
- virtual BOOL ScheduleSample(IMediaSample *pMediaSample);
- virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample,
- __out REFERENCE_TIME *pStartTime,
- __out REFERENCE_TIME *pEndTime);
- virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
- __out REFERENCE_TIME *ptrStart,
- __out REFERENCE_TIME *ptrEnd);
- // Lots of end of stream complexities
- void TimerCallback();
- void ResetEndOfStreamTimer();
- HRESULT NotifyEndOfStream();
- virtual HRESULT SendEndOfStream();
- virtual HRESULT ResetEndOfStream();
- virtual HRESULT EndOfStream();
- // Rendering is based around the clock
- void SignalTimerFired();
- virtual HRESULT CancelNotification();
- virtual HRESULT ClearPendingSample();
- // Called when the filter changes state
- virtual HRESULT Active();
- virtual HRESULT Inactive();
- virtual HRESULT StartStreaming();
- virtual HRESULT StopStreaming();
- virtual HRESULT BeginFlush();
- virtual HRESULT EndFlush();
- // Deal with connections and type changes
- virtual HRESULT BreakConnect();
- virtual HRESULT SetMediaType(const CMediaType *pmt);
- virtual HRESULT CompleteConnect(IPin *pReceivePin);
- // These look after the handling of data samples
- virtual HRESULT PrepareReceive(IMediaSample *pMediaSample);
- virtual HRESULT Receive(IMediaSample *pMediaSample);
- virtual BOOL HaveCurrentSample();
- virtual IMediaSample *GetCurrentSample();
- virtual HRESULT Render(IMediaSample *pMediaSample);
- // Derived classes MUST override these
- virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
- virtual HRESULT CheckMediaType(const CMediaType *) PURE;
- // Helper
- void WaitForReceiveToComplete();
- };
- // CBaseVideoRenderer is a renderer class (see its ancestor class) and
- // it handles scheduling of media samples so that they are drawn at the
- // correct time by the reference clock. It implements a degradation
- // strategy. Possible degradation modes are:
- // Drop frames here (only useful if the drawing takes significant time)
- // Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
- // Signal supplier to change the frame rate - i.e. ongoing skipping.
- // Or any combination of the above.
- // In order to determine what's useful to try we need to know what's going
- // on. This is done by timing various operations (including the supplier).
- // This timing is done by using timeGetTime as it is accurate enough and
- // usually cheaper than calling the reference clock. It also tells the
- // truth if there is an audio break and the reference clock stops.
- // We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
- // which the rest of the renderer calls at significant moments. These do
- // the timing.
- // the number of frames that the sliding averages are averaged over.
- // the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
- #define AVGPERIOD 4
- #define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
- // Spot the bug in this macro - I can't. but it doesn't work!
- class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
- public IQualProp, // Property page guff
- public IQualityControl // Allow throttling
- {
- protected:
- // Hungarian:
- // tFoo is the time Foo in mSec (beware m_tStart from filter.h)
- // trBar is the time Bar by the reference clock
- //******************************************************************
- // State variables to control synchronisation
- //******************************************************************
- // Control of sending Quality messages. We need to know whether
- // we are in trouble (e.g. frames being dropped) and where the time
- // is being spent.
- // When we drop a frame we play the next one early.
- // The frame after that is likely to wait before drawing and counting this
- // wait as spare time is unfair, so we count it as a zero wait.
- // We therefore need to know whether we are playing frames early or not.
- int m_nNormal; // The number of consecutive frames
- // drawn at their normal time (not early)
- // -1 means we just dropped a frame.
- #ifdef PERF
- BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm
- // not keen on people using it!)
- #endif
- BOOL m_bSupplierHandlingQuality;// The response to Quality messages says
- // our supplier is handling things.
- // We will allow things to go extra late
- // before dropping frames. We will play
- // very early after he has dropped one.
- // Control of scheduling, frame dropping etc.
- // We need to know where the time is being spent so as to tell whether
- // we should be taking action here, signalling supplier or what.
- // The variables are initialised to a mode of NOT dropping frames.
- // They will tell the truth after a few frames.
- // We typically record a start time for an event, later we get the time
- // again and subtract to get the elapsed time, and we average this over
- // a few frames. The average is used to tell what mode we are in.
- // Although these are reference times (64 bit) they are all DIFFERENCES
- // between times which are small. An int will go up to 214 secs before
- // overflow. Avoiding 64 bit multiplications and divisions seems
- // worth while.
- // Audio-video throttling. If the user has turned up audio quality
- // very high (in principle it could be any other stream, not just audio)
- // then we can receive cries for help via the graph manager. In this case
- // we put in a wait for some time after rendering each frame.
- int m_trThrottle;
- // The time taken to render (i.e. BitBlt) frames controls which component
- // needs to degrade. If the blt is expensive, the renderer degrades.
- // If the blt is cheap it's done anyway and the supplier degrades.
- int m_trRenderAvg; // Time frames are taking to blt
- int m_trRenderLast; // Time for last frame blt
- int m_tRenderStart; // Just before we started drawing (mSec)
- // derived from timeGetTime.
- // When frames are dropped we will play the next frame as early as we can.
- // If it was a false alarm and the machine is fast we slide gently back to
- // normal timing. To do this, we record the offset showing just how early
- // we really are. This will normally be negative meaning early or zero.
- int m_trEarliness;
- // Target provides slow long-term feedback to try to reduce the
- // average sync offset to zero. Whenever a frame is actually rendered
- // early we add a msec or two, whenever late we take off a few.
- // We add or take off 1/32 of the error time.
- // Eventually we should be hovering around zero. For a really bad case
- // where we were (say) 300mSec off, it might take 100 odd frames to
- // settle down. The rate of change of this is intended to be slower
- // than any other mechanism in Quartz, thereby avoiding hunting.
- int m_trTarget;
- // The proportion of time spent waiting for the right moment to blt
- // controls whether we bother to drop a frame or whether we reckon that
- // we're doing well enough that we can stand a one-frame glitch.
- int m_trWaitAvg; // Average of last few wait times
- // (actually we just average how early
- // we were). Negative here means LATE.
- // The average inter-frame time.
- // This is used to calculate the proportion of the time used by the
- // three operations (supplying us, waiting, rendering)
- int m_trFrameAvg; // Average inter-frame time
- int m_trDuration; // duration of last frame.
- #ifdef PERF
- // Performance logging identifiers
- int m_idTimeStamp; // MSR_id for frame time stamp
- int m_idEarliness; // MSR_id for earliness fudge
- int m_idTarget; // MSR_id for Target fudge
- int m_idWaitReal; // MSR_id for true wait time
- int m_idWait; // MSR_id for wait time recorded
- int m_idFrameAccuracy; // MSR_id for time frame is late (int)
- int m_idRenderAvg; // MSR_id for Render time recorded (int)
- int m_idSchLateTime; // MSR_id for lateness at scheduler
- int m_idQualityRate; // MSR_id for Quality rate requested
- int m_idQualityTime; // MSR_id for Quality time requested
- int m_idDecision; // MSR_id for decision code
- int m_idDuration; // MSR_id for duration of a frame
- int m_idThrottle; // MSR_id for audio-video throttling
- //int m_idDebug; // MSR_id for trace style debugging
- //int m_idSendQuality; // MSR_id for timing the notifications per se
- #endif // PERF
- REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame
- // with no earliness fudges etc.
- #ifdef PERF
- REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered
- // debug...
- int m_idFrameAvg;
- int m_idWaitAvg;
- #endif
- // PROPERTY PAGE
- // This has edit fields that show the user what's happening
- // These member variables hold these counts.
- int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER
- int m_cFramesDrawn; // Frames since streaming started seen BY THE
- // RENDERER (some may be dropped upstream)
- // Next two support average sync offset and standard deviation of sync offset.
- LONGLONG m_iTotAcc; // Sum of accuracies in mSec
- LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec)
- // Next two allow jitter calculation. Jitter is std deviation of frame time.
- REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times)
- LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec)
- LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec
- // To get performance statistics on frame rate, jitter etc, we need
- // to record the lateness and inter-frame time. What we actually need are the
- // data above (sum, sum of squares and number of entries for each) but the data
- // is generated just ahead of time and only later do we discover whether the
- // frame was actually drawn or not. So we have to hang on to the data
- int m_trLate; // hold onto frame lateness
- int m_trFrame; // hold onto inter-frame time
- int m_tStreamingStart; // if streaming then time streaming started
- // else time of last streaming session
- // used for property page statistics
- #ifdef PERF
- LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time
- #endif
- public:
- CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer
- __in_opt LPCTSTR pName, // Debug ONLY description
- __inout_opt LPUNKNOWN pUnk, // Aggregated owner object
- __inout HRESULT *phr); // General OLE return code
- ~CBaseVideoRenderer();
- // IQualityControl methods - Notify allows audio-video throttling
- STDMETHODIMP SetSink( IQualityControl * piqc);
- STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q);
- // These provide a full video quality management implementation
- void OnRenderStart(IMediaSample *pMediaSample);
- void OnRenderEnd(IMediaSample *pMediaSample);
- void OnWaitStart();
- void OnWaitEnd();
- HRESULT OnStartStreaming();
- HRESULT OnStopStreaming();
- void ThrottleWait();
- // Handle the statistics gathering for our quality management
- void PreparePerformanceData(int trLate, int trFrame);
- virtual void RecordFrameLateness(int trLate, int trFrame);
- virtual void OnDirectRender(IMediaSample *pMediaSample);
- virtual HRESULT ResetStreamingTimes();
- BOOL ScheduleSample(IMediaSample *pMediaSample);
- HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
- __inout REFERENCE_TIME *ptrStart,
- __inout REFERENCE_TIME *ptrEnd);
- virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream);
- STDMETHODIMP JoinFilterGraph(__inout_opt IFilterGraph * pGraph, __in_opt LPCWSTR pName);
- //
- // Do estimates for standard deviations for per-frame
- // statistics
- //
- // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
- // (m_cFramesDrawn - 2)
- // or 0 if m_cFramesDrawn <= 3
- //
- HRESULT GetStdDev(
- int nSamples,
- __out int *piResult,
- LONGLONG llSumSq,
- LONGLONG iTot
- );
- public:
- // IQualProp property page support
- STDMETHODIMP get_FramesDroppedInRenderer(__out int *cFramesDropped);
- STDMETHODIMP get_FramesDrawn(__out int *pcFramesDrawn);
- STDMETHODIMP get_AvgFrameRate(__out int *piAvgFrameRate);
- STDMETHODIMP get_Jitter(__out int *piJitter);
- STDMETHODIMP get_AvgSyncOffset(__out int *piAvg);
- STDMETHODIMP get_DevSyncOffset(__out int *piDev);
- // Implement an IUnknown interface and expose IQualProp
- DECLARE_IUNKNOWN
- STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv);
- };
- #endif // __RENBASE__
|