My Project
renbase.h
1 //------------------------------------------------------------------------------
2 // File: RenBase.h
3 //
4 // Desc: DirectShow base classes - defines a generic ActiveX base renderer
5 // class.
6 //
7 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
9 
10 #pragma once
11 
12 #ifndef __RENBASE__
13 #define __RENBASE__
14 
15 // Forward class declarations
16 
17 class CBaseRenderer;
18 class CBaseVideoRenderer;
19 class CRendererInputPin;
20 
21 // This is our input pin class that channels calls to the renderer
22 
24 {
25 protected:
26 
27  CBaseRenderer *m_pRenderer;
28 
29 public:
30 
32  HRESULT *phr,
33  LPCWSTR Name);
34 
35  // Overriden from the base pin classes
36 
37  HRESULT BreakConnect();
38  HRESULT CompleteConnect(IPin *pReceivePin);
39  HRESULT SetMediaType(const CMediaType *pmt);
40  HRESULT CheckMediaType(const CMediaType *pmt);
41  HRESULT Active();
42  HRESULT Inactive();
43 
44  // Add rendering behaviour to interface functions
45 
46  STDMETHODIMP QueryId(LPWSTR *Id);
47  STDMETHODIMP EndOfStream();
48  STDMETHODIMP BeginFlush();
49  STDMETHODIMP EndFlush();
50  STDMETHODIMP Receive(IMediaSample *pMediaSample);
51 
52  // Helper
53  IMemAllocator inline *Allocator() const
54  {
55  return m_pAllocator;
56  }
57 };
58 
59 // Main renderer class that handles synchronisation and state changes
60 
61 class CBaseRenderer : public CBaseFilter
62 {
63 protected:
64 
65  friend class CRendererInputPin;
66 
67  friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
68  UINT uMsg, // Not currently used
69  DWORD_PTR dwUser, // User information
70  DWORD_PTR dw1, // Windows reserved
71  DWORD_PTR dw2); // Is also reserved
72 
73  CRendererPosPassThru *m_pPosition; // Media seeking pass by object
74  CAMEvent m_RenderEvent; // Used to signal timer events
75  CAMEvent m_ThreadSignal; // Signalled to release worker thread
76  CAMEvent m_evComplete; // Signalled when state complete
77  BOOL m_bAbort; // Stop us from rendering more data
78  BOOL m_bStreaming; // Are we currently streaming
79  DWORD_PTR m_dwAdvise; // Timer advise cookie
80  IMediaSample *m_pMediaSample; // Current image media sample
81  BOOL m_bEOS; // Any more samples in the stream
82  BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE
83  CRendererInputPin *m_pInputPin; // Our renderer input pin object
84  CCritSec m_InterfaceLock; // Critical section for interfaces
85  CCritSec m_RendererLock; // Controls access to internals
86  IQualityControl * m_pQSink; // QualityControl sink
87  BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT
88  // Avoid some deadlocks by tracking filter during stop
89  volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive
90  // And actually processing the sample
91  REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE
92  UINT m_EndOfStreamTimer; // Used to signal end of stream
93  CCritSec m_ObjectCreationLock; // This lock protects the creation and
94  // of m_pPosition and m_pInputPin. It
95  // ensures that two threads cannot create
96  // either object simultaneously.
97 
98 public:
99 
100  CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
101  TCHAR *pName, // Debug ONLY description
102  LPUNKNOWN pUnk, // Aggregated owner object
103  HRESULT *phr); // General OLE return code
104 
105  ~CBaseRenderer();
106 
107  // Overriden to say what interfaces we support and where
108 
109  virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv);
110  STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
111 
112  virtual HRESULT SourceThreadCanWait(BOOL bCanWait);
113 
114 #ifdef DEBUG
115  // Debug only dump of the renderer state
116  void DisplayRendererState();
117 #endif
118  virtual HRESULT WaitForRenderTime();
119  virtual HRESULT CompleteStateChange(FILTER_STATE OldState);
120 
121  // Return internal information about this filter
122 
123  BOOL IsEndOfStream() { return m_bEOS; };
124  BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; };
125  BOOL IsStreaming() { return m_bStreaming; };
126  void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; };
127  virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { };
128  CAMEvent *GetRenderEvent() { return &m_RenderEvent; };
129 
130  // Permit access to the transition state
131 
132  void Ready() { m_evComplete.Set(); };
133  void NotReady() { m_evComplete.Reset(); };
134  BOOL CheckReady() { return m_evComplete.Check(); };
135 
136  virtual int GetPinCount();
137  virtual CBasePin *GetPin(int n);
138  FILTER_STATE GetRealState();
139  void SendRepaint();
140  void SendNotifyWindow(IPin *pPin,HWND hwnd);
141  BOOL OnDisplayChange();
142  void SetRepaintStatus(BOOL bRepaint);
143 
144  // Override the filter and pin interface functions
145 
146  STDMETHODIMP Stop();
147  STDMETHODIMP Pause();
148  STDMETHODIMP Run(REFERENCE_TIME StartTime);
149  STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State);
150  STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
151 
152  // These are available for a quality management implementation
153 
154  virtual void OnRenderStart(IMediaSample *pMediaSample);
155  virtual void OnRenderEnd(IMediaSample *pMediaSample);
156  virtual HRESULT OnStartStreaming() { return NOERROR; };
157  virtual HRESULT OnStopStreaming() { return NOERROR; };
158  virtual void OnWaitStart() { };
159  virtual void OnWaitEnd() { };
160  virtual void PrepareRender() { };
161 
162 #ifdef PERF
163  REFERENCE_TIME m_trRenderStart; // Just before we started drawing
164  // Set in OnRenderStart, Used in OnRenderEnd
165  int m_idBaseStamp; // MSR_id for frame time stamp
166  int m_idBaseRenderTime; // MSR_id for true wait time
167  int m_idBaseAccuracy; // MSR_id for time frame is late (int)
168 #endif
169 
170  // Quality management implementation for scheduling rendering
171 
172  virtual BOOL ScheduleSample(IMediaSample *pMediaSample);
173  virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample,
174  REFERENCE_TIME *pStartTime,
175  REFERENCE_TIME *pEndTime);
176 
177  virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
178  REFERENCE_TIME *ptrStart,
179  REFERENCE_TIME *ptrEnd);
180 
181  // Lots of end of stream complexities
182 
183  void TimerCallback();
184  void ResetEndOfStreamTimer();
185  HRESULT NotifyEndOfStream();
186  virtual HRESULT SendEndOfStream();
187  virtual HRESULT ResetEndOfStream();
188  virtual HRESULT EndOfStream();
189 
190  // Rendering is based around the clock
191 
192  void SignalTimerFired();
193  virtual HRESULT CancelNotification();
194  virtual HRESULT ClearPendingSample();
195 
196  // Called when the filter changes state
197 
198  virtual HRESULT Active();
199  virtual HRESULT Inactive();
200  virtual HRESULT StartStreaming();
201  virtual HRESULT StopStreaming();
202  virtual HRESULT BeginFlush();
203  virtual HRESULT EndFlush();
204 
205  // Deal with connections and type changes
206 
207  virtual HRESULT BreakConnect();
208  virtual HRESULT SetMediaType(const CMediaType *pmt);
209  virtual HRESULT CompleteConnect(IPin *pReceivePin);
210 
211  // These look after the handling of data samples
212 
213  virtual HRESULT PrepareReceive(IMediaSample *pMediaSample);
214  virtual HRESULT Receive(IMediaSample *pMediaSample);
215  virtual BOOL HaveCurrentSample();
216  virtual IMediaSample *GetCurrentSample();
217  virtual HRESULT Render(IMediaSample *pMediaSample);
218 
219  // Derived classes MUST override these
220  virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
221  virtual HRESULT CheckMediaType(const CMediaType *) PURE;
222 
223  // Helper
224  void WaitForReceiveToComplete();
225 };
226 
227 
228 // CBaseVideoRenderer is a renderer class (see its ancestor class) and
229 // it handles scheduling of media samples so that they are drawn at the
230 // correct time by the reference clock. It implements a degradation
231 // strategy. Possible degradation modes are:
232 // Drop frames here (only useful if the drawing takes significant time)
233 // Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
234 // Signal supplier to change the frame rate - i.e. ongoing skipping.
235 // Or any combination of the above.
236 // In order to determine what's useful to try we need to know what's going
237 // on. This is done by timing various operations (including the supplier).
238 // This timing is done by using timeGetTime as it is accurate enough and
239 // usually cheaper than calling the reference clock. It also tells the
240 // truth if there is an audio break and the reference clock stops.
241 // We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
242 // which the rest of the renderer calls at significant moments. These do
243 // the timing.
244 
245 // the number of frames that the sliding averages are averaged over.
246 // the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
247 #define AVGPERIOD 4
248 #define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
249 // Spot the bug in this macro - I can't. but it doesn't work!
250 
251 class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
252  public IQualProp, // Property page guff
253  public IQualityControl // Allow throttling
254 {
255 protected:
256 
257  // Hungarian:
258  // tFoo is the time Foo in mSec (beware m_tStart from filter.h)
259  // trBar is the time Bar by the reference clock
260 
261  //******************************************************************
262  // State variables to control synchronisation
263  //******************************************************************
264 
265  // Control of sending Quality messages. We need to know whether
266  // we are in trouble (e.g. frames being dropped) and where the time
267  // is being spent.
268 
269  // When we drop a frame we play the next one early.
270  // The frame after that is likely to wait before drawing and counting this
271  // wait as spare time is unfair, so we count it as a zero wait.
272  // We therefore need to know whether we are playing frames early or not.
273 
274  int m_nNormal; // The number of consecutive frames
275  // drawn at their normal time (not early)
276  // -1 means we just dropped a frame.
277 
278 #ifdef PERF
279  BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm
280  // not keen on people using it!)
281 #endif
282 
283  BOOL m_bSupplierHandlingQuality;// The response to Quality messages says
284  // our supplier is handling things.
285  // We will allow things to go extra late
286  // before dropping frames. We will play
287  // very early after he has dropped one.
288 
289  // Control of scheduling, frame dropping etc.
290  // We need to know where the time is being spent so as to tell whether
291  // we should be taking action here, signalling supplier or what.
292  // The variables are initialised to a mode of NOT dropping frames.
293  // They will tell the truth after a few frames.
294  // We typically record a start time for an event, later we get the time
295  // again and subtract to get the elapsed time, and we average this over
296  // a few frames. The average is used to tell what mode we are in.
297 
298  // Although these are reference times (64 bit) they are all DIFFERENCES
299  // between times which are small. An int will go up to 214 secs before
300  // overflow. Avoiding 64 bit multiplications and divisions seems
301  // worth while.
302 
303 
304 
305  // Audio-video throttling. If the user has turned up audio quality
306  // very high (in principle it could be any other stream, not just audio)
307  // then we can receive cries for help via the graph manager. In this case
308  // we put in a wait for some time after rendering each frame.
309  int m_trThrottle;
310 
311  // The time taken to render (i.e. BitBlt) frames controls which component
312  // needs to degrade. If the blt is expensive, the renderer degrades.
313  // If the blt is cheap it's done anyway and the supplier degrades.
314  int m_trRenderAvg; // Time frames are taking to blt
315  int m_trRenderLast; // Time for last frame blt
316  int m_tRenderStart; // Just before we started drawing (mSec)
317  // derived from timeGetTime.
318 
319  // When frames are dropped we will play the next frame as early as we can.
320  // If it was a false alarm and the machine is fast we slide gently back to
321  // normal timing. To do this, we record the offset showing just how early
322  // we really are. This will normally be negative meaning early or zero.
323  int m_trEarliness;
324 
325  // Target provides slow long-term feedback to try to reduce the
326  // average sync offset to zero. Whenever a frame is actually rendered
327  // early we add a msec or two, whenever late we take off a few.
328  // We add or take off 1/32 of the error time.
329  // Eventually we should be hovering around zero. For a really bad case
330  // where we were (say) 300mSec off, it might take 100 odd frames to
331  // settle down. The rate of change of this is intended to be slower
332  // than any other mechanism in Quartz, thereby avoiding hunting.
333  int m_trTarget;
334 
335  // The proportion of time spent waiting for the right moment to blt
336  // controls whether we bother to drop a frame or whether we reckon that
337  // we're doing well enough that we can stand a one-frame glitch.
338  int m_trWaitAvg; // Average of last few wait times
339  // (actually we just average how early
340  // we were). Negative here means LATE.
341 
342  // The average inter-frame time.
343  // This is used to calculate the proportion of the time used by the
344  // three operations (supplying us, waiting, rendering)
345  int m_trFrameAvg; // Average inter-frame time
346  int m_trDuration; // duration of last frame.
347 
348 #ifdef PERF
349  // Performance logging identifiers
350  int m_idTimeStamp; // MSR_id for frame time stamp
351  int m_idEarliness; // MSR_id for earliness fudge
352  int m_idTarget; // MSR_id for Target fudge
353  int m_idWaitReal; // MSR_id for true wait time
354  int m_idWait; // MSR_id for wait time recorded
355  int m_idFrameAccuracy; // MSR_id for time frame is late (int)
356  int m_idRenderAvg; // MSR_id for Render time recorded (int)
357  int m_idSchLateTime; // MSR_id for lateness at scheduler
358  int m_idQualityRate; // MSR_id for Quality rate requested
359  int m_idQualityTime; // MSR_id for Quality time requested
360  int m_idDecision; // MSR_id for decision code
361  int m_idDuration; // MSR_id for duration of a frame
362  int m_idThrottle; // MSR_id for audio-video throttling
363  //int m_idDebug; // MSR_id for trace style debugging
364  //int m_idSendQuality; // MSR_id for timing the notifications per se
365 #endif // PERF
366  REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame
367  // with no earliness fudges etc.
368 #ifdef PERF
369  REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered
370 
371  // debug...
372  int m_idFrameAvg;
373  int m_idWaitAvg;
374 #endif
375 
376  // PROPERTY PAGE
377  // This has edit fields that show the user what's happening
378  // These member variables hold these counts.
379 
380  int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER
381  int m_cFramesDrawn; // Frames since streaming started seen BY THE
382  // RENDERER (some may be dropped upstream)
383 
384  // Next two support average sync offset and standard deviation of sync offset.
385  LONGLONG m_iTotAcc; // Sum of accuracies in mSec
386  LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec)
387 
388  // Next two allow jitter calculation. Jitter is std deviation of frame time.
389  REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times)
390  LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec)
391  LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec
392 
393  // To get performance statistics on frame rate, jitter etc, we need
394  // to record the lateness and inter-frame time. What we actually need are the
395  // data above (sum, sum of squares and number of entries for each) but the data
396  // is generated just ahead of time and only later do we discover whether the
397  // frame was actually drawn or not. So we have to hang on to the data
398  int m_trLate; // hold onto frame lateness
399  int m_trFrame; // hold onto inter-frame time
400 
401  int m_tStreamingStart; // if streaming then time streaming started
402  // else time of last streaming session
403  // used for property page statistics
404 #ifdef PERF
405  LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time
406 #endif
407 
408 public:
409 
410 
411  CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer
412  TCHAR *pName, // Debug ONLY description
413  LPUNKNOWN pUnk, // Aggregated owner object
414  HRESULT *phr); // General OLE return code
415 
417 
418  // IQualityControl methods - Notify allows audio-video throttling
419 
420  STDMETHODIMP SetSink( IQualityControl * piqc);
421  STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q);
422 
423  // These provide a full video quality management implementation
424 
425  void OnRenderStart(IMediaSample *pMediaSample);
426  void OnRenderEnd(IMediaSample *pMediaSample);
427  void OnWaitStart();
428  void OnWaitEnd();
429  HRESULT OnStartStreaming();
430  HRESULT OnStopStreaming();
431  void ThrottleWait();
432 
433  // Handle the statistics gathering for our quality management
434 
435  void PreparePerformanceData(int trLate, int trFrame);
436  virtual void RecordFrameLateness(int trLate, int trFrame);
437  virtual void OnDirectRender(IMediaSample *pMediaSample);
438  virtual HRESULT ResetStreamingTimes();
439  BOOL ScheduleSample(IMediaSample *pMediaSample);
440  HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
441  REFERENCE_TIME *ptrStart,
442  REFERENCE_TIME *ptrEnd);
443 
444  virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream);
445  STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName);
446 
447  //
448  // Do estimates for standard deviations for per-frame
449  // statistics
450  //
451  // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
452  // (m_cFramesDrawn - 2)
453  // or 0 if m_cFramesDrawn <= 3
454  //
455  HRESULT GetStdDev(
456  int nSamples,
457  int *piResult,
458  LONGLONG llSumSq,
459  LONGLONG iTot
460  );
461 public:
462 
463  // IQualProp property page support
464 
465  STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped);
466  STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn);
467  STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate);
468  STDMETHODIMP get_Jitter(int *piJitter);
469  STDMETHODIMP get_AvgSyncOffset(int *piAvg);
470  STDMETHODIMP get_DevSyncOffset(int *piDev);
471 
472  // Implement an IUnknown interface and expose IQualProp
473 
474  DECLARE_IUNKNOWN
475  STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv);
476 };
477 
478 #endif // __RENBASE__
479 
Definition: amfilter.h:331
Definition: amfilter.h:149
Definition: mtype.h:19
Definition: ctlutil.h:366
Definition: wxutil.h:19
Definition: renbase.h:251
Definition: renbase.h:23
Definition: wxutil.h:109
Definition: renbase.h:61
Definition: amfilter.h:820