Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 1 | //------------------------------------------------------------------------------
|
| 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 |
|
| 16 | class CBaseRenderer;
|
| 17 | class CBaseVideoRenderer;
|
| 18 | class CRendererInputPin;
|
| 19 |
|
| 20 | // This is our input pin class that channels calls to the renderer
|
| 21 |
|
| 22 | class CRendererInputPin : public CBaseInputPin
|
| 23 | {
|
| 24 | protected:
|
| 25 |
|
| 26 | CBaseRenderer *m_pRenderer;
|
| 27 |
|
| 28 | public:
|
| 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 |
|
| 60 | class CBaseRenderer : public CBaseFilter
|
| 61 | {
|
| 62 | protected:
|
| 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 |
|
| 97 | public:
|
| 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 |
|
| 250 | class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
|
| 251 | public IQualProp, // Property page guff
|
| 252 | public IQualityControl // Allow throttling
|
| 253 | {
|
| 254 | protected:
|
| 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 |
|
| 407 | public:
|
| 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 | );
|
| 460 | public:
|
| 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 |
|