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