1 //------------------------------------------------------------------------------
4 // Desc: DirectShow base classes - defines a generic ActiveX base renderer
7 // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
14 // Forward class declarations
17 class CBaseVideoRenderer
;
18 class CRendererInputPin
;
20 // This is our input pin class that channels calls to the renderer
22 class CRendererInputPin
: public CBaseInputPin
26 CBaseRenderer
*m_pRenderer
;
30 CRendererInputPin(CBaseRenderer
*pRenderer
,
34 // Overriden from the base pin classes
36 HRESULT
BreakConnect();
37 HRESULT
CompleteConnect(IPin
*pReceivePin
);
38 HRESULT
SetMediaType(const CMediaType
*pmt
);
39 HRESULT
CheckMediaType(const CMediaType
*pmt
);
43 // Add rendering behaviour to interface functions
45 STDMETHODIMP
QueryId(LPWSTR
*Id
);
46 STDMETHODIMP
EndOfStream();
47 STDMETHODIMP
BeginFlush();
48 STDMETHODIMP
EndFlush();
49 STDMETHODIMP
Receive(IMediaSample
*pMediaSample
);
52 IMemAllocator
inline *Allocator() const
58 // Main renderer class that handles synchronisation and state changes
60 class CBaseRenderer
: public CBaseFilter
64 friend class CRendererInputPin
;
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
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.
99 CBaseRenderer(REFCLSID RenderClass
, // CLSID for this renderer
100 TCHAR
*pName
, // Debug ONLY description
101 LPUNKNOWN pUnk
, // Aggregated owner object
102 HRESULT
*phr
); // General OLE return code
106 // Overriden to say what interfaces we support and where
108 virtual HRESULT
GetMediaPositionInterface(REFIID riid
,void **ppv
);
109 STDMETHODIMP
NonDelegatingQueryInterface(REFIID
, void **);
111 virtual HRESULT
SourceThreadCanWait(BOOL bCanWait
);
114 // Debug only dump of the renderer state
115 void DisplayRendererState();
117 virtual HRESULT
WaitForRenderTime();
118 virtual HRESULT
CompleteStateChange(FILTER_STATE OldState
);
120 // Return internal information about this filter
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
; };
129 // Permit access to the transition state
131 void Ready() { m_evComplete
.Set(); };
132 void NotReady() { m_evComplete
.Reset(); };
133 BOOL
CheckReady() { return m_evComplete
.Check(); };
135 virtual int GetPinCount();
136 virtual CBasePin
*GetPin(int n
);
137 FILTER_STATE
GetRealState();
139 void SendNotifyWindow(IPin
*pPin
,HWND hwnd
);
140 BOOL
OnDisplayChange();
141 void SetRepaintStatus(BOOL bRepaint
);
143 // Override the filter and pin interface functions
146 STDMETHODIMP
Pause();
147 STDMETHODIMP
Run(REFERENCE_TIME StartTime
);
148 STDMETHODIMP
GetState(DWORD dwMSecs
,FILTER_STATE
*State
);
149 STDMETHODIMP
FindPin(LPCWSTR Id
, IPin
**ppPin
);
151 // These are available for a quality management implementation
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() { };
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)
169 // Quality management implementation for scheduling rendering
171 virtual BOOL
ScheduleSample(IMediaSample
*pMediaSample
);
172 virtual HRESULT
GetSampleTimes(IMediaSample
*pMediaSample
,
173 REFERENCE_TIME
*pStartTime
,
174 REFERENCE_TIME
*pEndTime
);
176 virtual HRESULT
ShouldDrawSampleNow(IMediaSample
*pMediaSample
,
177 REFERENCE_TIME
*ptrStart
,
178 REFERENCE_TIME
*ptrEnd
);
180 // Lots of end of stream complexities
182 void TimerCallback();
183 void ResetEndOfStreamTimer();
184 HRESULT
NotifyEndOfStream();
185 virtual HRESULT
SendEndOfStream();
186 virtual HRESULT
ResetEndOfStream();
187 virtual HRESULT
EndOfStream();
189 // Rendering is based around the clock
191 void SignalTimerFired();
192 virtual HRESULT
CancelNotification();
193 virtual HRESULT
ClearPendingSample();
195 // Called when the filter changes state
197 virtual HRESULT
Active();
198 virtual HRESULT
Inactive();
199 virtual HRESULT
StartStreaming();
200 virtual HRESULT
StopStreaming();
201 virtual HRESULT
BeginFlush();
202 virtual HRESULT
EndFlush();
204 // Deal with connections and type changes
206 virtual HRESULT
BreakConnect();
207 virtual HRESULT
SetMediaType(const CMediaType
*pmt
);
208 virtual HRESULT
CompleteConnect(IPin
*pReceivePin
);
210 // These look after the handling of data samples
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
);
218 // Derived classes MUST override these
219 virtual HRESULT
DoRenderSample(IMediaSample
*pMediaSample
) PURE
;
220 virtual HRESULT
CheckMediaType(const CMediaType
*) PURE
;
223 void WaitForReceiveToComplete();
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
244 // the number of frames that the sliding averages are averaged over.
245 // the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
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!
250 class CBaseVideoRenderer
: public CBaseRenderer
, // Base renderer class
251 public IQualProp
, // Property page guff
252 public IQualityControl
// Allow throttling
257 // tFoo is the time Foo in mSec (beware m_tStart from filter.h)
258 // trBar is the time Bar by the reference clock
260 //******************************************************************
261 // State variables to control synchronisation
262 //******************************************************************
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
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.
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.
278 BOOL m_bDrawLateFrames
; // Don't drop any frames (debug and I'm
279 // not keen on people using it!)
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.
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.
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
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.
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.
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.
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.
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.
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.
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
365 REFERENCE_TIME m_trRememberStampForPerf
; // original time stamp of frame
366 // with no earliness fudges etc.
368 REFERENCE_TIME m_trRememberFrameForPerf
; // time when previous frame rendered
376 // This has edit fields that show the user what's happening
377 // These member variables hold these counts.
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)
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)
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
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
400 int m_tStreamingStart
; // if streaming then time streaming started
401 // else time of last streaming session
402 // used for property page statistics
404 LONGLONG m_llTimeOffset
; // timeGetTime()*10000+m_llTimeOffset==ref time
410 CBaseVideoRenderer(REFCLSID RenderClass
, // CLSID for this renderer
411 TCHAR
*pName
, // Debug ONLY description
412 LPUNKNOWN pUnk
, // Aggregated owner object
413 HRESULT
*phr
); // General OLE return code
415 ~CBaseVideoRenderer();
417 // IQualityControl methods - Notify allows audio-video throttling
419 STDMETHODIMP
SetSink( IQualityControl
* piqc
);
420 STDMETHODIMP
Notify( IBaseFilter
* pSelf
, Quality q
);
422 // These provide a full video quality management implementation
424 void OnRenderStart(IMediaSample
*pMediaSample
);
425 void OnRenderEnd(IMediaSample
*pMediaSample
);
428 HRESULT
OnStartStreaming();
429 HRESULT
OnStopStreaming();
432 // Handle the statistics gathering for our quality management
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 REFERENCE_TIME
*ptrStart
,
441 REFERENCE_TIME
*ptrEnd
);
443 virtual HRESULT
SendQuality(REFERENCE_TIME trLate
, REFERENCE_TIME trRealStream
);
444 STDMETHODIMP
JoinFilterGraph(IFilterGraph
* pGraph
, LPCWSTR pName
);
447 // Do estimates for standard deviations for per-frame
450 // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
451 // (m_cFramesDrawn - 2)
452 // or 0 if m_cFramesDrawn <= 3
462 // IQualProp property page support
464 STDMETHODIMP
get_FramesDroppedInRenderer(int *cFramesDropped
);
465 STDMETHODIMP
get_FramesDrawn(int *pcFramesDrawn
);
466 STDMETHODIMP
get_AvgFrameRate(int *piAvgFrameRate
);
467 STDMETHODIMP
get_Jitter(int *piJitter
);
468 STDMETHODIMP
get_AvgSyncOffset(int *piAvg
);
469 STDMETHODIMP
get_DevSyncOffset(int *piDev
);
471 // Implement an IUnknown interface and expose IQualProp
474 STDMETHODIMP
NonDelegatingQueryInterface(REFIID riid
,VOID
**ppv
);
477 #endif // __RENBASE__