renbase.cpp 97 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862
  1. //------------------------------------------------------------------------------
  2. // File: RenBase.cpp
  3. //
  4. // Desc: DirectShow base classes.
  5. //
  6. // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
  7. //------------------------------------------------------------------------------
  8. #include <pjmedia-videodev/config.h>
  9. #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
  10. #include <streams.h> // DirectShow base class definitions
  11. #include <mmsystem.h> // Needed for definition of timeGetTime
  12. #include <limits.h> // Standard data type limit definitions
  13. #include <measure.h> // Used for time critical log functions
  14. #pragma warning(disable:4355)
  15. // Helper function for clamping time differences
  16. int inline TimeDiff(REFERENCE_TIME rt)
  17. {
  18. if (rt < - (50 * UNITS)) {
  19. return -(50 * UNITS);
  20. } else
  21. if (rt > 50 * UNITS) {
  22. return 50 * UNITS;
  23. } else return (int)rt;
  24. }
  25. // Implements the CBaseRenderer class
  26. CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
  27. __in_opt LPCTSTR pName, // Debug ONLY description
  28. __inout_opt LPUNKNOWN pUnk, // Aggregated owner object
  29. __inout HRESULT *phr) : // General OLE return code
  30. CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass),
  31. m_evComplete(TRUE, phr),
  32. m_RenderEvent(FALSE, phr),
  33. m_bAbort(FALSE),
  34. m_pPosition(NULL),
  35. m_ThreadSignal(TRUE, phr),
  36. m_bStreaming(FALSE),
  37. m_bEOS(FALSE),
  38. m_bEOSDelivered(FALSE),
  39. m_pMediaSample(NULL),
  40. m_dwAdvise(0),
  41. m_pQSink(NULL),
  42. m_pInputPin(NULL),
  43. m_bRepaintStatus(TRUE),
  44. m_SignalTime(0),
  45. m_bInReceive(FALSE),
  46. m_EndOfStreamTimer(0)
  47. {
  48. if (SUCCEEDED(*phr)) {
  49. Ready();
  50. #ifdef PERF
  51. m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp"));
  52. m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)"));
  53. m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)"));
  54. #endif
  55. }
  56. }
  57. // Delete the dynamically allocated IMediaPosition and IMediaSeeking helper
  58. // object. The object is created when somebody queries us. These are standard
  59. // control interfaces for seeking and setting start/stop positions and rates.
  60. // We will probably also have made an input pin based on CRendererInputPin
  61. // that has to be deleted, it's created when an enumerator calls our GetPin
  62. CBaseRenderer::~CBaseRenderer()
  63. {
  64. ASSERT(m_bStreaming == FALSE);
  65. ASSERT(m_EndOfStreamTimer == 0);
  66. StopStreaming();
  67. ClearPendingSample();
  68. // Delete any IMediaPosition implementation
  69. if (m_pPosition) {
  70. delete m_pPosition;
  71. m_pPosition = NULL;
  72. }
  73. // Delete any input pin created
  74. if (m_pInputPin) {
  75. delete m_pInputPin;
  76. m_pInputPin = NULL;
  77. }
  78. // Release any Quality sink
  79. ASSERT(m_pQSink == NULL);
  80. }
  81. // This returns the IMediaPosition and IMediaSeeking interfaces
  82. HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid, __deref_out void **ppv)
  83. {
  84. CAutoLock cObjectCreationLock(&m_ObjectCreationLock);
  85. if (m_pPosition) {
  86. return m_pPosition->NonDelegatingQueryInterface(riid,ppv);
  87. }
  88. CBasePin *pPin = GetPin(0);
  89. if (NULL == pPin) {
  90. return E_OUTOFMEMORY;
  91. }
  92. HRESULT hr = NOERROR;
  93. // Create implementation of this dynamically since sometimes we may
  94. // never try and do a seek. The helper object implements a position
  95. // control interface (IMediaPosition) which in fact simply takes the
  96. // calls normally from the filter graph and passes them upstream
  97. m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"),
  98. CBaseFilter::GetOwner(),
  99. (HRESULT *) &hr,
  100. pPin);
  101. if (m_pPosition == NULL) {
  102. return E_OUTOFMEMORY;
  103. }
  104. if (FAILED(hr)) {
  105. delete m_pPosition;
  106. m_pPosition = NULL;
  107. return E_NOINTERFACE;
  108. }
  109. return GetMediaPositionInterface(riid,ppv);
  110. }
  111. // Overriden to say what interfaces we support and where
  112. STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
  113. {
  114. // Do we have this interface
  115. if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
  116. return GetMediaPositionInterface(riid,ppv);
  117. } else {
  118. return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
  119. }
  120. }
  121. // This is called whenever we change states, we have a manual reset event that
  122. // is signalled whenever we don't won't the source filter thread to wait in us
  123. // (such as in a stopped state) and likewise is not signalled whenever it can
  124. // wait (during paused and running) this function sets or resets the thread
  125. // event. The event is used to stop source filter threads waiting in Receive
  126. HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait)
  127. {
  128. if (bCanWait == TRUE) {
  129. m_ThreadSignal.Reset();
  130. } else {
  131. m_ThreadSignal.Set();
  132. }
  133. return NOERROR;
  134. }
  135. #ifdef DEBUG
  136. // Dump the current renderer state to the debug terminal. The hardest part of
  137. // the renderer is the window where we unlock everything to wait for a clock
  138. // to signal it is time to draw or for the application to cancel everything
  139. // by stopping the filter. If we get things wrong we can leave the thread in
  140. // WaitForRenderTime with no way for it to ever get out and we will deadlock
  141. void CBaseRenderer::DisplayRendererState()
  142. {
  143. DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime")));
  144. // No way should this be signalled at this point
  145. BOOL bSignalled = m_ThreadSignal.Check();
  146. DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled));
  147. // Now output the current renderer state variables
  148. DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State));
  149. DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort));
  150. DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming));
  151. DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise));
  152. DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample));
  153. DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS));
  154. DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered));
  155. DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus));
  156. // Output the delayed end of stream timer information
  157. DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer));
  158. DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime)));
  159. // Should never timeout during a flushing state
  160. BOOL bFlushing = m_pInputPin->IsFlushing();
  161. DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing));
  162. // Display the time we were told to start at
  163. DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time)));
  164. // Have we got a reference clock
  165. if (m_pClock == NULL) return;
  166. // Get the current time from the wall clock
  167. CRefTime CurrentTime,StartTime,EndTime;
  168. m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime);
  169. CRefTime Offset = CurrentTime - m_tStart;
  170. // Display the current time from the clock
  171. DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time)));
  172. DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs()));
  173. // Do we have a sample ready to render
  174. if (m_pMediaSample == NULL) return;
  175. m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime);
  176. DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"),
  177. StartTime.Millisecs(),EndTime.Millisecs()));
  178. // Calculate how long it is until it is due for rendering
  179. CRefTime Wait = (m_tStart + StartTime) - CurrentTime;
  180. DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs()));
  181. }
  182. #endif
  183. // Wait until the clock sets the timer event or we're otherwise signalled. We
  184. // set an arbitrary timeout for this wait and if it fires then we display the
  185. // current renderer state on the debugger. It will often fire if the filter's
  186. // left paused in an application however it may also fire during stress tests
  187. // if the synchronisation with application seeks and state changes is faulty
  188. #define RENDER_TIMEOUT 10000
  189. HRESULT CBaseRenderer::WaitForRenderTime()
  190. {
  191. HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent };
  192. DWORD Result = WAIT_TIMEOUT;
  193. // Wait for either the time to arrive or for us to be stopped
  194. OnWaitStart();
  195. while (Result == WAIT_TIMEOUT) {
  196. Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT);
  197. #ifdef DEBUG
  198. if (Result == WAIT_TIMEOUT) DisplayRendererState();
  199. #endif
  200. }
  201. OnWaitEnd();
  202. // We may have been awoken without the timer firing
  203. if (Result == WAIT_OBJECT_0) {
  204. return VFW_E_STATE_CHANGED;
  205. }
  206. SignalTimerFired();
  207. return NOERROR;
  208. }
  209. // Poll waiting for Receive to complete. This really matters when
  210. // Receive may set the palette and cause window messages
  211. // The problem is that if we don't really wait for a renderer to
  212. // stop processing we can deadlock waiting for a transform which
  213. // is calling the renderer's Receive() method because the transform's
  214. // Stop method doesn't know to process window messages to unblock
  215. // the renderer's Receive processing
  216. void CBaseRenderer::WaitForReceiveToComplete()
  217. {
  218. for (;;) {
  219. if (!m_bInReceive) {
  220. break;
  221. }
  222. MSG msg;
  223. // Receive all interthread snedmessages
  224. PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE);
  225. Sleep(1);
  226. }
  227. // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call
  228. // above just cleared the changebit which will cause some messaging
  229. // calls to block (waitMessage, MsgWaitFor...) now.
  230. // Post a dummy message to set the QS_POSTMESSAGE bit again
  231. if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) {
  232. // Send dummy message
  233. PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
  234. }
  235. }
  236. // A filter can have four discrete states, namely Stopped, Running, Paused,
  237. // Intermediate. We are in an intermediate state if we are currently trying
  238. // to pause but haven't yet got the first sample (or if we have been flushed
  239. // in paused state and therefore still have to wait for a sample to arrive)
  240. // This class contains an event called m_evComplete which is signalled when
  241. // the current state is completed and is not signalled when we are waiting to
  242. // complete the last state transition. As mentioned above the only time we
  243. // use this at the moment is when we wait for a media sample in paused state
  244. // If while we are waiting we receive an end of stream notification from the
  245. // source filter then we know no data is imminent so we can reset the event
  246. // This means that when we transition to paused the source filter must call
  247. // end of stream on us or send us an image otherwise we'll hang indefinately
  248. // Simple internal way of getting the real state
  249. FILTER_STATE CBaseRenderer::GetRealState() {
  250. return m_State;
  251. }
  252. // The renderer doesn't complete the full transition to paused states until
  253. // it has got one media sample to render. If you ask it for its state while
  254. // it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE
  255. STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State)
  256. {
  257. CheckPointer(State,E_POINTER);
  258. if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) {
  259. *State = m_State;
  260. return VFW_S_STATE_INTERMEDIATE;
  261. }
  262. *State = m_State;
  263. return NOERROR;
  264. }
  265. // If we're pausing and we have no samples we don't complete the transition
  266. // to State_Paused and we return S_FALSE. However if the m_bAbort flag has
  267. // been set then all samples are rejected so there is no point waiting for
  268. // one. If we do have a sample then return NOERROR. We will only ever return
  269. // VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample
  270. // (calling GetState after either being stopped or Run will NOT return this)
  271. HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState)
  272. {
  273. // Allow us to be paused when disconnected
  274. if (m_pInputPin->IsConnected() == FALSE) {
  275. Ready();
  276. return S_OK;
  277. }
  278. // Have we run off the end of stream
  279. if (IsEndOfStream() == TRUE) {
  280. Ready();
  281. return S_OK;
  282. }
  283. // Make sure we get fresh data after being stopped
  284. if (HaveCurrentSample() == TRUE) {
  285. if (OldState != State_Stopped) {
  286. Ready();
  287. return S_OK;
  288. }
  289. }
  290. NotReady();
  291. return S_FALSE;
  292. }
  293. // When we stop the filter the things we do are:-
  294. // Decommit the allocator being used in the connection
  295. // Release the source filter if it's waiting in Receive
  296. // Cancel any advise link we set up with the clock
  297. // Any end of stream signalled is now obsolete so reset
  298. // Allow us to be stopped when we are not connected
  299. STDMETHODIMP CBaseRenderer::Stop()
  300. {
  301. CAutoLock cRendererLock(&m_InterfaceLock);
  302. // Make sure there really is a state change
  303. if (m_State == State_Stopped) {
  304. return NOERROR;
  305. }
  306. // Is our input pin connected
  307. if (m_pInputPin->IsConnected() == FALSE) {
  308. NOTE("Input pin is not connected");
  309. m_State = State_Stopped;
  310. return NOERROR;
  311. }
  312. CBaseFilter::Stop();
  313. // If we are going into a stopped state then we must decommit whatever
  314. // allocator we are using it so that any source filter waiting in the
  315. // GetBuffer can be released and unlock themselves for a state change
  316. if (m_pInputPin->Allocator()) {
  317. m_pInputPin->Allocator()->Decommit();
  318. }
  319. // Cancel any scheduled rendering
  320. SetRepaintStatus(TRUE);
  321. StopStreaming();
  322. SourceThreadCanWait(FALSE);
  323. ResetEndOfStream();
  324. CancelNotification();
  325. // There should be no outstanding clock advise
  326. ASSERT(CancelNotification() == S_FALSE);
  327. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
  328. ASSERT(m_EndOfStreamTimer == 0);
  329. Ready();
  330. WaitForReceiveToComplete();
  331. m_bAbort = FALSE;
  332. return NOERROR;
  333. }
  334. // When we pause the filter the things we do are:-
  335. // Commit the allocator being used in the connection
  336. // Allow a source filter thread to wait in Receive
  337. // Cancel any clock advise link (we may be running)
  338. // Possibly complete the state change if we have data
  339. // Allow us to be paused when we are not connected
  340. STDMETHODIMP CBaseRenderer::Pause()
  341. {
  342. CAutoLock cRendererLock(&m_InterfaceLock);
  343. FILTER_STATE OldState = m_State;
  344. ASSERT(m_pInputPin->IsFlushing() == FALSE);
  345. // Make sure there really is a state change
  346. if (m_State == State_Paused) {
  347. return CompleteStateChange(State_Paused);
  348. }
  349. // Has our input pin been connected
  350. if (m_pInputPin->IsConnected() == FALSE) {
  351. NOTE("Input pin is not connected");
  352. m_State = State_Paused;
  353. return CompleteStateChange(State_Paused);
  354. }
  355. // Pause the base filter class
  356. HRESULT hr = CBaseFilter::Pause();
  357. if (FAILED(hr)) {
  358. NOTE("Pause failed");
  359. return hr;
  360. }
  361. // Enable EC_REPAINT events again
  362. SetRepaintStatus(TRUE);
  363. StopStreaming();
  364. SourceThreadCanWait(TRUE);
  365. CancelNotification();
  366. ResetEndOfStreamTimer();
  367. // If we are going into a paused state then we must commit whatever
  368. // allocator we are using it so that any source filter can call the
  369. // GetBuffer and expect to get a buffer without returning an error
  370. if (m_pInputPin->Allocator()) {
  371. m_pInputPin->Allocator()->Commit();
  372. }
  373. // There should be no outstanding advise
  374. ASSERT(CancelNotification() == S_FALSE);
  375. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
  376. ASSERT(m_EndOfStreamTimer == 0);
  377. ASSERT(m_pInputPin->IsFlushing() == FALSE);
  378. // When we come out of a stopped state we must clear any image we were
  379. // holding onto for frame refreshing. Since renderers see state changes
  380. // first we can reset ourselves ready to accept the source thread data
  381. // Paused or running after being stopped causes the current position to
  382. // be reset so we're not interested in passing end of stream signals
  383. if (OldState == State_Stopped) {
  384. m_bAbort = FALSE;
  385. ClearPendingSample();
  386. }
  387. return CompleteStateChange(OldState);
  388. }
  389. // When we run the filter the things we do are:-
  390. // Commit the allocator being used in the connection
  391. // Allow a source filter thread to wait in Receive
  392. // Signal the render event just to get us going
  393. // Start the base class by calling StartStreaming
  394. // Allow us to be run when we are not connected
  395. // Signal EC_COMPLETE if we are not connected
  396. STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime)
  397. {
  398. CAutoLock cRendererLock(&m_InterfaceLock);
  399. FILTER_STATE OldState = m_State;
  400. // Make sure there really is a state change
  401. if (m_State == State_Running) {
  402. return NOERROR;
  403. }
  404. // Send EC_COMPLETE if we're not connected
  405. if (m_pInputPin->IsConnected() == FALSE) {
  406. NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
  407. m_State = State_Running;
  408. return NOERROR;
  409. }
  410. Ready();
  411. // Pause the base filter class
  412. HRESULT hr = CBaseFilter::Run(StartTime);
  413. if (FAILED(hr)) {
  414. NOTE("Run failed");
  415. return hr;
  416. }
  417. // Allow the source thread to wait
  418. ASSERT(m_pInputPin->IsFlushing() == FALSE);
  419. SourceThreadCanWait(TRUE);
  420. SetRepaintStatus(FALSE);
  421. // There should be no outstanding advise
  422. ASSERT(CancelNotification() == S_FALSE);
  423. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
  424. ASSERT(m_EndOfStreamTimer == 0);
  425. ASSERT(m_pInputPin->IsFlushing() == FALSE);
  426. // If we are going into a running state then we must commit whatever
  427. // allocator we are using it so that any source filter can call the
  428. // GetBuffer and expect to get a buffer without returning an error
  429. if (m_pInputPin->Allocator()) {
  430. m_pInputPin->Allocator()->Commit();
  431. }
  432. // When we come out of a stopped state we must clear any image we were
  433. // holding onto for frame refreshing. Since renderers see state changes
  434. // first we can reset ourselves ready to accept the source thread data
  435. // Paused or running after being stopped causes the current position to
  436. // be reset so we're not interested in passing end of stream signals
  437. if (OldState == State_Stopped) {
  438. m_bAbort = FALSE;
  439. ClearPendingSample();
  440. }
  441. return StartStreaming();
  442. }
  443. // Return the number of input pins we support
  444. int CBaseRenderer::GetPinCount()
  445. {
  446. if (m_pInputPin == NULL) {
  447. // Try to create it
  448. (void)GetPin(0);
  449. }
  450. return m_pInputPin != NULL ? 1 : 0;
  451. }
  452. // We only support one input pin and it is numbered zero
  453. CBasePin *CBaseRenderer::GetPin(int n)
  454. {
  455. CAutoLock cObjectCreationLock(&m_ObjectCreationLock);
  456. // Should only ever be called with zero
  457. ASSERT(n == 0);
  458. if (n != 0) {
  459. return NULL;
  460. }
  461. // Create the input pin if not already done so
  462. if (m_pInputPin == NULL) {
  463. // hr must be initialized to NOERROR because
  464. // CRendererInputPin's constructor only changes
  465. // hr's value if an error occurs.
  466. HRESULT hr = NOERROR;
  467. m_pInputPin = new CRendererInputPin(this,&hr,L"In");
  468. if (NULL == m_pInputPin) {
  469. return NULL;
  470. }
  471. if (FAILED(hr)) {
  472. delete m_pInputPin;
  473. m_pInputPin = NULL;
  474. return NULL;
  475. }
  476. }
  477. return m_pInputPin;
  478. }
  479. // If "In" then return the IPin for our input pin, otherwise NULL and error
  480. STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, __deref_out IPin **ppPin)
  481. {
  482. CheckPointer(ppPin,E_POINTER);
  483. if (0==lstrcmpW(Id,L"In")) {
  484. *ppPin = GetPin(0);
  485. if (*ppPin) {
  486. (*ppPin)->AddRef();
  487. } else {
  488. return E_OUTOFMEMORY;
  489. }
  490. } else {
  491. *ppPin = NULL;
  492. return VFW_E_NOT_FOUND;
  493. }
  494. return NOERROR;
  495. }
  496. // Called when the input pin receives an EndOfStream notification. If we have
  497. // not got a sample, then notify EC_COMPLETE now. If we have samples, then set
  498. // m_bEOS and check for this on completing samples. If we're waiting to pause
  499. // then complete the transition to paused state by setting the state event
  500. HRESULT CBaseRenderer::EndOfStream()
  501. {
  502. // Ignore these calls if we are stopped
  503. if (m_State == State_Stopped) {
  504. return NOERROR;
  505. }
  506. // If we have a sample then wait for it to be rendered
  507. m_bEOS = TRUE;
  508. if (m_pMediaSample) {
  509. return NOERROR;
  510. }
  511. // If we are waiting for pause then we are now ready since we cannot now
  512. // carry on waiting for a sample to arrive since we are being told there
  513. // won't be any. This sets an event that the GetState function picks up
  514. Ready();
  515. // Only signal completion now if we are running otherwise queue it until
  516. // we do run in StartStreaming. This is used when we seek because a seek
  517. // causes a pause where early notification of completion is misleading
  518. if (m_bStreaming) {
  519. SendEndOfStream();
  520. }
  521. return NOERROR;
  522. }
  523. // When we are told to flush we should release the source thread
  524. HRESULT CBaseRenderer::BeginFlush()
  525. {
  526. // If paused then report state intermediate until we get some data
  527. if (m_State == State_Paused) {
  528. NotReady();
  529. }
  530. SourceThreadCanWait(FALSE);
  531. CancelNotification();
  532. ClearPendingSample();
  533. // Wait for Receive to complete
  534. WaitForReceiveToComplete();
  535. return NOERROR;
  536. }
  537. // After flushing the source thread can wait in Receive again
  538. HRESULT CBaseRenderer::EndFlush()
  539. {
  540. // Reset the current sample media time
  541. if (m_pPosition) m_pPosition->ResetMediaTime();
  542. // There should be no outstanding advise
  543. ASSERT(CancelNotification() == S_FALSE);
  544. SourceThreadCanWait(TRUE);
  545. return NOERROR;
  546. }
  547. // We can now send EC_REPAINTs if so required
  548. HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin)
  549. {
  550. // The caller should always hold the interface lock because
  551. // the function uses CBaseFilter::m_State.
  552. ASSERT(CritCheckIn(&m_InterfaceLock));
  553. m_bAbort = FALSE;
  554. if (State_Running == GetRealState()) {
  555. HRESULT hr = StartStreaming();
  556. if (FAILED(hr)) {
  557. return hr;
  558. }
  559. SetRepaintStatus(FALSE);
  560. } else {
  561. SetRepaintStatus(TRUE);
  562. }
  563. return NOERROR;
  564. }
  565. // Called when we go paused or running
  566. HRESULT CBaseRenderer::Active()
  567. {
  568. return NOERROR;
  569. }
  570. // Called when we go into a stopped state
  571. HRESULT CBaseRenderer::Inactive()
  572. {
  573. if (m_pPosition) {
  574. m_pPosition->ResetMediaTime();
  575. }
  576. // People who derive from this may want to override this behaviour
  577. // to keep hold of the sample in some circumstances
  578. ClearPendingSample();
  579. return NOERROR;
  580. }
  581. // Tell derived classes about the media type agreed
  582. HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt)
  583. {
  584. return NOERROR;
  585. }
  586. // When we break the input pin connection we should reset the EOS flags. When
  587. // we are asked for either IMediaPosition or IMediaSeeking we will create a
  588. // CPosPassThru object to handles media time pass through. When we're handed
  589. // samples we store (by calling CPosPassThru::RegisterMediaTime) their media
  590. // times so we can then return a real current position of data being rendered
  591. HRESULT CBaseRenderer::BreakConnect()
  592. {
  593. // Do we have a quality management sink
  594. if (m_pQSink) {
  595. m_pQSink->Release();
  596. m_pQSink = NULL;
  597. }
  598. // Check we have a valid connection
  599. if (m_pInputPin->IsConnected() == FALSE) {
  600. return S_FALSE;
  601. }
  602. // Check we are stopped before disconnecting
  603. if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) {
  604. return VFW_E_NOT_STOPPED;
  605. }
  606. SetRepaintStatus(FALSE);
  607. ResetEndOfStream();
  608. ClearPendingSample();
  609. m_bAbort = FALSE;
  610. if (State_Running == m_State) {
  611. StopStreaming();
  612. }
  613. return NOERROR;
  614. }
  615. // Retrieves the sample times for this samples (note the sample times are
  616. // passed in by reference not value). We return S_FALSE to say schedule this
  617. // sample according to the times on the sample. We also return S_OK in
  618. // which case the object should simply render the sample data immediately
  619. HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample,
  620. __out REFERENCE_TIME *pStartTime,
  621. __out REFERENCE_TIME *pEndTime)
  622. {
  623. ASSERT(m_dwAdvise == 0);
  624. ASSERT(pMediaSample);
  625. // If the stop time for this sample is before or the same as start time,
  626. // then just ignore it (release it) and schedule the next one in line
  627. // Source filters should always fill in the start and end times properly!
  628. if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) {
  629. if (*pEndTime < *pStartTime) {
  630. return VFW_E_START_TIME_AFTER_END;
  631. }
  632. } else {
  633. // no time set in the sample... draw it now?
  634. return S_OK;
  635. }
  636. // Can't synchronise without a clock so we return S_OK which tells the
  637. // caller that the sample should be rendered immediately without going
  638. // through the overhead of setting a timer advise link with the clock
  639. if (m_pClock == NULL) {
  640. return S_OK;
  641. }
  642. return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime);
  643. }
  644. // By default all samples are drawn according to their time stamps so we
  645. // return S_FALSE. Returning S_OK means draw immediately, this is used
  646. // by the derived video renderer class in its quality management.
  647. HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample,
  648. __out REFERENCE_TIME *ptrStart,
  649. __out REFERENCE_TIME *ptrEnd)
  650. {
  651. return S_FALSE;
  652. }
  653. // We must always reset the current advise time to zero after a timer fires
  654. // because there are several possible ways which lead us not to do any more
  655. // scheduling such as the pending image being cleared after state changes
  656. void CBaseRenderer::SignalTimerFired()
  657. {
  658. m_dwAdvise = 0;
  659. }
  660. // Cancel any notification currently scheduled. This is called by the owning
  661. // window object when it is told to stop streaming. If there is no timer link
  662. // outstanding then calling this is benign otherwise we go ahead and cancel
  663. // We must always reset the render event as the quality management code can
  664. // signal immediate rendering by setting the event without setting an advise
  665. // link. If we're subsequently stopped and run the first attempt to setup an
  666. // advise link with the reference clock will find the event still signalled
  667. HRESULT CBaseRenderer::CancelNotification()
  668. {
  669. ASSERT(m_dwAdvise == 0 || m_pClock);
  670. DWORD_PTR dwAdvise = m_dwAdvise;
  671. // Have we a live advise link
  672. if (m_dwAdvise) {
  673. m_pClock->Unadvise(m_dwAdvise);
  674. SignalTimerFired();
  675. ASSERT(m_dwAdvise == 0);
  676. }
  677. // Clear the event and return our status
  678. m_RenderEvent.Reset();
  679. return (dwAdvise ? S_OK : S_FALSE);
  680. }
  681. // Responsible for setting up one shot advise links with the clock
  682. // Return FALSE if the sample is to be dropped (not drawn at all)
  683. // Return TRUE if the sample is to be drawn and in this case also
  684. // arrange for m_RenderEvent to be set at the appropriate time
  685. BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample)
  686. {
  687. REFERENCE_TIME StartSample, EndSample;
  688. // Is someone pulling our leg
  689. if (pMediaSample == NULL) {
  690. return FALSE;
  691. }
  692. // Get the next sample due up for rendering. If there aren't any ready
  693. // then GetNextSampleTimes returns an error. If there is one to be done
  694. // then it succeeds and yields the sample times. If it is due now then
  695. // it returns S_OK other if it's to be done when due it returns S_FALSE
  696. HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample);
  697. if (FAILED(hr)) {
  698. return FALSE;
  699. }
  700. // If we don't have a reference clock then we cannot set up the advise
  701. // time so we simply set the event indicating an image to render. This
  702. // will cause us to run flat out without any timing or synchronisation
  703. if (hr == S_OK) {
  704. EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent));
  705. return TRUE;
  706. }
  707. ASSERT(m_dwAdvise == 0);
  708. ASSERT(m_pClock);
  709. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
  710. // We do have a valid reference clock interface so we can ask it to
  711. // set an event when the image comes due for rendering. We pass in
  712. // the reference time we were told to start at and also the current
  713. // stream time which is the offset from the start reference time
  714. hr = m_pClock->AdviseTime(
  715. (REFERENCE_TIME) m_tStart, // Start run time
  716. StartSample, // Stream time
  717. (HEVENT)(HANDLE) m_RenderEvent, // Render notification
  718. &m_dwAdvise); // Advise cookie
  719. if (SUCCEEDED(hr)) {
  720. return TRUE;
  721. }
  722. // We could not schedule the next sample for rendering despite the fact
  723. // we have a valid sample here. This is a fair indication that either
  724. // the system clock is wrong or the time stamp for the sample is duff
  725. ASSERT(m_dwAdvise == 0);
  726. return FALSE;
  727. }
  728. // This is called when a sample comes due for rendering. We pass the sample
  729. // on to the derived class. After rendering we will initialise the timer for
  730. // the next sample, NOTE signal that the last one fired first, if we don't
  731. // do this it thinks there is still one outstanding that hasn't completed
  732. HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample)
  733. {
  734. // If the media sample is NULL then we will have been notified by the
  735. // clock that another sample is ready but in the mean time someone has
  736. // stopped us streaming which causes the next sample to be released
  737. if (pMediaSample == NULL) {
  738. return S_FALSE;
  739. }
  740. // If we have stopped streaming then don't render any more samples, the
  741. // thread that got in and locked us and then reset this flag does not
  742. // clear the pending sample as we can use it to refresh any output device
  743. if (m_bStreaming == FALSE) {
  744. return S_FALSE;
  745. }
  746. // Time how long the rendering takes
  747. OnRenderStart(pMediaSample);
  748. DoRenderSample(pMediaSample);
  749. OnRenderEnd(pMediaSample);
  750. return NOERROR;
  751. }
  752. // Checks if there is a sample waiting at the renderer
  753. BOOL CBaseRenderer::HaveCurrentSample()
  754. {
  755. CAutoLock cRendererLock(&m_RendererLock);
  756. return (m_pMediaSample == NULL ? FALSE : TRUE);
  757. }
  758. // Returns the current sample waiting at the video renderer. We AddRef the
  759. // sample before returning so that should it come due for rendering the
  760. // person who called this method will hold the remaining reference count
  761. // that will stop the sample being added back onto the allocator free list
  762. IMediaSample *CBaseRenderer::GetCurrentSample()
  763. {
  764. CAutoLock cRendererLock(&m_RendererLock);
  765. if (m_pMediaSample) {
  766. m_pMediaSample->AddRef();
  767. }
  768. return m_pMediaSample;
  769. }
  770. // Called when the source delivers us a sample. We go through a few checks to
  771. // make sure the sample can be rendered. If we are running (streaming) then we
  772. // have the sample scheduled with the reference clock, if we are not streaming
  773. // then we have received an sample in paused mode so we can complete any state
  774. // transition. On leaving this function everything will be unlocked so an app
  775. // thread may get in and change our state to stopped (for example) in which
  776. // case it will also signal the thread event so that our wait call is stopped
  777. HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample)
  778. {
  779. CAutoLock cInterfaceLock(&m_InterfaceLock);
  780. m_bInReceive = TRUE;
  781. // Check our flushing and filter state
  782. // This function must hold the interface lock because it calls
  783. // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses
  784. // CBasePin::m_bRunTimeError.
  785. HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample);
  786. if (hr != NOERROR) {
  787. m_bInReceive = FALSE;
  788. return E_FAIL;
  789. }
  790. // Has the type changed on a media sample. We do all rendering
  791. // synchronously on the source thread, which has a side effect
  792. // that only one buffer is ever outstanding. Therefore when we
  793. // have Receive called we can go ahead and change the format
  794. // Since the format change can cause a SendMessage we just don't
  795. // lock
  796. if (m_pInputPin->SampleProps()->pMediaType) {
  797. hr = m_pInputPin->SetMediaType(
  798. (CMediaType *)m_pInputPin->SampleProps()->pMediaType);
  799. if (FAILED(hr)) {
  800. m_bInReceive = FALSE;
  801. return hr;
  802. }
  803. }
  804. CAutoLock cSampleLock(&m_RendererLock);
  805. ASSERT(IsActive() == TRUE);
  806. ASSERT(m_pInputPin->IsFlushing() == FALSE);
  807. ASSERT(m_pInputPin->IsConnected() == TRUE);
  808. ASSERT(m_pMediaSample == NULL);
  809. // Return an error if we already have a sample waiting for rendering
  810. // source pins must serialise the Receive calls - we also check that
  811. // no data is being sent after the source signalled an end of stream
  812. if (m_pMediaSample || m_bEOS || m_bAbort) {
  813. Ready();
  814. m_bInReceive = FALSE;
  815. return E_UNEXPECTED;
  816. }
  817. // Store the media times from this sample
  818. if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample);
  819. // Schedule the next sample if we are streaming
  820. if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) {
  821. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
  822. ASSERT(CancelNotification() == S_FALSE);
  823. m_bInReceive = FALSE;
  824. return VFW_E_SAMPLE_REJECTED;
  825. }
  826. // Store the sample end time for EC_COMPLETE handling
  827. m_SignalTime = m_pInputPin->SampleProps()->tStop;
  828. // BEWARE we sometimes keep the sample even after returning the thread to
  829. // the source filter such as when we go into a stopped state (we keep it
  830. // to refresh the device with) so we must AddRef it to keep it safely. If
  831. // we start flushing the source thread is released and any sample waiting
  832. // will be released otherwise GetBuffer may never return (see BeginFlush)
  833. m_pMediaSample = pMediaSample;
  834. m_pMediaSample->AddRef();
  835. if (m_bStreaming == FALSE) {
  836. SetRepaintStatus(TRUE);
  837. }
  838. return NOERROR;
  839. }
  840. // Called by the source filter when we have a sample to render. Under normal
  841. // circumstances we set an advise link with the clock, wait for the time to
  842. // arrive and then render the data using the PURE virtual DoRenderSample that
  843. // the derived class will have overriden. After rendering the sample we may
  844. // also signal EOS if it was the last one sent before EndOfStream was called
  845. HRESULT CBaseRenderer::Receive(IMediaSample *pSample)
  846. {
  847. ASSERT(pSample);
  848. // It may return VFW_E_SAMPLE_REJECTED code to say don't bother
  849. HRESULT hr = PrepareReceive(pSample);
  850. ASSERT(m_bInReceive == SUCCEEDED(hr));
  851. if (FAILED(hr)) {
  852. if (hr == VFW_E_SAMPLE_REJECTED) {
  853. return NOERROR;
  854. }
  855. return hr;
  856. }
  857. // We realize the palette in "PrepareRender()" so we have to give away the
  858. // filter lock here.
  859. if (m_State == State_Paused) {
  860. PrepareRender();
  861. // no need to use InterlockedExchange
  862. m_bInReceive = FALSE;
  863. {
  864. // We must hold both these locks
  865. CAutoLock cRendererLock(&m_InterfaceLock);
  866. if (m_State == State_Stopped)
  867. return NOERROR;
  868. m_bInReceive = TRUE;
  869. CAutoLock cSampleLock(&m_RendererLock);
  870. OnReceiveFirstSample(pSample);
  871. }
  872. Ready();
  873. }
  874. // Having set an advise link with the clock we sit and wait. We may be
  875. // awoken by the clock firing or by a state change. The rendering call
  876. // will lock the critical section and check we can still render the data
  877. hr = WaitForRenderTime();
  878. if (FAILED(hr)) {
  879. m_bInReceive = FALSE;
  880. return NOERROR;
  881. }
  882. PrepareRender();
  883. // Set this here and poll it until we work out the locking correctly
  884. // It can't be right that the streaming stuff grabs the interface
  885. // lock - after all we want to be able to wait for this stuff
  886. // to complete
  887. m_bInReceive = FALSE;
  888. // We must hold both these locks
  889. CAutoLock cRendererLock(&m_InterfaceLock);
  890. // since we gave away the filter wide lock, the sate of the filter could
  891. // have chnaged to Stopped
  892. if (m_State == State_Stopped)
  893. return NOERROR;
  894. CAutoLock cSampleLock(&m_RendererLock);
  895. // Deal with this sample
  896. Render(m_pMediaSample);
  897. ClearPendingSample();
  898. SendEndOfStream();
  899. CancelNotification();
  900. return NOERROR;
  901. }
  902. // This is called when we stop or are inactivated to clear the pending sample
  903. // We release the media sample interface so that they can be allocated to the
  904. // source filter again, unless of course we are changing state to inactive in
  905. // which case GetBuffer will return an error. We must also reset the current
  906. // media sample to NULL so that we know we do not currently have an image
  907. HRESULT CBaseRenderer::ClearPendingSample()
  908. {
  909. CAutoLock cRendererLock(&m_RendererLock);
  910. if (m_pMediaSample) {
  911. m_pMediaSample->Release();
  912. m_pMediaSample = NULL;
  913. }
  914. return NOERROR;
  915. }
  916. // Used to signal end of stream according to the sample end time
  917. void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
  918. UINT uMsg, // Not currently used
  919. DWORD_PTR dwUser,// User information
  920. DWORD_PTR dw1, // Windows reserved
  921. DWORD_PTR dw2) // is also reserved
  922. {
  923. CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser;
  924. NOTE1("EndOfStreamTimer called (%d)",uID);
  925. pRenderer->TimerCallback();
  926. }
  927. // Do the timer callback work
  928. void CBaseRenderer::TimerCallback()
  929. {
  930. // Lock for synchronization (but don't hold this lock when calling
  931. // timeKillEvent)
  932. CAutoLock cRendererLock(&m_RendererLock);
  933. // See if we should signal end of stream now
  934. if (m_EndOfStreamTimer) {
  935. m_EndOfStreamTimer = 0;
  936. SendEndOfStream();
  937. }
  938. }
  939. // If we are at the end of the stream signal the filter graph but do not set
  940. // the state flag back to FALSE. Once we drop off the end of the stream we
  941. // leave the flag set (until a subsequent ResetEndOfStream). Each sample we
  942. // get delivered will update m_SignalTime to be the last sample's end time.
  943. // We must wait this long before signalling end of stream to the filtergraph
  944. #define TIMEOUT_DELIVERYWAIT 50
  945. #define TIMEOUT_RESOLUTION 10
  946. HRESULT CBaseRenderer::SendEndOfStream()
  947. {
  948. ASSERT(CritCheckIn(&m_RendererLock));
  949. if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) {
  950. return NOERROR;
  951. }
  952. // If there is no clock then signal immediately
  953. if (m_pClock == NULL) {
  954. return NotifyEndOfStream();
  955. }
  956. // How long into the future is the delivery time
  957. REFERENCE_TIME Signal = m_tStart + m_SignalTime;
  958. REFERENCE_TIME CurrentTime;
  959. m_pClock->GetTime(&CurrentTime);
  960. LONG Delay = LONG((Signal - CurrentTime) / 10000);
  961. // Dump the timing information to the debugger
  962. NOTE1("Delay until end of stream delivery %d",Delay);
  963. NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime));
  964. NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal));
  965. // Wait for the delivery time to arrive
  966. if (Delay < TIMEOUT_DELIVERYWAIT) {
  967. return NotifyEndOfStream();
  968. }
  969. // Signal a timer callback on another worker thread
  970. m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer
  971. TIMEOUT_RESOLUTION, // Timer resolution
  972. EndOfStreamTimer, // Callback function
  973. DWORD_PTR(this), // Used information
  974. TIME_ONESHOT); // Type of callback
  975. if (m_EndOfStreamTimer == 0) {
  976. return NotifyEndOfStream();
  977. }
  978. return NOERROR;
  979. }
  980. // Signals EC_COMPLETE to the filtergraph manager
  981. HRESULT CBaseRenderer::NotifyEndOfStream()
  982. {
  983. CAutoLock cRendererLock(&m_RendererLock);
  984. ASSERT(m_bEOSDelivered == FALSE);
  985. ASSERT(m_EndOfStreamTimer == 0);
  986. // Has the filter changed state
  987. if (m_bStreaming == FALSE) {
  988. ASSERT(m_EndOfStreamTimer == 0);
  989. return NOERROR;
  990. }
  991. // Reset the end of stream timer
  992. m_EndOfStreamTimer = 0;
  993. // If we've been using the IMediaPosition interface, set it's start
  994. // and end media "times" to the stop position by hand. This ensures
  995. // that we actually get to the end, even if the MPEG guestimate has
  996. // been bad or if the quality management dropped the last few frames
  997. if (m_pPosition) m_pPosition->EOS();
  998. m_bEOSDelivered = TRUE;
  999. NOTE("Sending EC_COMPLETE...");
  1000. return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
  1001. }
  1002. // Reset the end of stream flag, this is typically called when we transfer to
  1003. // stopped states since that resets the current position back to the start so
  1004. // we will receive more samples or another EndOfStream if there aren't any. We
  1005. // keep two separate flags one to say we have run off the end of the stream
  1006. // (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE
  1007. // to the filter graph. We need the latter otherwise we can end up sending an
  1008. // EC_COMPLETE every time the source changes state and calls our EndOfStream
  1009. HRESULT CBaseRenderer::ResetEndOfStream()
  1010. {
  1011. ResetEndOfStreamTimer();
  1012. CAutoLock cRendererLock(&m_RendererLock);
  1013. m_bEOS = FALSE;
  1014. m_bEOSDelivered = FALSE;
  1015. m_SignalTime = 0;
  1016. return NOERROR;
  1017. }
  1018. // Kills any outstanding end of stream timer
  1019. void CBaseRenderer::ResetEndOfStreamTimer()
  1020. {
  1021. ASSERT(CritCheckOut(&m_RendererLock));
  1022. if (m_EndOfStreamTimer) {
  1023. timeKillEvent(m_EndOfStreamTimer);
  1024. m_EndOfStreamTimer = 0;
  1025. }
  1026. }
  1027. // This is called when we start running so that we can schedule any pending
  1028. // image we have with the clock and display any timing information. If we
  1029. // don't have any sample but we have queued an EOS flag then we send it. If
  1030. // we do have a sample then we wait until that has been rendered before we
  1031. // signal the filter graph otherwise we may change state before it's done
  1032. HRESULT CBaseRenderer::StartStreaming()
  1033. {
  1034. CAutoLock cRendererLock(&m_RendererLock);
  1035. if (m_bStreaming == TRUE) {
  1036. return NOERROR;
  1037. }
  1038. // Reset the streaming times ready for running
  1039. m_bStreaming = TRUE;
  1040. timeBeginPeriod(1);
  1041. OnStartStreaming();
  1042. // There should be no outstanding advise
  1043. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
  1044. ASSERT(CancelNotification() == S_FALSE);
  1045. // If we have an EOS and no data then deliver it now
  1046. if (m_pMediaSample == NULL) {
  1047. return SendEndOfStream();
  1048. }
  1049. // Have the data rendered
  1050. ASSERT(m_pMediaSample);
  1051. if (!ScheduleSample(m_pMediaSample))
  1052. m_RenderEvent.Set();
  1053. return NOERROR;
  1054. }
  1055. // This is called when we stop streaming so that we can set our internal flag
  1056. // indicating we are not now to schedule any more samples arriving. The state
  1057. // change methods in the filter implementation take care of cancelling any
  1058. // clock advise link we have set up and clearing any pending sample we have
  1059. HRESULT CBaseRenderer::StopStreaming()
  1060. {
  1061. CAutoLock cRendererLock(&m_RendererLock);
  1062. m_bEOSDelivered = FALSE;
  1063. if (m_bStreaming == TRUE) {
  1064. m_bStreaming = FALSE;
  1065. OnStopStreaming();
  1066. timeEndPeriod(1);
  1067. }
  1068. return NOERROR;
  1069. }
  1070. // We have a boolean flag that is reset when we have signalled EC_REPAINT to
  1071. // the filter graph. We set this when we receive an image so that should any
  1072. // conditions arise again we can send another one. By having a flag we ensure
  1073. // we don't flood the filter graph with redundant calls. We do not set the
  1074. // event when we receive an EndOfStream call since there is no point in us
  1075. // sending further EC_REPAINTs. In particular the AutoShowWindow method and
  1076. // the DirectDraw object use this method to control the window repainting
  1077. void CBaseRenderer::SetRepaintStatus(BOOL bRepaint)
  1078. {
  1079. CAutoLock cSampleLock(&m_RendererLock);
  1080. m_bRepaintStatus = bRepaint;
  1081. }
  1082. // Pass the window handle to the upstream filter
  1083. void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd)
  1084. {
  1085. IMediaEventSink *pSink;
  1086. // Does the pin support IMediaEventSink
  1087. HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink);
  1088. if (SUCCEEDED(hr)) {
  1089. pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0);
  1090. pSink->Release();
  1091. }
  1092. NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0);
  1093. }
  1094. // Signal an EC_REPAINT to the filter graph. This can be used to have data
  1095. // sent to us. For example when a video window is first displayed it may
  1096. // not have an image to display, at which point it signals EC_REPAINT. The
  1097. // filtergraph will either pause the graph if stopped or if already paused
  1098. // it will call put_CurrentPosition of the current position. Setting the
  1099. // current position to itself has the stream flushed and the image resent
  1100. #define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_)));
  1101. void CBaseRenderer::SendRepaint()
  1102. {
  1103. CAutoLock cSampleLock(&m_RendererLock);
  1104. ASSERT(m_pInputPin);
  1105. // We should not send repaint notifications when...
  1106. // - An end of stream has been notified
  1107. // - Our input pin is being flushed
  1108. // - The input pin is not connected
  1109. // - We have aborted a video playback
  1110. // - There is a repaint already sent
  1111. if (m_bAbort == FALSE) {
  1112. if (m_pInputPin->IsConnected() == TRUE) {
  1113. if (m_pInputPin->IsFlushing() == FALSE) {
  1114. if (IsEndOfStream() == FALSE) {
  1115. if (m_bRepaintStatus == TRUE) {
  1116. IPin *pPin = (IPin *) m_pInputPin;
  1117. NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0);
  1118. SetRepaintStatus(FALSE);
  1119. RLOG("Sending repaint");
  1120. }
  1121. }
  1122. }
  1123. }
  1124. }
  1125. }
  1126. // When a video window detects a display change (WM_DISPLAYCHANGE message) it
  1127. // can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The
  1128. // filtergraph will stop everyone and reconnect our input pin. As we're then
  1129. // reconnected we can accept the media type that matches the new display mode
  1130. // since we may no longer be able to draw the current image type efficiently
  1131. BOOL CBaseRenderer::OnDisplayChange()
  1132. {
  1133. // Ignore if we are not connected yet
  1134. CAutoLock cSampleLock(&m_RendererLock);
  1135. if (m_pInputPin->IsConnected() == FALSE) {
  1136. return FALSE;
  1137. }
  1138. RLOG("Notification of EC_DISPLAY_CHANGE");
  1139. // Pass our input pin as parameter on the event
  1140. IPin *pPin = (IPin *) m_pInputPin;
  1141. m_pInputPin->AddRef();
  1142. NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0);
  1143. SetAbortSignal(TRUE);
  1144. ClearPendingSample();
  1145. m_pInputPin->Release();
  1146. return TRUE;
  1147. }
  1148. // Called just before we start drawing.
  1149. // Store the current time in m_trRenderStart to allow the rendering time to be
  1150. // logged. Log the time stamp of the sample and how late it is (neg is early)
  1151. void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample)
  1152. {
  1153. #ifdef PERF
  1154. REFERENCE_TIME trStart, trEnd;
  1155. pMediaSample->GetTime(&trStart, &trEnd);
  1156. MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits
  1157. m_pClock->GetTime(&m_trRenderStart);
  1158. MSR_INTEGER(0, (int)m_trRenderStart);
  1159. REFERENCE_TIME trStream;
  1160. trStream = m_trRenderStart-m_tStart; // convert reftime to stream time
  1161. MSR_INTEGER(0,(int)trStream);
  1162. const int trLate = (int)(trStream - trStart);
  1163. MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec
  1164. #endif
  1165. } // OnRenderStart
  1166. // Called directly after drawing an image.
  1167. // calculate the time spent drawing and log it.
  1168. void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample)
  1169. {
  1170. #ifdef PERF
  1171. REFERENCE_TIME trNow;
  1172. m_pClock->GetTime(&trNow);
  1173. MSR_INTEGER(0,(int)trNow);
  1174. int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec
  1175. MSR_INTEGER(m_idBaseRenderTime, t);
  1176. #endif
  1177. } // OnRenderEnd
  1178. // Constructor must be passed the base renderer object
  1179. CRendererInputPin::CRendererInputPin(__inout CBaseRenderer *pRenderer,
  1180. __inout HRESULT *phr,
  1181. __in_opt LPCWSTR pPinName) :
  1182. CBaseInputPin(NAME("Renderer pin"),
  1183. pRenderer,
  1184. &pRenderer->m_InterfaceLock,
  1185. (HRESULT *) phr,
  1186. pPinName)
  1187. {
  1188. m_pRenderer = pRenderer;
  1189. ASSERT(m_pRenderer);
  1190. }
  1191. // Signals end of data stream on the input pin
  1192. STDMETHODIMP CRendererInputPin::EndOfStream()
  1193. {
  1194. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1195. CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
  1196. // Make sure we're streaming ok
  1197. HRESULT hr = CheckStreaming();
  1198. if (hr != NOERROR) {
  1199. return hr;
  1200. }
  1201. // Pass it onto the renderer
  1202. hr = m_pRenderer->EndOfStream();
  1203. if (SUCCEEDED(hr)) {
  1204. hr = CBaseInputPin::EndOfStream();
  1205. }
  1206. return hr;
  1207. }
  1208. // Signals start of flushing on the input pin - we do the final reset end of
  1209. // stream with the renderer lock unlocked but with the interface lock locked
  1210. // We must do this because we call timeKillEvent, our timer callback method
  1211. // has to take the renderer lock to serialise our state. Therefore holding a
  1212. // renderer lock when calling timeKillEvent could cause a deadlock condition
  1213. STDMETHODIMP CRendererInputPin::BeginFlush()
  1214. {
  1215. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1216. {
  1217. CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
  1218. CBaseInputPin::BeginFlush();
  1219. m_pRenderer->BeginFlush();
  1220. }
  1221. return m_pRenderer->ResetEndOfStream();
  1222. }
  1223. // Signals end of flushing on the input pin
  1224. STDMETHODIMP CRendererInputPin::EndFlush()
  1225. {
  1226. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1227. CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
  1228. HRESULT hr = m_pRenderer->EndFlush();
  1229. if (SUCCEEDED(hr)) {
  1230. hr = CBaseInputPin::EndFlush();
  1231. }
  1232. return hr;
  1233. }
  1234. // Pass the sample straight through to the renderer object
  1235. STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample)
  1236. {
  1237. HRESULT hr = m_pRenderer->Receive(pSample);
  1238. if (FAILED(hr)) {
  1239. // A deadlock could occur if the caller holds the renderer lock and
  1240. // attempts to acquire the interface lock.
  1241. ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock));
  1242. {
  1243. // The interface lock must be held when the filter is calling
  1244. // IsStopped() or IsFlushing(). The interface lock must also
  1245. // be held because the function uses m_bRunTimeError.
  1246. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1247. // We do not report errors which occur while the filter is stopping,
  1248. // flushing or if the m_bAbort flag is set . Errors are expected to
  1249. // occur during these operations and the streaming thread correctly
  1250. // handles the errors.
  1251. if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) {
  1252. // EC_ERRORABORT's first parameter is the error which caused
  1253. // the event and its' last parameter is 0. See the Direct
  1254. // Show SDK documentation for more information.
  1255. m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0);
  1256. {
  1257. CAutoLock alRendererLock(&m_pRenderer->m_RendererLock);
  1258. if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) {
  1259. m_pRenderer->NotifyEndOfStream();
  1260. }
  1261. }
  1262. m_bRunTimeError = TRUE;
  1263. }
  1264. }
  1265. }
  1266. return hr;
  1267. }
  1268. // Called when the input pin is disconnected
  1269. HRESULT CRendererInputPin::BreakConnect()
  1270. {
  1271. HRESULT hr = m_pRenderer->BreakConnect();
  1272. if (FAILED(hr)) {
  1273. return hr;
  1274. }
  1275. return CBaseInputPin::BreakConnect();
  1276. }
  1277. // Called when the input pin is connected
  1278. HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin)
  1279. {
  1280. HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin);
  1281. if (FAILED(hr)) {
  1282. return hr;
  1283. }
  1284. return CBaseInputPin::CompleteConnect(pReceivePin);
  1285. }
  1286. // Give the pin id of our one and only pin
  1287. STDMETHODIMP CRendererInputPin::QueryId(__deref_out LPWSTR *Id)
  1288. {
  1289. CheckPointer(Id,E_POINTER);
  1290. const WCHAR szIn[] = L"In";
  1291. *Id = (LPWSTR)CoTaskMemAlloc(sizeof(szIn));
  1292. if (*Id == NULL) {
  1293. return E_OUTOFMEMORY;
  1294. }
  1295. CopyMemory(*Id, szIn, sizeof(szIn));
  1296. return NOERROR;
  1297. }
  1298. // Will the filter accept this media type
  1299. HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt)
  1300. {
  1301. return m_pRenderer->CheckMediaType(pmt);
  1302. }
  1303. // Called when we go paused or running
  1304. HRESULT CRendererInputPin::Active()
  1305. {
  1306. return m_pRenderer->Active();
  1307. }
  1308. // Called when we go into a stopped state
  1309. HRESULT CRendererInputPin::Inactive()
  1310. {
  1311. // The caller must hold the interface lock because
  1312. // this function uses m_bRunTimeError.
  1313. ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock));
  1314. m_bRunTimeError = FALSE;
  1315. return m_pRenderer->Inactive();
  1316. }
  1317. // Tell derived classes about the media type agreed
  1318. HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt)
  1319. {
  1320. HRESULT hr = CBaseInputPin::SetMediaType(pmt);
  1321. if (FAILED(hr)) {
  1322. return hr;
  1323. }
  1324. return m_pRenderer->SetMediaType(pmt);
  1325. }
  1326. // We do not keep an event object to use when setting up a timer link with
  1327. // the clock but are given a pointer to one by the owning object through the
  1328. // SetNotificationObject method - this must be initialised before starting
  1329. // We can override the default quality management process to have it always
  1330. // draw late frames, this is currently done by having the following registry
  1331. // key (actually an INI key) called DrawLateFrames set to 1 (default is 0)
  1332. const TCHAR AMQUALITY[] = TEXT("ActiveMovie");
  1333. const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames");
  1334. CBaseVideoRenderer::CBaseVideoRenderer(
  1335. REFCLSID RenderClass, // CLSID for this renderer
  1336. __in_opt LPCTSTR pName, // Debug ONLY description
  1337. __inout_opt LPUNKNOWN pUnk, // Aggregated owner object
  1338. __inout HRESULT *phr) : // General OLE return code
  1339. CBaseRenderer(RenderClass,pName,pUnk,phr),
  1340. m_cFramesDropped(0),
  1341. m_cFramesDrawn(0),
  1342. m_bSupplierHandlingQuality(FALSE)
  1343. {
  1344. ResetStreamingTimes();
  1345. #ifdef PERF
  1346. m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp"));
  1347. m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge"));
  1348. m_idTarget = MSR_REGISTER(TEXT("Target (mSec)"));
  1349. m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled"));
  1350. m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code"));
  1351. m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent"));
  1352. m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent"));
  1353. m_idWaitReal = MSR_REGISTER(TEXT("Render wait"));
  1354. // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)"));
  1355. m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)"));
  1356. m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE);
  1357. //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message"));
  1358. m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg"));
  1359. m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg"));
  1360. m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg"));
  1361. m_idDuration = MSR_REGISTER(TEXT("Duration"));
  1362. m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait"));
  1363. // m_idDebug = MSR_REGISTER(TEXT("Debug stuff"));
  1364. #endif // PERF
  1365. } // Constructor
  1366. // Destructor is just a placeholder
  1367. CBaseVideoRenderer::~CBaseVideoRenderer()
  1368. {
  1369. ASSERT(m_dwAdvise == 0);
  1370. }
  1371. // The timing functions in this class are called by the window object and by
  1372. // the renderer's allocator.
  1373. // The windows object calls timing functions as it receives media sample
  1374. // images for drawing using GDI.
  1375. // The allocator calls timing functions when it starts passing DCI/DirectDraw
  1376. // surfaces which are not rendered in the same way; The decompressor writes
  1377. // directly to the surface with no separate rendering, so those code paths
  1378. // call direct into us. Since we only ever hand out DCI/DirectDraw surfaces
  1379. // when we have allocated one and only one image we know there cannot be any
  1380. // conflict between the two.
  1381. //
  1382. // We use timeGetTime to return the timing counts we use (since it's relative
  1383. // performance we are interested in rather than absolute compared to a clock)
  1384. // The window object sets the accuracy of the system clock (normally 1ms) by
  1385. // calling timeBeginPeriod/timeEndPeriod when it changes streaming states
  1386. // Reset all times controlling streaming.
  1387. // Set them so that
  1388. // 1. Frames will not initially be dropped
  1389. // 2. The first frame will definitely be drawn (achieved by saying that there
  1390. // has not ben a frame drawn for a long time).
  1391. HRESULT CBaseVideoRenderer::ResetStreamingTimes()
  1392. {
  1393. m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago
  1394. m_tStreamingStart = timeGetTime();
  1395. m_trRenderAvg = 0;
  1396. m_trFrameAvg = -1; // -1000 fps == "unset"
  1397. m_trDuration = 0; // 0 - strange value
  1398. m_trRenderLast = 0;
  1399. m_trWaitAvg = 0;
  1400. m_tRenderStart = 0;
  1401. m_cFramesDrawn = 0;
  1402. m_cFramesDropped = 0;
  1403. m_iTotAcc = 0;
  1404. m_iSumSqAcc = 0;
  1405. m_iSumSqFrameTime = 0;
  1406. m_trFrame = 0; // hygeine - not really needed
  1407. m_trLate = 0; // hygeine - not really needed
  1408. m_iSumFrameTime = 0;
  1409. m_nNormal = 0;
  1410. m_trEarliness = 0;
  1411. m_trTarget = -300000; // 30mSec early
  1412. m_trThrottle = 0;
  1413. m_trRememberStampForPerf = 0;
  1414. #ifdef PERF
  1415. m_trRememberFrameForPerf = 0;
  1416. #endif
  1417. return NOERROR;
  1418. } // ResetStreamingTimes
  1419. // Reset all times controlling streaming. Note that we're now streaming. We
  1420. // don't need to set the rendering event to have the source filter released
  1421. // as it is done during the Run processing. When we are run we immediately
  1422. // release the source filter thread and draw any image waiting (that image
  1423. // may already have been drawn once as a poster frame while we were paused)
  1424. HRESULT CBaseVideoRenderer::OnStartStreaming()
  1425. {
  1426. ResetStreamingTimes();
  1427. return NOERROR;
  1428. } // OnStartStreaming
  1429. // Called at end of streaming. Fixes times for property page report
  1430. HRESULT CBaseVideoRenderer::OnStopStreaming()
  1431. {
  1432. m_tStreamingStart = timeGetTime()-m_tStreamingStart;
  1433. return NOERROR;
  1434. } // OnStopStreaming
  1435. // Called when we start waiting for a rendering event.
  1436. // Used to update times spent waiting and not waiting.
  1437. void CBaseVideoRenderer::OnWaitStart()
  1438. {
  1439. MSR_START(m_idWaitReal);
  1440. } // OnWaitStart
  1441. // Called when we are awoken from the wait in the window OR by our allocator
  1442. // when it is hanging around until the next sample is due for rendering on a
  1443. // DCI/DirectDraw surface. We add the wait time into our rolling average.
  1444. // We grab the interface lock so that we're serialised with the application
  1445. // thread going through the run code - which in due course ends up calling
  1446. // ResetStreaming times - possibly as we run through this section of code
  1447. void CBaseVideoRenderer::OnWaitEnd()
  1448. {
  1449. #ifdef PERF
  1450. MSR_STOP(m_idWaitReal);
  1451. // for a perf build we want to know just exactly how late we REALLY are.
  1452. // even if this means that we have to look at the clock again.
  1453. REFERENCE_TIME trRealStream; // the real time now expressed as stream time.
  1454. #if 0
  1455. m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock!
  1456. #else
  1457. // We will be discarding overflows like mad here!
  1458. // This is wrong really because timeGetTime() can wrap but it's
  1459. // only for PERF
  1460. REFERENCE_TIME tr = timeGetTime()*10000;
  1461. trRealStream = tr + m_llTimeOffset;
  1462. #endif
  1463. trRealStream -= m_tStart; // convert to stream time (this is a reftime)
  1464. if (m_trRememberStampForPerf==0) {
  1465. // This is probably the poster frame at the start, and it is not scheduled
  1466. // in the usual way at all. Just count it. The rememberstamp gets set
  1467. // in ShouldDrawSampleNow, so this does invalid frame recording until we
  1468. // actually start playing.
  1469. PreparePerformanceData(0, 0);
  1470. } else {
  1471. int trLate = (int)(trRealStream - m_trRememberStampForPerf);
  1472. int trFrame = (int)(tr - m_trRememberFrameForPerf);
  1473. PreparePerformanceData(trLate, trFrame);
  1474. }
  1475. m_trRememberFrameForPerf = tr;
  1476. #endif //PERF
  1477. } // OnWaitEnd
  1478. // Put data on one side that describes the lateness of the current frame.
  1479. // We don't yet know whether it will actually be drawn. In direct draw mode,
  1480. // this decision is up to the filter upstream, and it could change its mind.
  1481. // The rules say that if it did draw it must call Receive(). One way or
  1482. // another we eventually get into either OnRenderStart or OnDirectRender and
  1483. // these both call RecordFrameLateness to update the statistics.
  1484. void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame)
  1485. {
  1486. m_trLate = trLate;
  1487. m_trFrame = trFrame;
  1488. } // PreparePerformanceData
  1489. // update the statistics:
  1490. // m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn
  1491. // Note that because the properties page reports using these variables,
  1492. // 1. We need to be inside a critical section
  1493. // 2. They must all be updated together. Updating the sums here and the count
  1494. // elsewhere can result in imaginary jitter (i.e. attempts to find square roots
  1495. // of negative numbers) in the property page code.
  1496. void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame)
  1497. {
  1498. // Record how timely we are.
  1499. int tLate = trLate/10000;
  1500. // Best estimate of moment of appearing on the screen is average of
  1501. // start and end draw times. Here we have only the end time. This may
  1502. // tend to show us as spuriously late by up to 1/2 frame rate achieved.
  1503. // Decoder probably monitors draw time. We don't bother.
  1504. MSR_INTEGER( m_idFrameAccuracy, tLate );
  1505. // This is a kludge - we can get frames that are very late
  1506. // especially (at start-up) and they invalidate the statistics.
  1507. // So ignore things that are more than 1 sec off.
  1508. if (tLate>1000 || tLate<-1000) {
  1509. if (m_cFramesDrawn<=1) {
  1510. tLate = 0;
  1511. } else if (tLate>0) {
  1512. tLate = 1000;
  1513. } else {
  1514. tLate = -1000;
  1515. }
  1516. }
  1517. // The very first frame often has a invalid time, so don't
  1518. // count it into the statistics. (???)
  1519. if (m_cFramesDrawn>1) {
  1520. m_iTotAcc += tLate;
  1521. m_iSumSqAcc += (tLate*tLate);
  1522. }
  1523. // calculate inter-frame time. Doesn't make sense for first frame
  1524. // second frame suffers from invalid first frame stamp.
  1525. if (m_cFramesDrawn>2) {
  1526. int tFrame = trFrame/10000; // convert to mSec else it overflows
  1527. // This is a kludge. It can overflow anyway (a pause can cause
  1528. // a very long inter-frame time) and it overflows at 2**31/10**7
  1529. // or about 215 seconds i.e. 3min 35sec
  1530. if (tFrame>1000||tFrame<0) tFrame = 1000;
  1531. m_iSumSqFrameTime += tFrame*tFrame;
  1532. ASSERT(m_iSumSqFrameTime>=0);
  1533. m_iSumFrameTime += tFrame;
  1534. }
  1535. ++m_cFramesDrawn;
  1536. } // RecordFrameLateness
  1537. void CBaseVideoRenderer::ThrottleWait()
  1538. {
  1539. if (m_trThrottle>0) {
  1540. int iThrottle = m_trThrottle/10000; // convert to mSec
  1541. MSR_INTEGER( m_idThrottle, iThrottle);
  1542. DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle));
  1543. Sleep(iThrottle);
  1544. } else {
  1545. Sleep(0);
  1546. }
  1547. } // ThrottleWait
  1548. // Whenever a frame is rendered it goes though either OnRenderStart
  1549. // or OnDirectRender. Data that are generated during ShouldDrawSample
  1550. // are added to the statistics by calling RecordFrameLateness from both
  1551. // these two places.
  1552. // Called in place of OnRenderStart..OnRenderEnd
  1553. // When a DirectDraw image is drawn
  1554. void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample)
  1555. {
  1556. m_trRenderAvg = 0;
  1557. m_trRenderLast = 5000000; // If we mode switch, we do NOT want this
  1558. // to inhibit the new average getting going!
  1559. // so we set it to half a second
  1560. // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000);
  1561. RecordFrameLateness(m_trLate, m_trFrame);
  1562. ThrottleWait();
  1563. } // OnDirectRender
  1564. // Called just before we start drawing. All we do is to get the current clock
  1565. // time (from the system) and return. We have to store the start render time
  1566. // in a member variable because it isn't used until we complete the drawing
  1567. // The rest is just performance logging.
  1568. void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample)
  1569. {
  1570. RecordFrameLateness(m_trLate, m_trFrame);
  1571. m_tRenderStart = timeGetTime();
  1572. } // OnRenderStart
  1573. // Called directly after drawing an image. We calculate the time spent in the
  1574. // drawing code and if this doesn't appear to have any odd looking spikes in
  1575. // it then we add it to the current average draw time. Measurement spikes may
  1576. // occur if the drawing thread is interrupted and switched to somewhere else.
  1577. void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample)
  1578. {
  1579. // The renderer time can vary erratically if we are interrupted so we do
  1580. // some smoothing to help get more sensible figures out but even that is
  1581. // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83
  1582. int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS
  1583. if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) {
  1584. // DO_MOVING_AVG(m_trRenderAvg, tr);
  1585. m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD;
  1586. }
  1587. m_trRenderLast = tr;
  1588. ThrottleWait();
  1589. } // OnRenderEnd
  1590. STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc)
  1591. {
  1592. m_pQSink = piqc;
  1593. return NOERROR;
  1594. } // SetSink
  1595. STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q)
  1596. {
  1597. // NOTE: We are NOT getting any locks here. We could be called
  1598. // asynchronously and possibly even on a time critical thread of
  1599. // someone else's - so we do the minumum. We only set one state
  1600. // variable (an integer) and if that happens to be in the middle
  1601. // of another thread reading it they will just get either the new
  1602. // or the old value. Locking would achieve no more than this.
  1603. // It might be nice to check that we are being called from m_pGraph, but
  1604. // it turns out to be a millisecond or so per throw!
  1605. // This is heuristics, these numbers are aimed at being "what works"
  1606. // rather than anything based on some theory.
  1607. // We use a hyperbola because it's easy to calculate and it includes
  1608. // a panic button asymptote (which we push off just to the left)
  1609. // The throttling fits the following table (roughly)
  1610. // Proportion Throttle (msec)
  1611. // >=1000 0
  1612. // 900 3
  1613. // 800 7
  1614. // 700 11
  1615. // 600 17
  1616. // 500 25
  1617. // 400 35
  1618. // 300 50
  1619. // 200 72
  1620. // 125 100
  1621. // 100 112
  1622. // 50 146
  1623. // 0 200
  1624. // (some evidence that we could go for a sharper kink - e.g. no throttling
  1625. // until below the 750 mark - might give fractionally more frames on a
  1626. // P60-ish machine). The easy way to get these coefficients is to use
  1627. // Renbase.xls follow the instructions therein using excel solver.
  1628. if (q.Proportion>=1000) { m_trThrottle = 0; }
  1629. else {
  1630. // The DWORD is to make quite sure I get unsigned arithmetic
  1631. // as the constant is between 2**31 and 2**32
  1632. m_trThrottle = -330000 + (388880000/(q.Proportion+167));
  1633. }
  1634. return NOERROR;
  1635. } // Notify
  1636. // Send a message to indicate what our supplier should do about quality.
  1637. // Theory:
  1638. // What a supplier wants to know is "is the frame I'm working on NOW
  1639. // going to be late?".
  1640. // F1 is the frame at the supplier (as above)
  1641. // Tf1 is the due time for F1
  1642. // T1 is the time at that point (NOW!)
  1643. // Tr1 is the time that f1 WILL actually be rendered
  1644. // L1 is the latency of the graph for frame F1 = Tr1-T1
  1645. // D1 (for delay) is how late F1 will be beyond its due time i.e.
  1646. // D1 = (Tr1-Tf1) which is what the supplier really wants to know.
  1647. // Unfortunately Tr1 is in the future and is unknown, so is L1
  1648. //
  1649. // We could estimate L1 by its value for a previous frame,
  1650. // L0 = Tr0-T0 and work off
  1651. // D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1)
  1652. // Rearranging terms:
  1653. // D1' = (T1-T0) + (Tr0-Tf1)
  1654. // adding (Tf0-Tf0) and rearranging again:
  1655. // = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1)
  1656. // = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0)
  1657. // But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the
  1658. // Late field in the quality message that we send.
  1659. // The other two terms just state what correction should be applied before
  1660. // using the lateness of F0 to predict the lateness of F1.
  1661. // (T1-T0) says how much time has actually passed (we have lost this much)
  1662. // (Tf1-Tf0) says how much time should have passed if we were keeping pace
  1663. // (we have gained this much).
  1664. //
  1665. // Suppliers should therefore work off:
  1666. // Quality.Late + (T1-T0) - (Tf1-Tf0)
  1667. // and see if this is "acceptably late" or even early (i.e. negative).
  1668. // They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from
  1669. // the time stamps in the frames. They get Quality.Late from us.
  1670. //
  1671. HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate,
  1672. REFERENCE_TIME trRealStream)
  1673. {
  1674. Quality q;
  1675. HRESULT hr;
  1676. // If we are the main user of time, then report this as Flood/Dry.
  1677. // If our suppliers are, then report it as Famine/Glut.
  1678. //
  1679. // We need to take action, but avoid hunting. Hunting is caused by
  1680. // 1. Taking too much action too soon and overshooting
  1681. // 2. Taking too long to react (so averaging can CAUSE hunting).
  1682. //
  1683. // The reason why we use trLate as well as Wait is to reduce hunting;
  1684. // if the wait time is coming down and about to go into the red, we do
  1685. // NOT want to rely on some average which is only telling is that it used
  1686. // to be OK once.
  1687. q.TimeStamp = (REFERENCE_TIME)trRealStream;
  1688. if (m_trFrameAvg<0) {
  1689. q.Type = Famine; // guess
  1690. }
  1691. // Is the greater part of the time taken bltting or something else
  1692. else if (m_trFrameAvg > 2*m_trRenderAvg) {
  1693. q.Type = Famine; // mainly other
  1694. } else {
  1695. q.Type = Flood; // mainly bltting
  1696. }
  1697. q.Proportion = 1000; // default
  1698. if (m_trFrameAvg<0) {
  1699. // leave it alone - we don't know enough
  1700. }
  1701. else if ( trLate> 0 ) {
  1702. // try to catch up over the next second
  1703. // We could be Really, REALLY late, but rendering all the frames
  1704. // anyway, just because it's so cheap.
  1705. q.Proportion = 1000 - (int)((trLate)/(UNITS/1000));
  1706. if (q.Proportion<500) {
  1707. q.Proportion = 500; // don't go daft. (could've been negative!)
  1708. } else {
  1709. }
  1710. } else if ( m_trWaitAvg>20000
  1711. && trLate<-20000
  1712. ){
  1713. // Go cautiously faster - aim at 2mSec wait.
  1714. if (m_trWaitAvg>=m_trFrameAvg) {
  1715. // This can happen because of some fudges.
  1716. // The waitAvg is how long we originally planned to wait
  1717. // The frameAvg is more honest.
  1718. // It means that we are spending a LOT of time waiting
  1719. q.Proportion = 2000; // double.
  1720. } else {
  1721. if (m_trFrameAvg+20000 > m_trWaitAvg) {
  1722. q.Proportion
  1723. = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg));
  1724. } else {
  1725. // We're apparently spending more than the whole frame time waiting.
  1726. // Assume that the averages are slightly out of kilter, but that we
  1727. // are indeed doing a lot of waiting. (This leg probably never
  1728. // happens, but the code avoids any potential divide by zero).
  1729. q.Proportion = 2000;
  1730. }
  1731. }
  1732. if (q.Proportion>2000) {
  1733. q.Proportion = 2000; // don't go crazy.
  1734. }
  1735. }
  1736. // Tell the supplier how late frames are when they get rendered
  1737. // That's how late we are now.
  1738. // If we are in directdraw mode then the guy upstream can see the drawing
  1739. // times and we'll just report on the start time. He can figure out any
  1740. // offset to apply. If we are in DIB Section mode then we will apply an
  1741. // extra offset which is half of our drawing time. This is usually small
  1742. // but can sometimes be the dominant effect. For this we will use the
  1743. // average drawing time rather than the last frame. If the last frame took
  1744. // a long time to draw and made us late, that's already in the lateness
  1745. // figure. We should not add it in again unless we expect the next frame
  1746. // to be the same. We don't, we expect the average to be a better shot.
  1747. // In direct draw mode the RenderAvg will be zero.
  1748. q.Late = trLate + m_trRenderAvg/2;
  1749. // log what we're doing
  1750. MSR_INTEGER(m_idQualityRate, q.Proportion);
  1751. MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 );
  1752. // A specific sink interface may be set through IPin
  1753. if (m_pQSink==NULL) {
  1754. // Get our input pin's peer. We send quality management messages
  1755. // to any nominated receiver of these things (set in the IPin
  1756. // interface), or else to our source filter.
  1757. IQualityControl *pQC = NULL;
  1758. IPin *pOutputPin = m_pInputPin->GetConnected();
  1759. ASSERT(pOutputPin != NULL);
  1760. // And get an AddRef'd quality control interface
  1761. hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC);
  1762. if (SUCCEEDED(hr)) {
  1763. m_pQSink = pQC;
  1764. }
  1765. }
  1766. if (m_pQSink) {
  1767. return m_pQSink->Notify(this,q);
  1768. }
  1769. return S_FALSE;
  1770. } // SendQuality
  1771. // We are called with a valid IMediaSample image to decide whether this is to
  1772. // be drawn or not. There must be a reference clock in operation.
  1773. // Return S_OK if it is to be drawn Now (as soon as possible)
  1774. // Return S_FALSE if it is to be drawn when it's due
  1775. // Return an error if we want to drop it
  1776. // m_nNormal=-1 indicates that we dropped the previous frame and so this
  1777. // one should be drawn early. Respect it and update it.
  1778. // Use current stream time plus a number of heuristics (detailed below)
  1779. // to make the decision
  1780. HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample,
  1781. __inout REFERENCE_TIME *ptrStart,
  1782. __inout REFERENCE_TIME *ptrEnd)
  1783. {
  1784. // Don't call us unless there's a clock interface to synchronise with
  1785. ASSERT(m_pClock);
  1786. MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits
  1787. MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits
  1788. // We lose a bit of time depending on the monitor type waiting for the next
  1789. // screen refresh. On average this might be about 8mSec - so it will be
  1790. // later than we think when the picture appears. To compensate a bit
  1791. // we bias the media samples by -8mSec i.e. 80000 UNITs.
  1792. // We don't ever make a stream time negative (call it paranoia)
  1793. if (*ptrStart>=80000) {
  1794. *ptrStart -= 80000;
  1795. *ptrEnd -= 80000; // bias stop to to retain valid frame duration
  1796. }
  1797. // Cache the time stamp now. We will want to compare what we did with what
  1798. // we started with (after making the monitor allowance).
  1799. m_trRememberStampForPerf = *ptrStart;
  1800. // Get reference times (current and late)
  1801. REFERENCE_TIME trRealStream; // the real time now expressed as stream time.
  1802. m_pClock->GetTime(&trRealStream);
  1803. #ifdef PERF
  1804. // While the reference clock is expensive:
  1805. // Remember the offset from timeGetTime and use that.
  1806. // This overflows all over the place, but when we subtract to get
  1807. // differences the overflows all cancel out.
  1808. m_llTimeOffset = trRealStream-timeGetTime()*10000;
  1809. #endif
  1810. trRealStream -= m_tStart; // convert to stream time (this is a reftime)
  1811. // We have to wory about two versions of "lateness". The truth, which we
  1812. // try to work out here and the one measured against m_trTarget which
  1813. // includes long term feedback. We report statistics against the truth
  1814. // but for operational decisions we work to the target.
  1815. // We use TimeDiff to make sure we get an integer because we
  1816. // may actually be late (or more likely early if there is a big time
  1817. // gap) by a very long time.
  1818. const int trTrueLate = TimeDiff(trRealStream - *ptrStart);
  1819. const int trLate = trTrueLate;
  1820. MSR_INTEGER(m_idSchLateTime, trTrueLate/10000);
  1821. // Send quality control messages upstream, measured against target
  1822. HRESULT hr = SendQuality(trLate, trRealStream);
  1823. // Note: the filter upstream is allowed to this FAIL meaning "you do it".
  1824. m_bSupplierHandlingQuality = (hr==S_OK);
  1825. // Decision time! Do we drop, draw when ready or draw immediately?
  1826. const int trDuration = (int)(*ptrEnd - *ptrStart);
  1827. {
  1828. // We need to see if the frame rate of the file has just changed.
  1829. // This would make comparing our previous frame rate with the current
  1830. // frame rate inefficent. Hang on a moment though. I've seen files
  1831. // where the frames vary between 33 and 34 mSec so as to average
  1832. // 30fps. A minor variation like that won't hurt us.
  1833. int t = m_trDuration/32;
  1834. if ( trDuration > m_trDuration+t
  1835. || trDuration < m_trDuration-t
  1836. ) {
  1837. // There's a major variation. Reset the average frame rate to
  1838. // exactly the current rate to disable decision 9002 for this frame,
  1839. // and remember the new rate.
  1840. m_trFrameAvg = trDuration;
  1841. m_trDuration = trDuration;
  1842. }
  1843. }
  1844. MSR_INTEGER(m_idEarliness, m_trEarliness/10000);
  1845. MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000);
  1846. MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000);
  1847. MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000);
  1848. MSR_INTEGER(m_idDuration, trDuration/10000);
  1849. #ifdef PERF
  1850. if (S_OK==pMediaSample->IsDiscontinuity()) {
  1851. MSR_INTEGER(m_idDecision, 9000);
  1852. }
  1853. #endif
  1854. // Control the graceful slide back from slow to fast machine mode.
  1855. // After a frame drop accept an early frame and set the earliness to here
  1856. // If this frame is already later than the earliness then slide it to here
  1857. // otherwise do the standard slide (reduce by about 12% per frame).
  1858. // Note: earliness is normally NEGATIVE
  1859. BOOL bJustDroppedFrame
  1860. = ( m_bSupplierHandlingQuality
  1861. // Can't use the pin sample properties because we might
  1862. // not be in Receive when we call this
  1863. && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one
  1864. )
  1865. || (m_nNormal==-1); // we just dropped one
  1866. // Set m_trEarliness (slide back from slow to fast machine mode)
  1867. if (trLate>0) {
  1868. m_trEarliness = 0; // we are no longer in fast machine mode at all!
  1869. } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) {
  1870. m_trEarliness = trLate; // Things have slipped of their own accord
  1871. } else {
  1872. m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide
  1873. }
  1874. // prepare the new wait average - but don't pollute the old one until
  1875. // we have finished with it.
  1876. int trWaitAvg;
  1877. {
  1878. // We never mix in a negative wait. This causes us to believe in fast machines
  1879. // slightly more.
  1880. int trL = trLate<0 ? -trLate : 0;
  1881. trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD;
  1882. }
  1883. int trFrame;
  1884. {
  1885. REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause!
  1886. if (tr>10000000) {
  1887. tr = 10000000; // 1 second - arbitrarily.
  1888. }
  1889. trFrame = int(tr);
  1890. }
  1891. // We will DRAW this frame IF...
  1892. if (
  1893. // ...the time we are spending drawing is a small fraction of the total
  1894. // observed inter-frame time so that dropping it won't help much.
  1895. (3*m_trRenderAvg <= m_trFrameAvg)
  1896. // ...or our supplier is NOT handling things and the next frame would
  1897. // be less timely than this one or our supplier CLAIMS to be handling
  1898. // things, and is now less than a full FOUR frames late.
  1899. || ( m_bSupplierHandlingQuality
  1900. ? (trLate <= trDuration*4)
  1901. : (trLate+trLate < trDuration)
  1902. )
  1903. // ...or we are on average waiting for over eight milliseconds then
  1904. // this may be just a glitch. Draw it and we'll hope to catch up.
  1905. || (m_trWaitAvg > 80000)
  1906. // ...or we haven't drawn an image for over a second. We will update
  1907. // the display, which stops the video looking hung.
  1908. // Do this regardless of how late this media sample is.
  1909. || ((trRealStream - m_trLastDraw) > UNITS)
  1910. ) {
  1911. HRESULT Result;
  1912. // We are going to play this frame. We may want to play it early.
  1913. // We will play it early if we think we are in slow machine mode.
  1914. // If we think we are NOT in slow machine mode, we will still play
  1915. // it early by m_trEarliness as this controls the graceful slide back.
  1916. // and in addition we aim at being m_trTarget late rather than "on time".
  1917. BOOL bPlayASAP = FALSE;
  1918. // we will play it AT ONCE (slow machine mode) if...
  1919. // ...we are playing catch-up
  1920. if ( bJustDroppedFrame) {
  1921. bPlayASAP = TRUE;
  1922. MSR_INTEGER(m_idDecision, 9001);
  1923. }
  1924. // ...or if we are running below the true frame rate
  1925. // exact comparisons are glitchy, for these measurements,
  1926. // so add an extra 5% or so
  1927. else if ( (m_trFrameAvg > trDuration + trDuration/16)
  1928. // It's possible to get into a state where we are losing ground, but
  1929. // are a very long way ahead. To avoid this or recover from it
  1930. // we refuse to play early by more than 10 frames.
  1931. && (trLate > - trDuration*10)
  1932. ){
  1933. bPlayASAP = TRUE;
  1934. MSR_INTEGER(m_idDecision, 9002);
  1935. }
  1936. #if 0
  1937. // ...or if we have been late and are less than one frame early
  1938. else if ( (trLate + trDuration > 0)
  1939. && (m_trWaitAvg<=20000)
  1940. ) {
  1941. bPlayASAP = TRUE;
  1942. MSR_INTEGER(m_idDecision, 9003);
  1943. }
  1944. #endif
  1945. // We will NOT play it at once if we are grossly early. On very slow frame
  1946. // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just
  1947. // because we got starved (for instance by the net) and dropped one frame
  1948. // some time or other. If we are more than 900mSec early, then wait.
  1949. if (trLate<-9000000) {
  1950. bPlayASAP = FALSE;
  1951. }
  1952. if (bPlayASAP) {
  1953. m_nNormal = 0;
  1954. MSR_INTEGER(m_idDecision, 0);
  1955. // When we are here, we are in slow-machine mode. trLate may well
  1956. // oscillate between negative and positive when the supplier is
  1957. // dropping frames to keep sync. We should not let that mislead
  1958. // us into thinking that we have as much as zero spare time!
  1959. // We just update with a zero wait.
  1960. m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD;
  1961. // Assume that we draw it immediately. Update inter-frame stats
  1962. m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD;
  1963. #ifndef PERF
  1964. // If this is NOT a perf build, then report what we know so far
  1965. // without looking at the clock any more. This assumes that we
  1966. // actually wait for exactly the time we hope to. It also reports
  1967. // how close we get to the manipulated time stamps that we now have
  1968. // rather than the ones we originally started with. It will
  1969. // therefore be a little optimistic. However it's fast.
  1970. PreparePerformanceData(trTrueLate, trFrame);
  1971. #endif
  1972. m_trLastDraw = trRealStream;
  1973. if (m_trEarliness > trLate) {
  1974. m_trEarliness = trLate; // if we are actually early, this is neg
  1975. }
  1976. Result = S_OK; // Draw it now
  1977. } else {
  1978. ++m_nNormal;
  1979. // Set the average frame rate to EXACTLY the ideal rate.
  1980. // If we are exiting slow-machine mode then we will have caught up
  1981. // and be running ahead, so as we slide back to exact timing we will
  1982. // have a longer than usual gap at this point. If we record this
  1983. // real gap then we'll think that we're running slow and go back
  1984. // into slow-machine mode and vever get it straight.
  1985. m_trFrameAvg = trDuration;
  1986. MSR_INTEGER(m_idDecision, 1);
  1987. // Play it early by m_trEarliness and by m_trTarget
  1988. {
  1989. int trE = m_trEarliness;
  1990. if (trE < -m_trFrameAvg) {
  1991. trE = -m_trFrameAvg;
  1992. }
  1993. *ptrStart += trE; // N.B. earliness is negative
  1994. }
  1995. int Delay = -trTrueLate;
  1996. Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait
  1997. m_trWaitAvg = trWaitAvg;
  1998. // Predict when it will actually be drawn and update frame stats
  1999. if (Result==S_FALSE) { // We are going to wait
  2000. trFrame = TimeDiff(*ptrStart-m_trLastDraw);
  2001. m_trLastDraw = *ptrStart;
  2002. } else {
  2003. // trFrame is already = trRealStream-m_trLastDraw;
  2004. m_trLastDraw = trRealStream;
  2005. }
  2006. #ifndef PERF
  2007. int iAccuracy;
  2008. if (Delay>0) {
  2009. // Report lateness based on when we intend to play it
  2010. iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf);
  2011. } else {
  2012. // Report lateness based on playing it *now*.
  2013. iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf;
  2014. }
  2015. PreparePerformanceData(iAccuracy, trFrame);
  2016. #endif
  2017. }
  2018. return Result;
  2019. }
  2020. // We are going to drop this frame!
  2021. // Of course in DirectDraw mode the guy upstream may draw it anyway.
  2022. // This will probably give a large negative wack to the wait avg.
  2023. m_trWaitAvg = trWaitAvg;
  2024. #ifdef PERF
  2025. // Respect registry setting - debug only!
  2026. if (m_bDrawLateFrames) {
  2027. return S_OK; // draw it when it's ready
  2028. } // even though it's late.
  2029. #endif
  2030. // We are going to drop this frame so draw the next one early
  2031. // n.b. if the supplier is doing direct draw then he may draw it anyway
  2032. // but he's doing something funny to arrive here in that case.
  2033. MSR_INTEGER(m_idDecision, 2);
  2034. m_nNormal = -1;
  2035. return E_FAIL; // drop it
  2036. } // ShouldDrawSampleNow
  2037. // NOTE we're called by both the window thread and the source filter thread
  2038. // so we have to be protected by a critical section (locked before called)
  2039. // Also, when the window thread gets signalled to render an image, it always
  2040. // does so regardless of how late it is. All the degradation is done when we
  2041. // are scheduling the next sample to be drawn. Hence when we start an advise
  2042. // link to draw a sample, that sample's time will always become the last one
  2043. // drawn - unless of course we stop streaming in which case we cancel links
  2044. BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample)
  2045. {
  2046. // We override ShouldDrawSampleNow to add quality management
  2047. BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample);
  2048. if (bDrawImage == FALSE) {
  2049. ++m_cFramesDropped;
  2050. return FALSE;
  2051. }
  2052. // m_cFramesDrawn must NOT be updated here. It has to be updated
  2053. // in RecordFrameLateness at the same time as the other statistics.
  2054. return TRUE;
  2055. }
  2056. // Implementation of IQualProp interface needed to support the property page
  2057. // This is how the property page gets the data out of the scheduler. We are
  2058. // passed into the constructor the owning object in the COM sense, this will
  2059. // either be the video renderer or an external IUnknown if we're aggregated.
  2060. // We initialise our CUnknown base class with this interface pointer. Then
  2061. // all we have to do is to override NonDelegatingQueryInterface to expose
  2062. // our IQualProp interface. The AddRef and Release are handled automatically
  2063. // by the base class and will be passed on to the appropriate outer object
  2064. STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(__out int *pcFramesDropped)
  2065. {
  2066. CheckPointer(pcFramesDropped,E_POINTER);
  2067. CAutoLock cVideoLock(&m_InterfaceLock);
  2068. *pcFramesDropped = m_cFramesDropped;
  2069. return NOERROR;
  2070. } // get_FramesDroppedInRenderer
  2071. // Set *pcFramesDrawn to the number of frames drawn since
  2072. // streaming started.
  2073. STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn)
  2074. {
  2075. CheckPointer(pcFramesDrawn,E_POINTER);
  2076. CAutoLock cVideoLock(&m_InterfaceLock);
  2077. *pcFramesDrawn = m_cFramesDrawn;
  2078. return NOERROR;
  2079. } // get_FramesDrawn
  2080. // Set iAvgFrameRate to the frames per hundred secs since
  2081. // streaming started. 0 otherwise.
  2082. STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate)
  2083. {
  2084. CheckPointer(piAvgFrameRate,E_POINTER);
  2085. CAutoLock cVideoLock(&m_InterfaceLock);
  2086. int t;
  2087. if (m_bStreaming) {
  2088. t = timeGetTime()-m_tStreamingStart;
  2089. } else {
  2090. t = m_tStreamingStart;
  2091. }
  2092. if (t<=0) {
  2093. *piAvgFrameRate = 0;
  2094. ASSERT(m_cFramesDrawn == 0);
  2095. } else {
  2096. // i is frames per hundred seconds
  2097. *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t);
  2098. }
  2099. return NOERROR;
  2100. } // get_AvgFrameRate
  2101. // Set *piAvg to the average sync offset since streaming started
  2102. // in mSec. The sync offset is the time in mSec between when the frame
  2103. // should have been drawn and when the frame was actually drawn.
  2104. STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset(__out int *piAvg)
  2105. {
  2106. CheckPointer(piAvg,E_POINTER);
  2107. CAutoLock cVideoLock(&m_InterfaceLock);
  2108. if (NULL==m_pClock) {
  2109. *piAvg = 0;
  2110. return NOERROR;
  2111. }
  2112. // Note that we didn't gather the stats on the first frame
  2113. // so we use m_cFramesDrawn-1 here
  2114. if (m_cFramesDrawn<=1) {
  2115. *piAvg = 0;
  2116. } else {
  2117. *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1));
  2118. }
  2119. return NOERROR;
  2120. } // get_AvgSyncOffset
  2121. // To avoid dragging in the maths library - a cheap
  2122. // approximate integer square root.
  2123. // We do this by getting a starting guess which is between 1
  2124. // and 2 times too large, followed by THREE iterations of
  2125. // Newton Raphson. (That will give accuracy to the nearest mSec
  2126. // for the range in question - roughly 0..1000)
  2127. //
  2128. // It would be faster to use a linear interpolation and ONE NR, but
  2129. // who cares. If anyone does - the best linear interpolation is
  2130. // to approximates sqrt(x) by
  2131. // y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1))
  2132. // 0r y = x*0.41421 + 0.59467
  2133. // This minimises the maximal error in the range in question.
  2134. // (error is about +0.008883 and then one NR will give error .0000something
  2135. // (Of course these are integers, so you can't just multiply by 0.41421
  2136. // you'd have to do some sort of MulDiv).
  2137. // Anyone wanna check my maths? (This is only for a property display!)
  2138. int isqrt(int x)
  2139. {
  2140. int s = 1;
  2141. // Make s an initial guess for sqrt(x)
  2142. if (x > 0x40000000) {
  2143. s = 0x8000; // prevent any conceivable closed loop
  2144. } else {
  2145. while (s*s<x) { // loop cannot possible go more than 31 times
  2146. s = 2*s; // normally it goes about 6 times
  2147. }
  2148. // Three NR iterations.
  2149. if (x==0) {
  2150. s= 0; // Wouldn't it be tragic to divide by zero whenever our
  2151. // accuracy was perfect!
  2152. } else {
  2153. s = (s*s+x)/(2*s);
  2154. if (s>=0) s = (s*s+x)/(2*s);
  2155. if (s>=0) s = (s*s+x)/(2*s);
  2156. }
  2157. }
  2158. return s;
  2159. }
  2160. //
  2161. // Do estimates for standard deviations for per-frame
  2162. // statistics
  2163. //
  2164. HRESULT CBaseVideoRenderer::GetStdDev(
  2165. int nSamples,
  2166. __out int *piResult,
  2167. LONGLONG llSumSq,
  2168. LONGLONG iTot
  2169. )
  2170. {
  2171. CheckPointer(piResult,E_POINTER);
  2172. CAutoLock cVideoLock(&m_InterfaceLock);
  2173. if (NULL==m_pClock) {
  2174. *piResult = 0;
  2175. return NOERROR;
  2176. }
  2177. // If S is the Sum of the Squares of observations and
  2178. // T the Total (i.e. sum) of the observations and there were
  2179. // N observations, then an estimate of the standard deviation is
  2180. // sqrt( (S - T**2/N) / (N-1) )
  2181. if (nSamples<=1) {
  2182. *piResult = 0;
  2183. } else {
  2184. LONGLONG x;
  2185. // First frames have invalid stamps, so we get no stats for them
  2186. // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1
  2187. // so we use m_cFramesDrawn-1 here
  2188. x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0);
  2189. x = x / (nSamples-1);
  2190. ASSERT(x>=0);
  2191. *piResult = isqrt((LONG)x);
  2192. }
  2193. return NOERROR;
  2194. }
  2195. // Set *piDev to the standard deviation in mSec of the sync offset
  2196. // of each frame since streaming started.
  2197. STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset(__out int *piDev)
  2198. {
  2199. // First frames have invalid stamps, so we get no stats for them
  2200. // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1
  2201. return GetStdDev(m_cFramesDrawn - 1,
  2202. piDev,
  2203. m_iSumSqAcc,
  2204. m_iTotAcc);
  2205. } // get_DevSyncOffset
  2206. // Set *piJitter to the standard deviation in mSec of the inter-frame time
  2207. // of frames since streaming started.
  2208. STDMETHODIMP CBaseVideoRenderer::get_Jitter(__out int *piJitter)
  2209. {
  2210. // First frames have invalid stamps, so we get no stats for them
  2211. // So second frame gives invalid inter-frame time
  2212. // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2
  2213. return GetStdDev(m_cFramesDrawn - 2,
  2214. piJitter,
  2215. m_iSumSqFrameTime,
  2216. m_iSumFrameTime);
  2217. } // get_Jitter
  2218. // Overidden to return our IQualProp interface
  2219. STDMETHODIMP
  2220. CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv)
  2221. {
  2222. // We return IQualProp and delegate everything else
  2223. if (riid == IID_IQualProp) {
  2224. return GetInterface( (IQualProp *)this, ppv);
  2225. } else if (riid == IID_IQualityControl) {
  2226. return GetInterface( (IQualityControl *)this, ppv);
  2227. }
  2228. return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv);
  2229. }
  2230. // Override JoinFilterGraph so that, just before leaving
  2231. // the graph we can send an EC_WINDOW_DESTROYED event
  2232. STDMETHODIMP
  2233. CBaseVideoRenderer::JoinFilterGraph(__inout_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName)
  2234. {
  2235. // Since we send EC_ACTIVATE, we also need to ensure
  2236. // we send EC_WINDOW_DESTROYED or the resource manager may be
  2237. // holding us as a focus object
  2238. if (!pGraph && m_pGraph) {
  2239. // We were in a graph and now we're not
  2240. // Do this properly in case we are aggregated
  2241. IBaseFilter* pFilter = this;
  2242. NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0);
  2243. }
  2244. return CBaseFilter::JoinFilterGraph(pGraph, pName);
  2245. }
  2246. // This removes a large number of level 4 warnings from the
  2247. // Microsoft compiler which in this case are not very useful
  2248. #pragma warning(disable: 4514)
  2249. #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */