AJA NTV2 SDK  17.6.0.2675
NTV2 SDK 17.6.0.2675
amfilter.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // File: AMFilter.cpp
3 //
4 // Desc: DirectShow base classes - implements class hierarchy for streams
5 // architecture.
6 //
7 // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
9 
10 
11 //=====================================================================
12 //=====================================================================
13 // The following classes are declared in this header:
14 //
15 //
16 // CBaseMediaFilter Basic IMediaFilter support (abstract class)
17 // CBaseFilter Support for IBaseFilter (incl. IMediaFilter)
18 // CEnumPins Enumerate input and output pins
19 // CEnumMediaTypes Enumerate the preferred pin formats
20 // CBasePin Abstract base class for IPin interface
21 // CBaseOutputPin Adds data provider member functions
22 // CBaseInputPin Implements IMemInputPin interface
23 // CMediaSample Basic transport unit for IMemInputPin
24 // CBaseAllocator General list guff for most allocators
25 // CMemAllocator Implements memory buffer allocation
26 //
27 //=====================================================================
28 //=====================================================================
29 
30 #include <streams.h>
31 #include <strsafe.h>
32 
33 #ifdef DXMPERF
34 #include "dxmperf.h"
35 #endif // DXMPERF
36 
37 
38 //=====================================================================
39 // Helpers
40 //=====================================================================
41 STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator)
42 {
43  return CoCreateInstance(CLSID_MemoryAllocator,
44  0,
45  CLSCTX_INPROC_SERVER,
46  IID_IMemAllocator,
47  (void **)ppAllocator);
48 }
49 
50 // Put this one here rather than in ctlutil.cpp to avoid linking
51 // anything brought in by ctlutil.cpp
53  __in_opt LPUNKNOWN pAgg,
54  BOOL bRenderer,
55  IPin *pPin,
56  __deref_out IUnknown **ppPassThru
57 )
58 {
59  *ppPassThru = NULL;
60  IUnknown *pUnkSeek;
61  HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru,
62  pAgg,
63  CLSCTX_INPROC_SERVER,
64  IID_IUnknown,
65  (void **)&pUnkSeek
66  );
67  if (FAILED(hr)) {
68  return hr;
69  }
70 
71  ISeekingPassThru *pPassThru;
72  hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru);
73  if (FAILED(hr)) {
74  pUnkSeek->Release();
75  return hr;
76  }
77  hr = pPassThru->Init(bRenderer, pPin);
78  pPassThru->Release();
79  if (FAILED(hr)) {
80  pUnkSeek->Release();
81  return hr;
82  }
83  *ppPassThru = pUnkSeek;
84  return S_OK;
85 }
86 
87 
88 
89 #define CONNECT_TRACE_LEVEL 3
90 
91 //=====================================================================
92 //=====================================================================
93 // Implements CBaseMediaFilter
94 //=====================================================================
95 //=====================================================================
96 
97 
98 /* Constructor */
99 
101  __inout_opt LPUNKNOWN pUnk,
102  __in CCritSec *pLock,
103  REFCLSID clsid) :
104  CUnknown(pName, pUnk),
105  m_pLock(pLock),
106  m_clsid(clsid),
107  m_State(State_Stopped),
108  m_pClock(NULL)
109 {
110 }
111 
112 
113 /* Destructor */
114 
116 {
117  // must be stopped, but can't call Stop here since
118  // our critsec has been destroyed.
119 
120  /* Release any clock we were using */
121 
122  if (m_pClock) {
123  m_pClock->Release();
124  m_pClock = NULL;
125  }
126 }
127 
128 
129 /* Override this to say what interfaces we support and where */
130 
131 STDMETHODIMP
133  REFIID riid,
134  __deref_out void ** ppv)
135 {
136  if (riid == IID_IMediaFilter) {
137  return GetInterface((IMediaFilter *) this, ppv);
138  } else if (riid == IID_IPersist) {
139  return GetInterface((IPersist *) this, ppv);
140  } else {
142  }
143 }
144 
145 /* Return the filter's clsid */
146 STDMETHODIMP
147 CBaseMediaFilter::GetClassID(__out CLSID *pClsID)
148 {
149  CheckPointer(pClsID,E_POINTER);
150  ValidateReadWritePtr(pClsID,sizeof(CLSID));
151  *pClsID = m_clsid;
152  return NOERROR;
153 }
154 
155 /* Override this if your state changes are not done synchronously */
156 
157 STDMETHODIMP
158 CBaseMediaFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State)
159 {
160  UNREFERENCED_PARAMETER(dwMSecs);
161  CheckPointer(State,E_POINTER);
162  ValidateReadWritePtr(State,sizeof(FILTER_STATE));
163 
164  *State = m_State;
165  return S_OK;
166 }
167 
168 
169 /* Set the clock we will use for synchronisation */
170 
171 STDMETHODIMP
172 CBaseMediaFilter::SetSyncSource(__inout_opt IReferenceClock *pClock)
173 {
174  CAutoLock cObjectLock(m_pLock);
175 
176  // Ensure the new one does not go away - even if the same as the old
177  if (pClock) {
178  pClock->AddRef();
179  }
180 
181  // if we have a clock, release it
182  if (m_pClock) {
183  m_pClock->Release();
184  }
185 
186  // Set the new reference clock (might be NULL)
187  // Should we query it to ensure it is a clock? Consider for a debug build.
188  m_pClock = pClock;
189 
190  return NOERROR;
191 }
192 
193 /* Return the clock we are using for synchronisation */
194 STDMETHODIMP
195 CBaseMediaFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock)
196 {
197  CheckPointer(pClock,E_POINTER);
198  ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
199  CAutoLock cObjectLock(m_pLock);
200 
201  if (m_pClock) {
202  // returning an interface... addref it...
203  m_pClock->AddRef();
204  }
205  *pClock = (IReferenceClock*)m_pClock;
206  return NOERROR;
207 }
208 
209 
210 /* Put the filter into a stopped state */
211 
212 STDMETHODIMP
214 {
215  CAutoLock cObjectLock(m_pLock);
216 
217  m_State = State_Stopped;
218  return S_OK;
219 }
220 
221 
222 /* Put the filter into a paused state */
223 
224 STDMETHODIMP
226 {
227  CAutoLock cObjectLock(m_pLock);
228 
229  m_State = State_Paused;
230  return S_OK;
231 }
232 
233 
234 // Put the filter into a running state.
235 
236 // The time parameter is the offset to be added to the samples'
237 // stream time to get the reference time at which they should be presented.
238 //
239 // you can either add these two and compare it against the reference clock,
240 // or you can call CBaseMediaFilter::StreamTime and compare that against
241 // the sample timestamp.
242 
243 STDMETHODIMP
244 CBaseMediaFilter::Run(REFERENCE_TIME tStart)
245 {
246  CAutoLock cObjectLock(m_pLock);
247 
248  // remember the stream time offset
249  m_tStart = tStart;
250 
251  if (m_State == State_Stopped){
252  HRESULT hr = Pause();
253 
254  if (FAILED(hr)) {
255  return hr;
256  }
257  }
258  m_State = State_Running;
259  return S_OK;
260 }
261 
262 
263 //
264 // return the current stream time - samples with start timestamps of this
265 // time or before should be rendered by now
266 HRESULT
268 {
269  // Caller must lock for synchronization
270  // We can't grab the filter lock because we want to be able to call
271  // this from worker threads without deadlocking
272 
273  if (m_pClock == NULL) {
274  return VFW_E_NO_CLOCK;
275  }
276 
277  // get the current reference time
278  HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
279  if (FAILED(hr)) {
280  return hr;
281  }
282 
283  // subtract the stream offset to get stream time
284  rtStream -= m_tStart;
285 
286  return S_OK;
287 }
288 
289 
290 //=====================================================================
291 //=====================================================================
292 // Implements CBaseFilter
293 //=====================================================================
294 //=====================================================================
295 
296 
297 /* Override this to say what interfaces we support and where */
298 
300  __deref_out void **ppv)
301 {
302  /* Do we have this interface */
303 
304  if (riid == IID_IBaseFilter) {
305  return GetInterface((IBaseFilter *) this, ppv);
306  } else if (riid == IID_IMediaFilter) {
307  return GetInterface((IMediaFilter *) this, ppv);
308  } else if (riid == IID_IPersist) {
309  return GetInterface((IPersist *) this, ppv);
310  } else if (riid == IID_IAMovieSetup) {
311  return GetInterface((IAMovieSetup *) this, ppv);
312  } else {
314  }
315 }
316 
317 #ifdef DEBUG
318 STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease()
319 {
320  if (m_cRef == 1) {
321  KASSERT(m_pGraph == NULL);
322  }
323  return CUnknown::NonDelegatingRelease();
324 }
325 #endif
326 
327 
328 /* Constructor */
329 
331  __inout_opt LPUNKNOWN pUnk,
332  __in CCritSec *pLock,
333  REFCLSID clsid) :
334  CUnknown( pName, pUnk ),
335  m_pLock(pLock),
336  m_clsid(clsid),
337  m_State(State_Stopped),
338  m_pClock(NULL),
339  m_pGraph(NULL),
340  m_pSink(NULL),
341  m_pName(NULL),
342  m_PinVersion(1)
343 {
344 #ifdef DXMPERF
345  PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this );
346 #endif // DXMPERF
347 
348  ASSERT(pLock != NULL);
349 }
350 
351 /* Passes in a redundant HRESULT argument */
352 
354  __in_opt LPUNKNOWN pUnk,
355  __in CCritSec *pLock,
356  REFCLSID clsid,
357  __inout HRESULT *phr) :
358  CUnknown( pName, pUnk ),
359  m_pLock(pLock),
360  m_clsid(clsid),
361  m_State(State_Stopped),
362  m_pClock(NULL),
363  m_pGraph(NULL),
364  m_pSink(NULL),
365  m_pName(NULL),
366  m_PinVersion(1)
367 {
368 #ifdef DXMPERF
369  PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this );
370 #endif // DXMPERF
371 
372  ASSERT(pLock != NULL);
373  UNREFERENCED_PARAMETER(phr);
374 }
375 
376 #ifdef UNICODE
377 CBaseFilter::CBaseFilter(__in_opt LPCSTR pName,
378  __in_opt LPUNKNOWN pUnk,
379  __in CCritSec *pLock,
380  REFCLSID clsid) :
381  CUnknown( pName, pUnk ),
382  m_pLock(pLock),
383  m_clsid(clsid),
384  m_State(State_Stopped),
385  m_pClock(NULL),
386  m_pGraph(NULL),
387  m_pSink(NULL),
388  m_pName(NULL),
389  m_PinVersion(1)
390 {
391 #ifdef DXMPERF
392  PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this );
393 #endif // DXMPERF
394 
395  ASSERT(pLock != NULL);
396 }
397 CBaseFilter::CBaseFilter(__in_opt LPCSTR pName,
398  __in_opt LPUNKNOWN pUnk,
399  __in CCritSec *pLock,
400  REFCLSID clsid,
401  __inout HRESULT *phr) :
402  CUnknown( pName, pUnk ),
403  m_pLock(pLock),
404  m_clsid(clsid),
405  m_State(State_Stopped),
406  m_pClock(NULL),
407  m_pGraph(NULL),
408  m_pSink(NULL),
409  m_pName(NULL),
410  m_PinVersion(1)
411 {
412 #ifdef DXMPERF
413  PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this );
414 #endif // DXMPERF
415 
416  ASSERT(pLock != NULL);
417  UNREFERENCED_PARAMETER(phr);
418 }
419 #endif
420 
421 /* Destructor */
422 
424 {
425 #ifdef DXMPERF
426  PERFLOG_DTOR( L"CBaseFilter", (IBaseFilter *) this );
427 #endif // DXMPERF
428 
429  // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink
430  // When we did we had the circular reference problem. Nothing would go away.
431 
432  delete[] m_pName;
433 
434  // must be stopped, but can't call Stop here since
435  // our critsec has been destroyed.
436 
437  /* Release any clock we were using */
438  if (m_pClock) {
439  m_pClock->Release();
440  m_pClock = NULL;
441  }
442 }
443 
444 /* Return the filter's clsid */
445 STDMETHODIMP
446 CBaseFilter::GetClassID(__out CLSID *pClsID)
447 {
448  CheckPointer(pClsID,E_POINTER);
449  ValidateReadWritePtr(pClsID,sizeof(CLSID));
450  *pClsID = m_clsid;
451  return NOERROR;
452 }
453 
454 /* Override this if your state changes are not done synchronously */
455 STDMETHODIMP
456 CBaseFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State)
457 {
458  UNREFERENCED_PARAMETER(dwMSecs);
459  CheckPointer(State,E_POINTER);
460  ValidateReadWritePtr(State,sizeof(FILTER_STATE));
461 
462  *State = m_State;
463  return S_OK;
464 }
465 
466 
467 /* Set the clock we will use for synchronisation */
468 
469 STDMETHODIMP
470 CBaseFilter::SetSyncSource(__in_opt IReferenceClock *pClock)
471 {
472  CAutoLock cObjectLock(m_pLock);
473 
474  // Ensure the new one does not go away - even if the same as the old
475  if (pClock) {
476  pClock->AddRef();
477  }
478 
479  // if we have a clock, release it
480  if (m_pClock) {
481  m_pClock->Release();
482  }
483 
484  // Set the new reference clock (might be NULL)
485  // Should we query it to ensure it is a clock? Consider for a debug build.
486  m_pClock = pClock;
487 
488  return NOERROR;
489 }
490 
491 /* Return the clock we are using for synchronisation */
492 STDMETHODIMP
493 CBaseFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock)
494 {
495  CheckPointer(pClock,E_POINTER);
496  ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
497  CAutoLock cObjectLock(m_pLock);
498 
499  if (m_pClock) {
500  // returning an interface... addref it...
501  m_pClock->AddRef();
502  }
503  *pClock = (IReferenceClock*)m_pClock;
504  return NOERROR;
505 }
506 
507 
508 
509 // override CBaseMediaFilter Stop method, to deactivate any pins this
510 // filter has.
511 STDMETHODIMP
513 {
514  CAutoLock cObjectLock(m_pLock);
515  HRESULT hr = NOERROR;
516 
517  // notify all pins of the state change
518  if (m_State != State_Stopped) {
519  int cPins = GetPinCount();
520  for (int c = 0; c < cPins; c++) {
521 
522  CBasePin *pPin = GetPin(c);
523  if (NULL == pPin) {
524  break;
525  }
526 
527  // Disconnected pins are not activated - this saves pins worrying
528  // about this state themselves. We ignore the return code to make
529  // sure everyone is inactivated regardless. The base input pin
530  // class can return an error if it has no allocator but Stop can
531  // be used to resync the graph state after something has gone bad
532 
533  if (pPin->IsConnected()) {
534  HRESULT hrTmp = pPin->Inactive();
535  if (FAILED(hrTmp) && SUCCEEDED(hr)) {
536  hr = hrTmp;
537  }
538  }
539  }
540  }
541 
542 #ifdef DXMPERF
543  PERFLOG_STOP( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State );
544 #endif // DXMPERF
545 
546  m_State = State_Stopped;
547  return hr;
548 }
549 
550 
551 // override CBaseMediaFilter Pause method to activate any pins
552 // this filter has (also called from Run)
553 
554 STDMETHODIMP
556 {
557  CAutoLock cObjectLock(m_pLock);
558 
559  // notify all pins of the change to active state
560  if (m_State == State_Stopped) {
561  int cPins = GetPinCount();
562  for (int c = 0; c < cPins; c++) {
563 
564  CBasePin *pPin = GetPin(c);
565  if (NULL == pPin) {
566  break;
567  }
568 
569  // Disconnected pins are not activated - this saves pins
570  // worrying about this state themselves
571 
572  if (pPin->IsConnected()) {
573  HRESULT hr = pPin->Active();
574  if (FAILED(hr)) {
575  return hr;
576  }
577  }
578  }
579  }
580 
581 
582 #ifdef DXMPERF
583  PERFLOG_PAUSE( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State );
584 #endif // DXMPERF
585 
586  m_State = State_Paused;
587  return S_OK;
588 }
589 
590 // Put the filter into a running state.
591 
592 // The time parameter is the offset to be added to the samples'
593 // stream time to get the reference time at which they should be presented.
594 //
595 // you can either add these two and compare it against the reference clock,
596 // or you can call CBaseFilter::StreamTime and compare that against
597 // the sample timestamp.
598 
599 STDMETHODIMP
600 CBaseFilter::Run(REFERENCE_TIME tStart)
601 {
602  CAutoLock cObjectLock(m_pLock);
603 
604  // remember the stream time offset
605  m_tStart = tStart;
606 
607  if (m_State == State_Stopped){
608  HRESULT hr = Pause();
609 
610  if (FAILED(hr)) {
611  return hr;
612  }
613  }
614  // notify all pins of the change to active state
615  if (m_State != State_Running) {
616  int cPins = GetPinCount();
617  for (int c = 0; c < cPins; c++) {
618 
619  CBasePin *pPin = GetPin(c);
620  if (NULL == pPin) {
621  break;
622  }
623 
624  // Disconnected pins are not activated - this saves pins
625  // worrying about this state themselves
626 
627  if (pPin->IsConnected()) {
628  HRESULT hr = pPin->Run(tStart);
629  if (FAILED(hr)) {
630  return hr;
631  }
632  }
633  }
634  }
635 
636 #ifdef DXMPERF
637  PERFLOG_RUN( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, tStart, m_State );
638 #endif // DXMPERF
639 
640  m_State = State_Running;
641  return S_OK;
642 }
643 
644 //
645 // return the current stream time - samples with start timestamps of this
646 // time or before should be rendered by now
647 HRESULT
649 {
650  // Caller must lock for synchronization
651  // We can't grab the filter lock because we want to be able to call
652  // this from worker threads without deadlocking
653 
654  if (m_pClock == NULL) {
655  return VFW_E_NO_CLOCK;
656  }
657 
658  // get the current reference time
659  HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
660  if (FAILED(hr)) {
661  return hr;
662  }
663 
664  // subtract the stream offset to get stream time
665  rtStream -= m_tStart;
666 
667  return S_OK;
668 }
669 
670 
671 /* Create an enumerator for the pins attached to this filter */
672 
673 STDMETHODIMP
674 CBaseFilter::EnumPins(__deref_out IEnumPins **ppEnum)
675 {
676  CheckPointer(ppEnum,E_POINTER);
677  ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
678 
679  /* Create a new ref counted enumerator */
680 
681  *ppEnum = new CEnumPins(this,
682  NULL);
683 
684  return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
685 }
686 
687 
688 // default behaviour of FindPin is to assume pins are named
689 // by their pin names
690 STDMETHODIMP
692  LPCWSTR Id,
693  __deref_out IPin ** ppPin
694 )
695 {
696  CheckPointer(ppPin,E_POINTER);
697  ValidateReadWritePtr(ppPin,sizeof(IPin *));
698 
699  // We're going to search the pin list so maintain integrity
700  CAutoLock lck(m_pLock);
701  int iCount = GetPinCount();
702  for (int i = 0; i < iCount; i++) {
703  CBasePin *pPin = GetPin(i);
704  if (NULL == pPin) {
705  break;
706  }
707 
708  if (0 == lstrcmpW(pPin->Name(), Id)) {
709  // Found one that matches
710  //
711  // AddRef() and return it
712  *ppPin = pPin;
713  pPin->AddRef();
714  return S_OK;
715  }
716  }
717  *ppPin = NULL;
718  return VFW_E_NOT_FOUND;
719 }
720 
721 /* Return information about this filter */
722 
723 STDMETHODIMP
724 CBaseFilter::QueryFilterInfo(__out FILTER_INFO * pInfo)
725 {
726  CheckPointer(pInfo,E_POINTER);
727  ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO));
728 
729  if (m_pName) {
730  (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName);
731  } else {
732  pInfo->achName[0] = L'\0';
733  }
734  pInfo->pGraph = m_pGraph;
735  if (m_pGraph)
736  m_pGraph->AddRef();
737  return NOERROR;
738 }
739 
740 
741 /* Provide the filter with a filter graph */
742 
743 STDMETHODIMP
745  __inout_opt IFilterGraph * pGraph,
746  __in_opt LPCWSTR pName)
747 {
748  CAutoLock cObjectLock(m_pLock);
749 
750  // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink)
751 
752  m_pGraph = pGraph;
753  if (m_pGraph) {
754  HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink,
755  (void**) &m_pSink);
756  if (FAILED(hr)) {
757  ASSERT(m_pSink == NULL);
758  }
759  else m_pSink->Release(); // we do NOT keep a reference on it.
760  } else {
761  // if graph pointer is null, then we should
762  // also release the IMediaEventSink on the same object - we don't
763  // refcount it, so just set it to null
764  m_pSink = NULL;
765  }
766 
767 
768  if (m_pName) {
769  delete[] m_pName;
770  m_pName = NULL;
771  }
772 
773  if (pName) {
774  size_t namelen;
775  HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &namelen);
776  if (FAILED(hr)) {
777  return hr;
778  }
779  m_pName = new WCHAR[namelen + 1];
780  if (m_pName) {
781  (void)StringCchCopyW(m_pName, namelen + 1, pName);
782  } else {
783  return E_OUTOFMEMORY;
784  }
785  }
786 
787 #ifdef DXMPERF
788  PERFLOG_JOINGRAPH( m_pName ? m_pName : L"CBaseFilter",(IBaseFilter *) this, pGraph );
789 #endif // DXMPERF
790 
791  return NOERROR;
792 }
793 
794 
795 // return a Vendor information string. Optional - may return E_NOTIMPL.
796 // memory returned should be freed using CoTaskMemFree
797 // default implementation returns E_NOTIMPL
798 STDMETHODIMP
800  __deref_out LPWSTR* pVendorInfo)
801 {
802  UNREFERENCED_PARAMETER(pVendorInfo);
803  return E_NOTIMPL;
804 }
805 
806 
807 // send an event notification to the filter graph if we know about it.
808 // returns S_OK if delivered, S_FALSE if the filter graph does not sink
809 // events, or an error otherwise.
810 HRESULT
812  long EventCode,
813  LONG_PTR EventParam1,
814  LONG_PTR EventParam2)
815 {
816  // Snapshot so we don't have to lock up
817  IMediaEventSink *pSink = m_pSink;
818  if (pSink) {
819  if (EC_COMPLETE == EventCode) {
820  EventParam2 = (LONG_PTR)(IBaseFilter*)this;
821  }
822 
823  return pSink->Notify(EventCode, EventParam1, EventParam2);
824  } else {
825  return E_NOTIMPL;
826  }
827 }
828 
829 // Request reconnect
830 // pPin is the pin to reconnect
831 // pmt is the type to reconnect with - can be NULL
832 // Calls ReconnectEx on the filter graph
833 HRESULT
835  IPin *pPin,
836  __in_opt AM_MEDIA_TYPE const *pmt
837 )
838 {
839  IFilterGraph2 *pGraph2;
840  if (m_pGraph != NULL) {
841  HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2);
842  if (SUCCEEDED(hr)) {
843  hr = pGraph2->ReconnectEx(pPin, pmt);
844  pGraph2->Release();
845  return hr;
846  } else {
847  return m_pGraph->Reconnect(pPin);
848  }
849  } else {
850  return E_NOINTERFACE;
851  }
852 }
853 
854 
855 
856 /* This is the same idea as the media type version does for type enumeration
857  on pins but for the list of pins available. So if the list of pins you
858  provide changes dynamically then either override this virtual function
859  to provide the version number, or more simply call IncrementPinVersion */
860 
862 {
863  return m_PinVersion;
864 }
865 
866 
867 /* Increment the current pin version cookie */
868 
870 {
871  InterlockedIncrement(&m_PinVersion);
872 }
873 
874 /* register filter */
875 
876 STDMETHODIMP CBaseFilter::Register()
877 {
878  // get setup data, if it exists
879  //
880  LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
881 
882  // check we've got data
883  //
884  if( NULL == psetupdata ) return S_FALSE;
885 
886  // init is ref counted so call just in case
887  // we're being called cold.
888  //
889  HRESULT hr = CoInitialize( (LPVOID)NULL );
890  ASSERT( SUCCEEDED(hr) );
891 
892  // get hold of IFilterMapper
893  //
894  IFilterMapper *pIFM;
895  hr = CoCreateInstance( CLSID_FilterMapper
896  , NULL
897  , CLSCTX_INPROC_SERVER
898  , IID_IFilterMapper
899  , (void **)&pIFM );
900  if( SUCCEEDED(hr) )
901  {
902  hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE );
903  pIFM->Release();
904  }
905 
906  // and clear up
907  //
908  CoFreeUnusedLibraries();
909  CoUninitialize();
910 
911  return NOERROR;
912 }
913 
914 
915 /* unregister filter */
916 
918 {
919  // get setup data, if it exists
920  //
921  LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
922 
923  // check we've got data
924  //
925  if( NULL == psetupdata ) return S_FALSE;
926 
927  // OLE init is ref counted so call
928  // just in case we're being called cold.
929  //
930  HRESULT hr = CoInitialize( (LPVOID)NULL );
931  ASSERT( SUCCEEDED(hr) );
932 
933  // get hold of IFilterMapper
934  //
935  IFilterMapper *pIFM;
936  hr = CoCreateInstance( CLSID_FilterMapper
937  , NULL
938  , CLSCTX_INPROC_SERVER
939  , IID_IFilterMapper
940  , (void **)&pIFM );
941  if( SUCCEEDED(hr) )
942  {
943  hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE );
944 
945  // release interface
946  //
947  pIFM->Release();
948  }
949 
950  // clear up
951  //
952  CoFreeUnusedLibraries();
953  CoUninitialize();
954 
955  // handle one acceptable "error" - that
956  // of filter not being registered!
957  // (couldn't find a suitable #define'd
958  // name for the error!)
959  //
960  if( 0x80070002 == hr)
961  return NOERROR;
962  else
963  return hr;
964 }
965 
966 
967 //=====================================================================
968 //=====================================================================
969 // Implements CEnumPins
970 //=====================================================================
971 //=====================================================================
972 
973 
975  __in_opt CEnumPins *pEnumPins) :
976  m_Position(0),
977  m_PinCount(0),
978  m_pFilter(pFilter),
979  m_cRef(1), // Already ref counted
980  m_PinCache(NAME("Pin Cache"))
981 {
982 
983 #ifdef DEBUG
984  m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0);
985 #endif
986 
987  /* We must be owned by a filter derived from CBaseFilter */
988 
989  ASSERT(pFilter != NULL);
990 
991  /* Hold a reference count on our filter */
992  m_pFilter->AddRef();
993 
994  /* Are we creating a new enumerator */
995 
996  if (pEnumPins == NULL) {
997  m_Version = m_pFilter->GetPinVersion();
998  m_PinCount = m_pFilter->GetPinCount();
999  } else {
1000  ASSERT(m_Position <= m_PinCount);
1001  m_Position = pEnumPins->m_Position;
1002  m_PinCount = pEnumPins->m_PinCount;
1003  m_Version = pEnumPins->m_Version;
1004  m_PinCache.AddTail(&(pEnumPins->m_PinCache));
1005  }
1006 }
1007 
1008 
1009 /* Destructor releases the reference count on our filter NOTE since we hold
1010  a reference count on the filter who created us we know it is safe to
1011  release it, no access can be made to it afterwards though as we have just
1012  caused the last reference count to go and the object to be deleted */
1013 
1015 {
1016  m_pFilter->Release();
1017 
1018 #ifdef DEBUG
1019  DbgRegisterObjectDestruction(m_dwCookie);
1020 #endif
1021 }
1022 
1023 
1024 /* Override this to say what interfaces we support where */
1025 
1026 STDMETHODIMP
1027 CEnumPins::QueryInterface(REFIID riid, __deref_out void **ppv)
1028 {
1029  CheckPointer(ppv, E_POINTER);
1030 
1031  /* Do we have this interface */
1032 
1033  if (riid == IID_IEnumPins || riid == IID_IUnknown) {
1034  return GetInterface((IEnumPins *) this, ppv);
1035  } else {
1036  *ppv = NULL;
1037  return E_NOINTERFACE;
1038  }
1039 }
1040 
1042 CEnumPins::AddRef()
1043 {
1044  return InterlockedIncrement(&m_cRef);
1045 }
1046 
1048 CEnumPins::Release()
1049 {
1050  ULONG cRef = InterlockedDecrement(&m_cRef);
1051  if (cRef == 0) {
1052  delete this;
1053  }
1054  return cRef;
1055 }
1056 
1057 /* One of an enumerator's basic member functions allows us to create a cloned
1058  interface that initially has the same state. Since we are taking a snapshot
1059  of an object (current position and all) we must lock access at the start */
1060 
1061 STDMETHODIMP
1062 CEnumPins::Clone(__deref_out IEnumPins **ppEnum)
1063 {
1064  CheckPointer(ppEnum,E_POINTER);
1065  ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
1066  HRESULT hr = NOERROR;
1067 
1068  /* Check we are still in sync with the filter */
1069  if (AreWeOutOfSync() == TRUE) {
1070  *ppEnum = NULL;
1071  hr = VFW_E_ENUM_OUT_OF_SYNC;
1072  } else {
1073  *ppEnum = new CEnumPins(m_pFilter,
1074  this);
1075  if (*ppEnum == NULL) {
1076  hr = E_OUTOFMEMORY;
1077  }
1078  }
1079  return hr;
1080 }
1081 
1082 
1083 /* Return the next pin after the current position */
1084 
1085 STDMETHODIMP
1086 CEnumPins::Next(ULONG cPins, // place this many pins...
1087  __out_ecount(cPins) IPin **ppPins, // ...in this array
1088  __out_opt ULONG *pcFetched) // actual count passed returned here
1089 {
1090  CheckPointer(ppPins,E_POINTER);
1091  ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *));
1092 
1093  ASSERT(ppPins);
1094 
1095  if (pcFetched!=NULL) {
1096  ValidateWritePtr(pcFetched, sizeof(ULONG));
1097  *pcFetched = 0; // default unless we succeed
1098  }
1099  // now check that the parameter is valid
1100  else if (cPins>1) { // pcFetched == NULL
1101  return E_INVALIDARG;
1102  }
1103  ULONG cFetched = 0; // increment as we get each one.
1104 
1105  /* Check we are still in sync with the filter */
1106  if (AreWeOutOfSync() == TRUE) {
1107  // If we are out of sync, we should refresh the enumerator.
1108  // This will reset the position and update the other members, but
1109  // will not clear cache of pins we have already returned.
1110  Refresh();
1111  }
1112 
1113  /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed
1114  so we must QI for the IPin (which increments its reference count)
1115  If while we are retrieving a pin from the filter an error occurs we
1116  assume that our internal state is stale with respect to the filter
1117  (for example someone has deleted a pin) so we
1118  return VFW_E_ENUM_OUT_OF_SYNC */
1119 
1120  while (cFetched < cPins && m_PinCount > m_Position) {
1121 
1122  /* Get the next pin object from the filter */
1123 
1124  CBasePin *pPin = m_pFilter->GetPin(m_Position++);
1125  if (pPin == NULL) {
1126  // If this happend, and it's not the first time through, then we've got a problem,
1127  // since we should really go back and release the iPins, which we have previously
1128  // AddRef'ed.
1129  ASSERT( cFetched==0 );
1130  return VFW_E_ENUM_OUT_OF_SYNC;
1131  }
1132 
1133  /* We only want to return this pin, if it is not in our cache */
1134  if (0 == m_PinCache.Find(pPin))
1135  {
1136  /* From the object get an IPin interface */
1137 
1138  *ppPins = pPin;
1139  pPin->AddRef();
1140 
1141  cFetched++;
1142  ppPins++;
1143 
1144  m_PinCache.AddTail(pPin);
1145  }
1146  }
1147 
1148  if (pcFetched!=NULL) {
1149  *pcFetched = cFetched;
1150  }
1151 
1152  return (cPins==cFetched ? NOERROR : S_FALSE);
1153 }
1154 
1155 
1156 /* Skip over one or more entries in the enumerator */
1157 
1158 STDMETHODIMP
1160 {
1161  /* Check we are still in sync with the filter */
1162  if (AreWeOutOfSync() == TRUE) {
1163  return VFW_E_ENUM_OUT_OF_SYNC;
1164  }
1165 
1166  /* Work out how many pins are left to skip over */
1167  /* We could position at the end if we are asked to skip too many... */
1168  /* ..which would match the base implementation for CEnumMediaTypes::Skip */
1169 
1170  ULONG PinsLeft = m_PinCount - m_Position;
1171  if (cPins > PinsLeft) {
1172  return S_FALSE;
1173  }
1174  m_Position += cPins;
1175  return NOERROR;
1176 }
1177 
1178 
1179 /* Set the current position back to the start */
1180 /* Reset has 4 simple steps:
1181  *
1182  * Set position to head of list
1183  * Sync enumerator with object being enumerated
1184  * Clear the cache of pins already returned
1185  * return S_OK
1186  */
1187 
1188 STDMETHODIMP
1190 {
1191  m_Version = m_pFilter->GetPinVersion();
1192  m_PinCount = m_pFilter->GetPinCount();
1193 
1194  m_Position = 0;
1195 
1196  // Clear the cache
1197  m_PinCache.RemoveAll();
1198 
1199  return S_OK;
1200 }
1201 
1202 
1203 /* Set the current position back to the start */
1204 /* Refresh has 3 simple steps:
1205  *
1206  * Set position to head of list
1207  * Sync enumerator with object being enumerated
1208  * return S_OK
1209  */
1210 
1211 STDMETHODIMP
1212 CEnumPins::Refresh()
1213 {
1214  m_Version = m_pFilter->GetPinVersion();
1215  m_PinCount = m_pFilter->GetPinCount();
1216 
1217  m_Position = 0;
1218  return S_OK;
1219 }
1220 
1221 
1222 //=====================================================================
1223 //=====================================================================
1224 // Implements CEnumMediaTypes
1225 //=====================================================================
1226 //=====================================================================
1227 
1228 
1230  __in_opt CEnumMediaTypes *pEnumMediaTypes) :
1231  m_Position(0),
1232  m_pPin(pPin),
1233  m_cRef(1)
1234 {
1235 
1236 #ifdef DEBUG
1237  m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0);
1238 #endif
1239 
1240  /* We must be owned by a pin derived from CBasePin */
1241 
1242  ASSERT(pPin != NULL);
1243 
1244  /* Hold a reference count on our pin */
1245  m_pPin->AddRef();
1246 
1247  /* Are we creating a new enumerator */
1248 
1249  if (pEnumMediaTypes == NULL) {
1250  m_Version = m_pPin->GetMediaTypeVersion();
1251  return;
1252  }
1253 
1254  m_Position = pEnumMediaTypes->m_Position;
1255  m_Version = pEnumMediaTypes->m_Version;
1256 }
1257 
1258 
1259 /* Destructor releases the reference count on our base pin. NOTE since we hold
1260  a reference count on the pin who created us we know it is safe to release
1261  it, no access can be made to it afterwards though as we might have just
1262  caused the last reference count to go and the object to be deleted */
1263 
1265 {
1266 #ifdef DEBUG
1267  DbgRegisterObjectDestruction(m_dwCookie);
1268 #endif
1269  m_pPin->Release();
1270 }
1271 
1272 
1273 /* Override this to say what interfaces we support where */
1274 
1275 STDMETHODIMP
1276 CEnumMediaTypes::QueryInterface(REFIID riid, __deref_out void **ppv)
1277 {
1278  CheckPointer(ppv, E_POINTER);
1279 
1280  /* Do we have this interface */
1281 
1282  if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) {
1283  return GetInterface((IEnumMediaTypes *) this, ppv);
1284  } else {
1285  *ppv = NULL;
1286  return E_NOINTERFACE;
1287  }
1288 }
1289 
1291 CEnumMediaTypes::AddRef()
1292 {
1293  return InterlockedIncrement(&m_cRef);
1294 }
1295 
1297 CEnumMediaTypes::Release()
1298 {
1299  ULONG cRef = InterlockedDecrement(&m_cRef);
1300  if (cRef == 0) {
1301  delete this;
1302  }
1303  return cRef;
1304 }
1305 
1306 /* One of an enumerator's basic member functions allows us to create a cloned
1307  interface that initially has the same state. Since we are taking a snapshot
1308  of an object (current position and all) we must lock access at the start */
1309 
1310 STDMETHODIMP
1311 CEnumMediaTypes::Clone(__deref_out IEnumMediaTypes **ppEnum)
1312 {
1313  CheckPointer(ppEnum,E_POINTER);
1314  ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
1315  HRESULT hr = NOERROR;
1316 
1317  /* Check we are still in sync with the pin */
1318  if (AreWeOutOfSync() == TRUE) {
1319  *ppEnum = NULL;
1320  hr = VFW_E_ENUM_OUT_OF_SYNC;
1321  } else {
1322 
1323  *ppEnum = new CEnumMediaTypes(m_pPin,
1324  this);
1325 
1326  if (*ppEnum == NULL) {
1327  hr = E_OUTOFMEMORY;
1328  }
1329  }
1330  return hr;
1331 }
1332 
1333 
1334 /* Enumerate the next pin(s) after the current position. The client using this
1335  interface passes in a pointer to an array of pointers each of which will
1336  be filled in with a pointer to a fully initialised media type format
1337  Return NOERROR if it all works,
1338  S_FALSE if fewer than cMediaTypes were enumerated.
1339  VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by
1340  state changes in the filter
1341  The actual count always correctly reflects the number of types in the array.
1342 */
1343 
1344 STDMETHODIMP
1345 CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types...
1346  __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes, // ...in this array
1347  __out ULONG *pcFetched) // actual count passed
1348 {
1349  CheckPointer(ppMediaTypes,E_POINTER);
1350  ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *));
1351  /* Check we are still in sync with the pin */
1352  if (AreWeOutOfSync() == TRUE) {
1353  return VFW_E_ENUM_OUT_OF_SYNC;
1354  }
1355 
1356  if (pcFetched!=NULL) {
1357  ValidateWritePtr(pcFetched, sizeof(ULONG));
1358  *pcFetched = 0; // default unless we succeed
1359  }
1360  // now check that the parameter is valid
1361  else if (cMediaTypes>1) { // pcFetched == NULL
1362  return E_INVALIDARG;
1363  }
1364  ULONG cFetched = 0; // increment as we get each one.
1365 
1366  /* Return each media type by asking the filter for them in turn - If we
1367  have an error code retured to us while we are retrieving a media type
1368  we assume that our internal state is stale with respect to the filter
1369  (for example the window size changing) so we return
1370  VFW_E_ENUM_OUT_OF_SYNC */
1371 
1372  while (cMediaTypes) {
1373 
1374  CMediaType cmt;
1375 
1376  HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt);
1377  if (S_OK != hr) {
1378  break;
1379  }
1380 
1381  /* We now have a CMediaType object that contains the next media type
1382  but when we assign it to the array position we CANNOT just assign
1383  the AM_MEDIA_TYPE structure because as soon as the object goes out of
1384  scope it will delete the memory we have just copied. The function
1385  we use is CreateMediaType which allocates a task memory block */
1386 
1387  /* Transfer across the format block manually to save an allocate
1388  and free on the format block and generally go faster */
1389 
1390  *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1391  if (*ppMediaTypes == NULL) {
1392  break;
1393  }
1394 
1395  /* Do a regular copy */
1396  **ppMediaTypes = cmt;
1397 
1398  /* Make sure the destructor doesn't free these */
1399  cmt.pbFormat = NULL;
1400  cmt.cbFormat = NULL;
1401  cmt.pUnk = NULL;
1402 
1403 
1404  ppMediaTypes++;
1405  cFetched++;
1406  cMediaTypes--;
1407  }
1408 
1409  if (pcFetched!=NULL) {
1410  *pcFetched = cFetched;
1411  }
1412 
1413  return ( cMediaTypes==0 ? NOERROR : S_FALSE );
1414 }
1415 
1416 
1417 /* Skip over one or more entries in the enumerator */
1418 
1419 STDMETHODIMP
1421 {
1422  // If we're skipping 0 elements we're guaranteed to skip the
1423  // correct number of elements
1424  if (cMediaTypes == 0) {
1425  return S_OK;
1426  }
1427 
1428  /* Check we are still in sync with the pin */
1429  if (AreWeOutOfSync() == TRUE) {
1430  return VFW_E_ENUM_OUT_OF_SYNC;
1431  }
1432 
1433  m_Position += cMediaTypes;
1434 
1435  /* See if we're over the end */
1436  CMediaType cmt;
1437  return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE;
1438 }
1439 
1440 
1441 /* Set the current position back to the start */
1442 /* Reset has 3 simple steps:
1443  *
1444  * set position to head of list
1445  * sync enumerator with object being enumerated
1446  * return S_OK
1447  */
1448 
1449 STDMETHODIMP
1451 
1452 {
1453  m_Position = 0;
1454 
1455  // Bring the enumerator back into step with the current state. This
1456  // may be a noop but ensures that the enumerator will be valid on the
1457  // next call.
1458  m_Version = m_pPin->GetMediaTypeVersion();
1459  return NOERROR;
1460 }
1461 
1462 
1463 //=====================================================================
1464 //=====================================================================
1465 // Implements CBasePin
1466 //=====================================================================
1467 //=====================================================================
1468 
1469 
1470 /* NOTE The implementation of this class calls the CUnknown constructor with
1471  a NULL outer unknown pointer. This has the effect of making us a self
1472  contained class, ie any QueryInterface, AddRef or Release calls will be
1473  routed to the class's NonDelegatingUnknown methods. You will typically
1474  find that the classes that do this then override one or more of these
1475  virtual functions to provide more specialised behaviour. A good example
1476  of this is where a class wants to keep the QueryInterface internal but
1477  still wants its lifetime controlled by the external object */
1478 
1479 /* Constructor */
1480 
1481 CBasePin::CBasePin(__in_opt LPCTSTR pObjectName,
1482  __in CBaseFilter *pFilter,
1483  __in CCritSec *pLock,
1484  __inout HRESULT *phr,
1485  __in_opt LPCWSTR pName,
1486  PIN_DIRECTION dir) :
1487  CUnknown( pObjectName, NULL ),
1488  m_pFilter(pFilter),
1489  m_pLock(pLock),
1490  m_pName(NULL),
1491  m_Connected(NULL),
1492  m_dir(dir),
1493  m_bRunTimeError(FALSE),
1494  m_pQSink(NULL),
1495  m_TypeVersion(1),
1496  m_tStart(),
1497  m_tStop(MAX_TIME),
1498  m_bCanReconnectWhenActive(false),
1499  m_bTryMyTypesFirst(false),
1500  m_dRate(1.0)
1501 {
1502  /* WARNING - pFilter is often not a properly constituted object at
1503  this state (in particular QueryInterface may not work) - this
1504  is because its owner is often its containing object and we
1505  have been called from the containing object's constructor so
1506  the filter's owner has not yet had its CUnknown constructor
1507  called
1508  */
1509 #ifdef DXMPERF
1510  PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this );
1511 #endif // DXMPERF
1512 
1513  ASSERT(pFilter != NULL);
1514  ASSERT(pLock != NULL);
1515 
1516  if (pName) {
1517  size_t cchName;
1518  HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName);
1519  if (SUCCEEDED(hr)) {
1520  m_pName = new WCHAR[cchName + 1];
1521  if (m_pName) {
1522  (void)StringCchCopyW(m_pName, cchName + 1, pName);
1523  }
1524  }
1525  }
1526 
1527 #ifdef DEBUG
1528  m_cRef = 0;
1529 #endif
1530 }
1531 
1532 #ifdef UNICODE
1533 CBasePin::CBasePin(__in_opt LPCSTR pObjectName,
1534  __in CBaseFilter *pFilter,
1535  __in CCritSec *pLock,
1536  __inout HRESULT *phr,
1537  __in_opt LPCWSTR pName,
1538  PIN_DIRECTION dir) :
1539  CUnknown( pObjectName, NULL ),
1540  m_pFilter(pFilter),
1541  m_pLock(pLock),
1542  m_pName(NULL),
1543  m_Connected(NULL),
1544  m_dir(dir),
1545  m_bRunTimeError(FALSE),
1546  m_pQSink(NULL),
1547  m_TypeVersion(1),
1548  m_tStart(),
1549  m_tStop(MAX_TIME),
1550  m_bCanReconnectWhenActive(false),
1551  m_bTryMyTypesFirst(false),
1552  m_dRate(1.0)
1553 {
1554  /* WARNING - pFilter is often not a properly constituted object at
1555  this state (in particular QueryInterface may not work) - this
1556  is because its owner is often its containing object and we
1557  have been called from the containing object's constructor so
1558  the filter's owner has not yet had its CUnknown constructor
1559  called
1560  */
1561 #ifdef DXMPERF
1562  PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this );
1563 #endif // DXMPERF
1564 
1565  ASSERT(pFilter != NULL);
1566  ASSERT(pLock != NULL);
1567 
1568  if (pName) {
1569  size_t cchName;
1570  HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName);
1571  if (SUCCEEDED(hr)) {
1572  m_pName = new WCHAR[cchName + 1];
1573  if (m_pName) {
1574  (void)StringCchCopyW(m_pName, cchName + 1, pName);
1575  }
1576  }
1577  }
1578 
1579 
1580 #ifdef DEBUG
1581  m_cRef = 0;
1582 #endif
1583 }
1584 #endif
1585 
1586 /* Destructor since a connected pin holds a reference count on us there is
1587  no way that we can be deleted unless we are not currently connected */
1588 
1590 {
1591 #ifdef DXMPERF
1592  PERFLOG_DTOR( m_pName ? m_pName : L"CBasePin", (IPin *) this );
1593 #endif // DXMPERF
1594 
1595  // We don't call disconnect because if the filter is going away
1596  // all the pins must have a reference count of zero so they must
1597  // have been disconnected anyway - (but check the assumption)
1598  ASSERT(m_Connected == FALSE);
1599 
1600  delete[] m_pName;
1601 
1602  // check the internal reference count is consistent
1603  ASSERT(m_cRef == 0);
1604 }
1605 
1606 
1607 /* Override this to say what interfaces we support and where */
1608 
1609 STDMETHODIMP
1610 CBasePin::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv)
1611 {
1612  /* Do we have this interface */
1613 
1614  if (riid == IID_IPin) {
1615  return GetInterface((IPin *) this, ppv);
1616  } else if (riid == IID_IQualityControl) {
1617  return GetInterface((IQualityControl *) this, ppv);
1618  } else {
1620  }
1621 }
1622 
1623 
1624 /* Override to increment the owning filter's reference count */
1625 
1627 CBasePin::NonDelegatingAddRef()
1628 {
1629  ASSERT(InterlockedIncrement(&m_cRef) > 0);
1630  return m_pFilter->AddRef();
1631 }
1632 
1633 
1634 /* Override to decrement the owning filter's reference count */
1635 
1637 CBasePin::NonDelegatingRelease()
1638 {
1639  ASSERT(InterlockedDecrement(&m_cRef) >= 0);
1640  return m_pFilter->Release();
1641 }
1642 
1643 
1644 /* Displays pin connection information */
1645 
1646 #ifdef DEBUG
1647 void
1648 CBasePin::DisplayPinInfo(IPin *pReceivePin)
1649 {
1650 
1652  PIN_INFO ConnectPinInfo;
1653  PIN_INFO ReceivePinInfo;
1654 
1655  if (FAILED(QueryPinInfo(&ConnectPinInfo))) {
1656  StringCchCopyW(ConnectPinInfo.achName, sizeof(ConnectPinInfo.achName)/sizeof(WCHAR), L"Bad Pin");
1657  } else {
1658  QueryPinInfoReleaseFilter(ConnectPinInfo);
1659  }
1660 
1661  if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) {
1662  StringCchCopyW(ReceivePinInfo.achName, sizeof(ReceivePinInfo.achName)/sizeof(WCHAR), L"Bad Pin");
1663  } else {
1664  QueryPinInfoReleaseFilter(ReceivePinInfo);
1665  }
1666 
1667  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :")));
1668  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName));
1669  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName));
1670  }
1671 }
1672 #endif
1673 
1674 
1675 /* Displays general information on the pin media type */
1676 
1677 #ifdef DEBUG
1678 void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt)
1679 {
1680  UNREFERENCED_PARAMETER(pPin);
1682  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:")));
1683  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"),
1684  GuidNames[*pmt->Type()]));
1685  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"),
1686  GuidNames[*pmt->Subtype()]));
1687  }
1688 }
1689 #endif
1690 
1691 /* Asked to connect to a pin. A pin is always attached to an owning filter
1692  object so we always delegate our locking to that object. We first of all
1693  retrieve a media type enumerator for the input pin and see if we accept
1694  any of the formats that it would ideally like, failing that we retrieve
1695  our enumerator and see if it will accept any of our preferred types */
1696 
1697 STDMETHODIMP
1699  IPin * pReceivePin,
1700  __in_opt const AM_MEDIA_TYPE *pmt // optional media type
1701 )
1702 {
1703  CheckPointer(pReceivePin,E_POINTER);
1704  ValidateReadPtr(pReceivePin,sizeof(IPin));
1705  CAutoLock cObjectLock(m_pLock);
1706  DisplayPinInfo(pReceivePin);
1707 
1708  /* See if we are already connected */
1709 
1710  if (m_Connected) {
1711  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected")));
1712  return VFW_E_ALREADY_CONNECTED;
1713  }
1714 
1715  /* See if the filter is active */
1716  if (!IsStopped() && !m_bCanReconnectWhenActive) {
1717  return VFW_E_NOT_STOPPED;
1718  }
1719 
1720 
1721  // Find a mutually agreeable media type -
1722  // Pass in the template media type. If this is partially specified,
1723  // each of the enumerated media types will need to be checked against
1724  // it. If it is non-null and fully specified, we will just try to connect
1725  // with this.
1726 
1727  const CMediaType * ptype = (CMediaType*)pmt;
1728  HRESULT hr = AgreeMediaType(pReceivePin, ptype);
1729  if (FAILED(hr)) {
1730  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type")));
1731 
1732  // Since the procedure is already returning an error code, there
1733  // is nothing else this function can do to report the error.
1734  EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
1735 
1736 #ifdef DXMPERF
1737  PERFLOG_CONNECT( (IPin *) this, pReceivePin, hr, pmt );
1738 #endif // DXMPERF
1739 
1740  return hr;
1741  }
1742 
1743  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded")));
1744 
1745 #ifdef DXMPERF
1746  PERFLOG_CONNECT( (IPin *) this, pReceivePin, NOERROR, pmt );
1747 #endif // DXMPERF
1748 
1749  return NOERROR;
1750 }
1751 
1752 // given a specific media type, attempt a connection (includes
1753 // checking that the type is acceptable to this pin)
1754 HRESULT
1756  IPin* pReceivePin, // connect to this pin
1757  const CMediaType* pmt // using this type
1758 )
1759 {
1760  // The caller should hold the filter lock becasue this function
1761  // uses m_Connected. The caller should also hold the filter lock
1762  // because this function calls SetMediaType(), IsStopped() and
1763  // CompleteConnect().
1765 
1766  // Check that the connection is valid -- need to do this for every
1767  // connect attempt since BreakConnect will undo it.
1768  HRESULT hr = CheckConnect(pReceivePin);
1769  if (FAILED(hr)) {
1770  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed")));
1771 
1772  // Since the procedure is already returning an error code, there
1773  // is nothing else this function can do to report the error.
1774  EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
1775 
1776  return hr;
1777  }
1778 
1779  DisplayTypeInfo(pReceivePin, pmt);
1780 
1781  /* Check we will accept this media type */
1782 
1783  hr = CheckMediaType(pmt);
1784  if (hr == NOERROR) {
1785 
1786  /* Make ourselves look connected otherwise ReceiveConnection
1787  may not be able to complete the connection
1788  */
1789  m_Connected = pReceivePin;
1790  m_Connected->AddRef();
1791  hr = SetMediaType(pmt);
1792  if (SUCCEEDED(hr)) {
1793  /* See if the other pin will accept this type */
1794 
1795  hr = pReceivePin->ReceiveConnection((IPin *)this, pmt);
1796  if (SUCCEEDED(hr)) {
1797  /* Complete the connection */
1798 
1799  hr = CompleteConnect(pReceivePin);
1800  if (SUCCEEDED(hr)) {
1801  return hr;
1802  } else {
1803  DbgLog((LOG_TRACE,
1805  TEXT("Failed to complete connection")));
1806  pReceivePin->Disconnect();
1807  }
1808  }
1809  }
1810  } else {
1811  // we cannot use this media type
1812 
1813  // return a specific media type error if there is one
1814  // or map a general failure code to something more helpful
1815  // (in particular S_FALSE gets changed to an error code)
1816  if (SUCCEEDED(hr) ||
1817  (hr == E_FAIL) ||
1818  (hr == E_INVALIDARG)) {
1819  hr = VFW_E_TYPE_NOT_ACCEPTED;
1820  }
1821  }
1822 
1823  // BreakConnect and release any connection here in case CheckMediaType
1824  // failed, or if we set anything up during a call back during
1825  // ReceiveConnection.
1826 
1827  // Since the procedure is already returning an error code, there
1828  // is nothing else this function can do to report the error.
1829  EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
1830 
1831  /* If failed then undo our state */
1832  if (m_Connected) {
1833  m_Connected->Release();
1834  m_Connected = NULL;
1835  }
1836 
1837  return hr;
1838 }
1839 
1840 /* Given an enumerator we cycle through all the media types it proposes and
1841  firstly suggest them to our derived pin class and if that succeeds try
1842  them with the pin in a ReceiveConnection call. This means that if our pin
1843  proposes a media type we still check in here that we can support it. This
1844  is deliberate so that in simple cases the enumerator can hold all of the
1845  media types even if some of them are not really currently available */
1846 
1848  IPin *pReceivePin,
1849  __in_opt const CMediaType *pmt,
1850  IEnumMediaTypes *pEnum)
1851 {
1852  /* Reset the current enumerator position */
1853 
1854  HRESULT hr = pEnum->Reset();
1855  if (FAILED(hr)) {
1856  return hr;
1857  }
1858 
1859  CMediaType *pMediaType = NULL;
1860  ULONG ulMediaCount = 0;
1861 
1862  // attempt to remember a specific error code if there is one
1863  HRESULT hrFailure = S_OK;
1864 
1865  for (;;) {
1866 
1867  /* Retrieve the next media type NOTE each time round the loop the
1868  enumerator interface will allocate another AM_MEDIA_TYPE structure
1869  If we are successful then we copy it into our output object, if
1870  not then we must delete the memory allocated before returning */
1871 
1872  hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount);
1873  if (hr != S_OK) {
1874  if (S_OK == hrFailure) {
1875  hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
1876  }
1877  return hrFailure;
1878  }
1879 
1880 
1881  ASSERT(ulMediaCount == 1);
1882  ASSERT(pMediaType);
1883 
1884  // check that this matches the partial type (if any)
1885 
1886  if (pMediaType &&
1887  ((pmt == NULL) ||
1888  pMediaType->MatchesPartial(pmt))) {
1889 
1890  hr = AttemptConnection(pReceivePin, pMediaType);
1891 
1892  // attempt to remember a specific error code
1893  if (FAILED(hr) &&
1894  SUCCEEDED(hrFailure) &&
1895  (hr != E_FAIL) &&
1896  (hr != E_INVALIDARG) &&
1897  (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
1898  hrFailure = hr;
1899  }
1900  } else {
1901  hr = VFW_E_NO_ACCEPTABLE_TYPES;
1902  }
1903 
1904  if(pMediaType) {
1905  DeleteMediaType(pMediaType);
1906  pMediaType = NULL;
1907  }
1908 
1909  if (S_OK == hr) {
1910  return hr;
1911  }
1912  }
1913 }
1914 
1915 
1916 /* This is called to make the connection, including the taask of finding
1917  a media type for the pin connection. pmt is the proposed media type
1918  from the Connect call: if this is fully specified, we will try that.
1919  Otherwise we enumerate and try all the input pin's types first and
1920  if that fails we then enumerate and try all our preferred media types.
1921  For each media type we check it against pmt (if non-null and partially
1922  specified) as well as checking that both pins will accept it.
1923  */
1924 
1926  IPin *pReceivePin,
1927  const CMediaType *pmt)
1928 {
1929  ASSERT(pReceivePin);
1930  IEnumMediaTypes *pEnumMediaTypes = NULL;
1931 
1932  // if the media type is fully specified then use that
1933  if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) {
1934 
1935  // if this media type fails, then we must fail the connection
1936  // since if pmt is nonnull we are only allowed to connect
1937  // using a type that matches it.
1938 
1939  return AttemptConnection(pReceivePin, pmt);
1940  }
1941 
1942 
1943  /* Try the other pin's enumerator */
1944 
1945  HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
1946 
1947  for (int i = 0; i < 2; i++) {
1948  HRESULT hr;
1949  if (i == (int)m_bTryMyTypesFirst) {
1950  hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes);
1951  } else {
1952  hr = EnumMediaTypes(&pEnumMediaTypes);
1953  }
1954  if (SUCCEEDED(hr)) {
1955  ASSERT(pEnumMediaTypes);
1956  hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes);
1957  pEnumMediaTypes->Release();
1958  if (SUCCEEDED(hr)) {
1959  return NOERROR;
1960  } else {
1961  // try to remember specific error codes if there are any
1962  if ((hr != E_FAIL) &&
1963  (hr != E_INVALIDARG) &&
1964  (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
1965  hrFailure = hr;
1966  }
1967  }
1968  }
1969  }
1970 
1971  return hrFailure;
1972 }
1973 
1974 
1975 /* Called when we want to complete a connection to another filter. Failing
1976  this will also fail the connection and disconnect the other pin as well */
1977 
1978 HRESULT
1979 CBasePin::CompleteConnect(IPin *pReceivePin)
1980 {
1981  UNREFERENCED_PARAMETER(pReceivePin);
1982  return NOERROR;
1983 }
1984 
1985 
1986 /* This is called to set the format for a pin connection - CheckMediaType
1987  will have been called to check the connection format and if it didn't
1988  return an error code then this (virtual) function will be invoked */
1989 
1990 HRESULT
1992 {
1993  HRESULT hr = m_mt.Set(*pmt);
1994  if (FAILED(hr)) {
1995  return hr;
1996  }
1997 
1998  return NOERROR;
1999 }
2000 
2001 
2002 /* This is called during Connect() to provide a virtual method that can do
2003  any specific check needed for connection such as QueryInterface. This
2004  base class method just checks that the pin directions don't match */
2005 
2006 HRESULT
2008 {
2009  /* Check that pin directions DONT match */
2010 
2011  PIN_DIRECTION pd;
2012  pPin->QueryDirection(&pd);
2013 
2014  ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT));
2015  ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT));
2016 
2017  // we should allow for non-input and non-output connections?
2018  if (pd == m_dir) {
2019  return VFW_E_INVALID_DIRECTION;
2020  }
2021  return NOERROR;
2022 }
2023 
2024 
2025 /* This is called when we realise we can't make a connection to the pin and
2026  must undo anything we did in CheckConnect - override to release QIs done */
2027 
2028 HRESULT
2030 {
2031  return NOERROR;
2032 }
2033 
2034 
2035 /* Called normally by an output pin on an input pin to try and establish a
2036  connection.
2037 */
2038 
2039 STDMETHODIMP
2041  IPin * pConnector, // this is the pin who we will connect to
2042  const AM_MEDIA_TYPE *pmt // this is the media type we will exchange
2043 )
2044 {
2045  CheckPointer(pConnector,E_POINTER);
2046  CheckPointer(pmt,E_POINTER);
2047  ValidateReadPtr(pConnector,sizeof(IPin));
2048  ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
2049  CAutoLock cObjectLock(m_pLock);
2050 
2051  /* Are we already connected */
2052  if (m_Connected) {
2053  return VFW_E_ALREADY_CONNECTED;
2054  }
2055 
2056  /* See if the filter is active */
2057  if (!IsStopped() && !m_bCanReconnectWhenActive) {
2058  return VFW_E_NOT_STOPPED;
2059  }
2060 
2061  HRESULT hr = CheckConnect(pConnector);
2062  if (FAILED(hr)) {
2063  // Since the procedure is already returning an error code, there
2064  // is nothing else this function can do to report the error.
2065  EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
2066 
2067 #ifdef DXMPERF
2068  PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt );
2069 #endif // DXMPERF
2070 
2071  return hr;
2072  }
2073 
2074  /* Ask derived class if this media type is ok */
2075 
2076  CMediaType * pcmt = (CMediaType*) pmt;
2077  hr = CheckMediaType(pcmt);
2078  if (hr != NOERROR) {
2079  // no -we don't support this media type
2080 
2081  // Since the procedure is already returning an error code, there
2082  // is nothing else this function can do to report the error.
2083  EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
2084 
2085  // return a specific media type error if there is one
2086  // or map a general failure code to something more helpful
2087  // (in particular S_FALSE gets changed to an error code)
2088  if (SUCCEEDED(hr) ||
2089  (hr == E_FAIL) ||
2090  (hr == E_INVALIDARG)) {
2091  hr = VFW_E_TYPE_NOT_ACCEPTED;
2092  }
2093 
2094 #ifdef DXMPERF
2095  PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt );
2096 #endif // DXMPERF
2097 
2098  return hr;
2099  }
2100 
2101  /* Complete the connection */
2102 
2103  m_Connected = pConnector;
2104  m_Connected->AddRef();
2105  hr = SetMediaType(pcmt);
2106  if (SUCCEEDED(hr)) {
2107  hr = CompleteConnect(pConnector);
2108  if (SUCCEEDED(hr)) {
2109 
2110 #ifdef DXMPERF
2111  PERFLOG_RXCONNECT( pConnector, (IPin *) this, NOERROR, pmt );
2112 #endif // DXMPERF
2113 
2114  return NOERROR;
2115  }
2116  }
2117 
2118  DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection.")));
2119  m_Connected->Release();
2120  m_Connected = NULL;
2121 
2122  // Since the procedure is already returning an error code, there
2123  // is nothing else this function can do to report the error.
2124  EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
2125 
2126 #ifdef DXMPERF
2127  PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt );
2128 #endif // DXMPERF
2129 
2130  return hr;
2131 }
2132 
2133 
2134 /* Called when we want to terminate a pin connection */
2135 
2136 STDMETHODIMP
2138 {
2139  CAutoLock cObjectLock(m_pLock);
2140 
2141  /* See if the filter is active */
2142  if (!IsStopped()) {
2143  return VFW_E_NOT_STOPPED;
2144  }
2145 
2146  return DisconnectInternal();
2147 }
2148 
2149 STDMETHODIMP
2151 {
2153 
2154  if (m_Connected) {
2155  HRESULT hr = BreakConnect();
2156  if( FAILED( hr ) ) {
2157 
2158 #ifdef DXMPERF
2159  PERFLOG_DISCONNECT( (IPin *) this, m_Connected, hr );
2160 #endif // DXMPERF
2161 
2162  // There is usually a bug in the program if BreakConnect() fails.
2163  DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." );
2164  return hr;
2165  }
2166 
2167  m_Connected->Release();
2168  m_Connected = NULL;
2169 
2170 #ifdef DXMPERF
2171  PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_OK );
2172 #endif // DXMPERF
2173 
2174  return S_OK;
2175  } else {
2176  // no connection - not an error
2177 
2178 #ifdef DXMPERF
2179  PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_FALSE );
2180 #endif // DXMPERF
2181 
2182  return S_FALSE;
2183  }
2184 }
2185 
2186 
2187 /* Return an AddRef()'d pointer to the connected pin if there is one */
2188 STDMETHODIMP
2190  __deref_out IPin **ppPin
2191 )
2192 {
2193  CheckPointer(ppPin,E_POINTER);
2194  ValidateReadWritePtr(ppPin,sizeof(IPin *));
2195  //
2196  // It's pointless to lock here.
2197  // The caller should ensure integrity.
2198  //
2199 
2200  IPin *pPin = m_Connected;
2201  *ppPin = pPin;
2202  if (pPin != NULL) {
2203  pPin->AddRef();
2204  return S_OK;
2205  } else {
2206  ASSERT(*ppPin == NULL);
2207  return VFW_E_NOT_CONNECTED;
2208  }
2209 }
2210 
2211 /* Return the media type of the connection */
2212 STDMETHODIMP
2214  __out AM_MEDIA_TYPE *pmt
2215 )
2216 {
2217  CheckPointer(pmt,E_POINTER);
2218  ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE));
2219  CAutoLock cObjectLock(m_pLock);
2220 
2221  /* Copy constructor of m_mt allocates the memory */
2222  if (IsConnected()) {
2223  CopyMediaType( pmt, &m_mt );
2224  return S_OK;
2225  } else {
2226  ((CMediaType *)pmt)->InitMediaType();
2227  return VFW_E_NOT_CONNECTED;
2228  }
2229 }
2230 
2231 /* Return information about the filter we are connect to */
2232 
2233 STDMETHODIMP
2235  __out PIN_INFO * pInfo
2236 )
2237 {
2238  CheckPointer(pInfo,E_POINTER);
2239  ValidateReadWritePtr(pInfo,sizeof(PIN_INFO));
2240 
2241  pInfo->pFilter = m_pFilter;
2242  if (m_pFilter) {
2243  m_pFilter->AddRef();
2244  }
2245 
2246  if (m_pName) {
2247  (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName);
2248  } else {
2249  pInfo->achName[0] = L'\0';
2250  }
2251 
2252  pInfo->dir = m_dir;
2253 
2254  return NOERROR;
2255 }
2256 
2257 STDMETHODIMP
2259  __out PIN_DIRECTION * pPinDir
2260 )
2261 {
2262  CheckPointer(pPinDir,E_POINTER);
2263  ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION));
2264 
2265  *pPinDir = m_dir;
2266  return NOERROR;
2267 }
2268 
2269 // Default QueryId to return the pin's name
2270 STDMETHODIMP
2272  __deref_out LPWSTR * Id
2273 )
2274 {
2275  // We're not going away because someone's got a pointer to us
2276  // so there's no need to lock
2277 
2278  return AMGetWideString(Name(), Id);
2279 }
2280 
2281 /* Does this pin support this media type WARNING this interface function does
2282  not lock the main object as it is meant to be asynchronous by nature - if
2283  the media types you support depend on some internal state that is updated
2284  dynamically then you will need to implement locking in a derived class */
2285 
2286 STDMETHODIMP
2288  const AM_MEDIA_TYPE *pmt
2289 )
2290 {
2291  CheckPointer(pmt,E_POINTER);
2292  ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
2293 
2294  /* The CheckMediaType method is valid to return error codes if the media
2295  type is horrible, an example might be E_INVALIDARG. What we do here
2296  is map all the error codes into either S_OK or S_FALSE regardless */
2297 
2298  HRESULT hr = CheckMediaType((CMediaType*)pmt);
2299  if (FAILED(hr)) {
2300  return S_FALSE;
2301  }
2302  // note that the only defined success codes should be S_OK and S_FALSE...
2303  return hr;
2304 }
2305 
2306 
2307 /* This can be called to return an enumerator for the pin's list of preferred
2308  media types. An input pin is not obliged to have any preferred formats
2309  although it can do. For example, the window renderer has a preferred type
2310  which describes a video image that matches the current window size. All
2311  output pins should expose at least one preferred format otherwise it is
2312  possible that neither pin has any types and so no connection is possible */
2313 
2314 STDMETHODIMP
2316  __deref_out IEnumMediaTypes **ppEnum
2317 )
2318 {
2319  CheckPointer(ppEnum,E_POINTER);
2320  ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
2321 
2322  /* Create a new ref counted enumerator */
2323 
2324  *ppEnum = new CEnumMediaTypes(this,
2325  NULL);
2326 
2327  if (*ppEnum == NULL) {
2328  return E_OUTOFMEMORY;
2329  }
2330 
2331  return NOERROR;
2332 }
2333 
2334 
2335 
2336 /* This is a virtual function that returns a media type corresponding with
2337  place iPosition in the list. This base class simply returns an error as
2338  we support no media types by default but derived classes should override */
2339 
2340 HRESULT CBasePin::GetMediaType(int iPosition, __inout CMediaType *pMediaType)
2341 {
2342  UNREFERENCED_PARAMETER(iPosition);
2343  UNREFERENCED_PARAMETER(pMediaType);
2344  return E_UNEXPECTED;
2345 }
2346 
2347 
2348 /* This is a virtual function that returns the current media type version.
2349  The base class initialises the media type enumerators with the value 1
2350  By default we always returns that same value. A Derived class may change
2351  the list of media types available and after doing so it should increment
2352  the version either in a method derived from this, or more simply by just
2353  incrementing the m_TypeVersion base pin variable. The type enumerators
2354  call this when they want to see if their enumerations are out of date */
2355 
2357 {
2358  return m_TypeVersion;
2359 }
2360 
2361 
2362 /* Increment the cookie representing the current media type version */
2363 
2365 {
2366  InterlockedIncrement(&m_TypeVersion);
2367 }
2368 
2369 
2370 /* Called by IMediaFilter implementation when the state changes from Stopped
2371  to either paused or running and in derived classes could do things like
2372  commit memory and grab hardware resource (the default is to do nothing) */
2373 
2374 HRESULT
2376 {
2377  return NOERROR;
2378 }
2379 
2380 /* Called by IMediaFilter implementation when the state changes from
2381  to either paused to running and in derived classes could do things like
2382  commit memory and grab hardware resource (the default is to do nothing) */
2383 
2384 HRESULT
2385 CBasePin::Run(REFERENCE_TIME tStart)
2386 {
2387  UNREFERENCED_PARAMETER(tStart);
2388  return NOERROR;
2389 }
2390 
2391 
2392 /* Also called by the IMediaFilter implementation when the state changes to
2393  Stopped at which point you should decommit allocators and free hardware
2394  resources you grabbed in the Active call (default is also to do nothing) */
2395 
2396 HRESULT
2398 {
2399  m_bRunTimeError = FALSE;
2400  return NOERROR;
2401 }
2402 
2403 
2404 // Called when no more data will arrive
2405 STDMETHODIMP
2407 {
2408  return S_OK;
2409 }
2410 
2411 
2412 STDMETHODIMP
2413 CBasePin::SetSink(IQualityControl * piqc)
2414 {
2415  CAutoLock cObjectLock(m_pLock);
2416  if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl));
2417  m_pQSink = piqc;
2418  return NOERROR;
2419 } // SetSink
2420 
2421 
2422 STDMETHODIMP
2423 CBasePin::Notify(IBaseFilter * pSender, Quality q)
2424 {
2425  UNREFERENCED_PARAMETER(q);
2426  UNREFERENCED_PARAMETER(pSender);
2427  DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)");
2428  return E_NOTIMPL;
2429 } //Notify
2430 
2431 
2432 // NewSegment notifies of the start/stop/rate applying to the data
2433 // about to be received. Default implementation records data and
2434 // returns S_OK.
2435 // Override this to pass downstream.
2436 STDMETHODIMP
2438  REFERENCE_TIME tStart,
2439  REFERENCE_TIME tStop,
2440  double dRate)
2441 {
2442  m_tStart = tStart;
2443  m_tStop = tStop;
2444  m_dRate = dRate;
2445 
2446  return S_OK;
2447 }
2448 
2449 
2450 //=====================================================================
2451 //=====================================================================
2452 // Implements CBaseOutputPin
2453 //=====================================================================
2454 //=====================================================================
2455 
2456 
2457 CBaseOutputPin::CBaseOutputPin(__in_opt LPCTSTR pObjectName,
2458  __in CBaseFilter *pFilter,
2459  __in CCritSec *pLock,
2460  __inout HRESULT *phr,
2461  __in_opt LPCWSTR pName) :
2462  CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
2463  m_pAllocator(NULL),
2464  m_pInputPin(NULL)
2465 {
2466  ASSERT(pFilter);
2467 }
2468 
2469 #ifdef UNICODE
2470 CBaseOutputPin::CBaseOutputPin(__in_opt LPCSTR pObjectName,
2471  __in CBaseFilter *pFilter,
2472  __in CCritSec *pLock,
2473  __inout HRESULT *phr,
2474  __in_opt LPCWSTR pName) :
2475  CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
2476  m_pAllocator(NULL),
2477  m_pInputPin(NULL)
2478 {
2479  ASSERT(pFilter);
2480 }
2481 #endif
2482 
2483 /* This is called after a media type has been proposed
2484 
2485  Try to complete the connection by agreeing the allocator
2486 */
2487 HRESULT
2489 {
2490  UNREFERENCED_PARAMETER(pReceivePin);
2492 }
2493 
2494 
2495 /* This method is called when the output pin is about to try and connect to
2496  an input pin. It is at this point that you should try and grab any extra
2497  interfaces that you need, in this case IMemInputPin. Because this is
2498  only called if we are not currently connected we do NOT need to call
2499  BreakConnect. This also makes it easier to derive classes from us as
2500  BreakConnect is only called when we actually have to break a connection
2501  (or a partly made connection) and not when we are checking a connection */
2502 
2503 /* Overriden from CBasePin */
2504 
2505 HRESULT
2507 {
2508  HRESULT hr = CBasePin::CheckConnect(pPin);
2509  if (FAILED(hr)) {
2510  return hr;
2511  }
2512 
2513  // get an input pin and an allocator interface
2514  hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin);
2515  if (FAILED(hr)) {
2516  return hr;
2517  }
2518  return NOERROR;
2519 }
2520 
2521 
2522 /* Overriden from CBasePin */
2523 
2524 HRESULT
2526 {
2527  /* Release any allocator we hold */
2528 
2529  if (m_pAllocator) {
2530  // Always decommit the allocator because a downstream filter may or
2531  // may not decommit the connection's allocator. A memory leak could
2532  // occur if the allocator is not decommited when a connection is broken.
2533  HRESULT hr = m_pAllocator->Decommit();
2534  if( FAILED( hr ) ) {
2535  return hr;
2536  }
2537 
2538  m_pAllocator->Release();
2539  m_pAllocator = NULL;
2540  }
2541 
2542  /* Release any input pin interface we hold */
2543 
2544  if (m_pInputPin) {
2545  m_pInputPin->Release();
2546  m_pInputPin = NULL;
2547  }
2548  return NOERROR;
2549 }
2550 
2551 
2552 /* This is called when the input pin didn't give us a valid allocator */
2553 
2554 HRESULT
2555 CBaseOutputPin::InitAllocator(__deref_out IMemAllocator **ppAlloc)
2556 {
2557  return CreateMemoryAllocator(ppAlloc);
2558 }
2559 
2560 
2561 /* Decide on an allocator, override this if you want to use your own allocator
2562  Override DecideBufferSize to call SetProperties. If the input pin fails
2563  the GetAllocator call then this will construct a CMemAllocator and call
2564  DecideBufferSize on that, and if that fails then we are completely hosed.
2565  If the you succeed the DecideBufferSize call, we will notify the input
2566  pin of the selected allocator. NOTE this is called during Connect() which
2567  therefore looks after grabbing and locking the object's critical section */
2568 
2569 // We query the input pin for its requested properties and pass this to
2570 // DecideBufferSize to allow it to fulfill requests that it is happy
2571 // with (eg most people don't care about alignment and are thus happy to
2572 // use the downstream pin's alignment request).
2573 
2574 HRESULT
2575 CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **ppAlloc)
2576 {
2577  HRESULT hr = NOERROR;
2578  *ppAlloc = NULL;
2579 
2580  // get downstream prop request
2581  // the derived class may modify this in DecideBufferSize, but
2582  // we assume that he will consistently modify it the same way,
2583  // so we only get it once
2584  ALLOCATOR_PROPERTIES prop;
2585  ZeroMemory(&prop, sizeof(prop));
2586 
2587  // whatever he returns, we assume prop is either all zeros
2588  // or he has filled it out.
2589  pPin->GetAllocatorRequirements(&prop);
2590 
2591  // if he doesn't care about alignment, then set it to 1
2592  if (prop.cbAlign == 0) {
2593  prop.cbAlign = 1;
2594  }
2595 
2596  /* Try the allocator provided by the input pin */
2597 
2598  hr = pPin->GetAllocator(ppAlloc);
2599  if (SUCCEEDED(hr)) {
2600 
2601  hr = DecideBufferSize(*ppAlloc, &prop);
2602  if (SUCCEEDED(hr)) {
2603  hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
2604  if (SUCCEEDED(hr)) {
2605  return NOERROR;
2606  }
2607  }
2608  }
2609 
2610  /* If the GetAllocator failed we may not have an interface */
2611 
2612  if (*ppAlloc) {
2613  (*ppAlloc)->Release();
2614  *ppAlloc = NULL;
2615  }
2616 
2617  /* Try the output pin's allocator by the same method */
2618 
2619  hr = InitAllocator(ppAlloc);
2620  if (SUCCEEDED(hr)) {
2621 
2622  // note - the properties passed here are in the same
2623  // structure as above and may have been modified by
2624  // the previous call to DecideBufferSize
2625  hr = DecideBufferSize(*ppAlloc, &prop);
2626  if (SUCCEEDED(hr)) {
2627  hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
2628  if (SUCCEEDED(hr)) {
2629  return NOERROR;
2630  }
2631  }
2632  }
2633 
2634  /* Likewise we may not have an interface to release */
2635 
2636  if (*ppAlloc) {
2637  (*ppAlloc)->Release();
2638  *ppAlloc = NULL;
2639  }
2640  return hr;
2641 }
2642 
2643 
2644 /* This returns an empty sample buffer from the allocator WARNING the same
2645  dangers and restrictions apply here as described below for Deliver() */
2646 
2647 HRESULT
2648 CBaseOutputPin::GetDeliveryBuffer(__deref_out IMediaSample ** ppSample,
2649  __in_opt REFERENCE_TIME * pStartTime,
2650  __in_opt REFERENCE_TIME * pEndTime,
2651  DWORD dwFlags)
2652 {
2653  if (m_pAllocator != NULL) {
2654  return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags);
2655  } else {
2656  return E_NOINTERFACE;
2657  }
2658 }
2659 
2660 
2661 /* Deliver a filled-in sample to the connected input pin. NOTE the object must
2662  have locked itself before calling us otherwise we may get halfway through
2663  executing this method only to find the filter graph has got in and
2664  disconnected us from the input pin. If the filter has no worker threads
2665  then the lock is best applied on Receive(), otherwise it should be done
2666  when the worker thread is ready to deliver. There is a wee snag to worker
2667  threads that this shows up. The worker thread must lock the object when
2668  it is ready to deliver a sample, but it may have to wait until a state
2669  change has completed, but that may never complete because the state change
2670  is waiting for the worker thread to complete. The way to handle this is for
2671  the state change code to grab the critical section, then set an abort event
2672  for the worker thread, then release the critical section and wait for the
2673  worker thread to see the event we set and then signal that it has finished
2674  (with another event). At which point the state change code can complete */
2675 
2676 // note (if you've still got any breath left after reading that) that you
2677 // need to release the sample yourself after this call. if the connected
2678 // input pin needs to hold onto the sample beyond the call, it will addref
2679 // the sample itself.
2680 
2681 // of course you must release this one and call GetDeliveryBuffer for the
2682 // next. You cannot reuse it directly.
2683 
2684 HRESULT
2685 CBaseOutputPin::Deliver(IMediaSample * pSample)
2686 {
2687  if (m_pInputPin == NULL) {
2688  return VFW_E_NOT_CONNECTED;
2689  }
2690 
2691 #ifdef DXMPERF
2692  PERFLOG_DELIVER( m_pName ? m_pName : L"CBaseOutputPin", (IPin *) this, (IPin *) m_pInputPin, pSample, &m_mt );
2693 #endif // DXMPERF
2694 
2695  return m_pInputPin->Receive(pSample);
2696 }
2697 
2698 
2699 // called from elsewhere in our filter to pass EOS downstream to
2700 // our connected input pin
2701 HRESULT
2703 {
2704  // remember this is on IPin not IMemInputPin
2705  if (m_Connected == NULL) {
2706  return VFW_E_NOT_CONNECTED;
2707  }
2708  return m_Connected->EndOfStream();
2709 }
2710 
2711 
2712 /* Commit the allocator's memory, this is called through IMediaFilter
2713  which is responsible for locking the object before calling us */
2714 
2715 HRESULT
2717 {
2718  if (m_pAllocator == NULL) {
2719  return VFW_E_NO_ALLOCATOR;
2720  }
2721  return m_pAllocator->Commit();
2722 }
2723 
2724 
2725 /* Free up or unprepare allocator's memory, this is called through
2726  IMediaFilter which is responsible for locking the object first */
2727 
2728 HRESULT
2730 {
2731  m_bRunTimeError = FALSE;
2732  if (m_pAllocator == NULL) {
2733  return VFW_E_NO_ALLOCATOR;
2734  }
2735  return m_pAllocator->Decommit();
2736 }
2737 
2738 // we have a default handling of EndOfStream which is to return
2739 // an error, since this should be called on input pins only
2740 STDMETHODIMP
2742 {
2743  return E_UNEXPECTED;
2744 }
2745 
2746 
2747 // BeginFlush should be called on input pins only
2748 STDMETHODIMP
2750 {
2751  return E_UNEXPECTED;
2752 }
2753 
2754 // EndFlush should be called on input pins only
2755 STDMETHODIMP
2757 {
2758  return E_UNEXPECTED;
2759 }
2760 
2761 // call BeginFlush on the connected input pin
2762 HRESULT
2764 {
2765  // remember this is on IPin not IMemInputPin
2766  if (m_Connected == NULL) {
2767  return VFW_E_NOT_CONNECTED;
2768  }
2769  return m_Connected->BeginFlush();
2770 }
2771 
2772 // call EndFlush on the connected input pin
2773 HRESULT
2775 {
2776  // remember this is on IPin not IMemInputPin
2777  if (m_Connected == NULL) {
2778  return VFW_E_NOT_CONNECTED;
2779  }
2780  return m_Connected->EndFlush();
2781 }
2782 // deliver NewSegment to connected pin
2783 HRESULT
2785  REFERENCE_TIME tStart,
2786  REFERENCE_TIME tStop,
2787  double dRate)
2788 {
2789  if (m_Connected == NULL) {
2790  return VFW_E_NOT_CONNECTED;
2791  }
2792  return m_Connected->NewSegment(tStart, tStop, dRate);
2793 }
2794 
2795 
2796 //=====================================================================
2797 //=====================================================================
2798 // Implements CBaseInputPin
2799 //=====================================================================
2800 //=====================================================================
2801 
2802 
2803 /* Constructor creates a default allocator object */
2804 
2805 CBaseInputPin::CBaseInputPin(__in_opt LPCTSTR pObjectName,
2806  __in CBaseFilter *pFilter,
2807  __in CCritSec *pLock,
2808  __inout HRESULT *phr,
2809  __in_opt LPCWSTR pPinName) :
2810  CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
2811  m_pAllocator(NULL),
2812  m_bReadOnly(FALSE),
2813  m_bFlushing(FALSE)
2814 {
2815  ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
2816 }
2817 
2818 #ifdef UNICODE
2819 CBaseInputPin::CBaseInputPin(__in LPCSTR pObjectName,
2820  __in CBaseFilter *pFilter,
2821  __in CCritSec *pLock,
2822  __inout HRESULT *phr,
2823  __in_opt LPCWSTR pPinName) :
2824  CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
2825  m_pAllocator(NULL),
2826  m_bReadOnly(FALSE),
2827  m_bFlushing(FALSE)
2828 {
2829  ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
2830 }
2831 #endif
2832 
2833 /* Destructor releases it's reference count on the default allocator */
2834 
2836 {
2837  if (m_pAllocator != NULL) {
2838  m_pAllocator->Release();
2839  m_pAllocator = NULL;
2840  }
2841 }
2842 
2843 
2844 // override this to publicise our interfaces
2845 STDMETHODIMP
2846 CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
2847 {
2848  /* Do we know about this interface */
2849 
2850  if (riid == IID_IMemInputPin) {
2851  return GetInterface((IMemInputPin *) this, ppv);
2852  } else {
2854  }
2855 }
2856 
2857 
2858 /* Return the allocator interface that this input pin would like the output
2859  pin to use. NOTE subsequent calls to GetAllocator should all return an
2860  interface onto the SAME object so we create one object at the start
2861 
2862  Note:
2863  The allocator is Release()'d on disconnect and replaced on
2864  NotifyAllocator().
2865 
2866  Override this to provide your own allocator.
2867 */
2868 
2869 STDMETHODIMP
2871  __deref_out IMemAllocator **ppAllocator)
2872 {
2873  CheckPointer(ppAllocator,E_POINTER);
2874  ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
2875  CAutoLock cObjectLock(m_pLock);
2876 
2877  if (m_pAllocator == NULL) {
2879  if (FAILED(hr)) {
2880  return hr;
2881  }
2882  }
2883  ASSERT(m_pAllocator != NULL);
2884  *ppAllocator = m_pAllocator;
2885  m_pAllocator->AddRef();
2886  return NOERROR;
2887 }
2888 
2889 
2890 /* Tell the input pin which allocator the output pin is actually going to use
2891  Override this if you care - NOTE the locking we do both here and also in
2892  GetAllocator is unnecessary but derived classes that do something useful
2893  will undoubtedly have to lock the object so this might help remind people */
2894 
2895 STDMETHODIMP
2897  IMemAllocator * pAllocator,
2898  BOOL bReadOnly)
2899 {
2900  CheckPointer(pAllocator,E_POINTER);
2901  ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
2902  CAutoLock cObjectLock(m_pLock);
2903 
2904  IMemAllocator *pOldAllocator = m_pAllocator;
2905  pAllocator->AddRef();
2906  m_pAllocator = pAllocator;
2907 
2908  if (pOldAllocator != NULL) {
2909  pOldAllocator->Release();
2910  }
2911 
2912  // the readonly flag indicates whether samples from this allocator should
2913  // be regarded as readonly - if true, then inplace transforms will not be
2914  // allowed.
2915  m_bReadOnly = (BYTE)bReadOnly;
2916  return NOERROR;
2917 }
2918 
2919 
2920 HRESULT
2922 {
2923  /* We don't need our allocator any more */
2924  if (m_pAllocator) {
2925  // Always decommit the allocator because a downstream filter may or
2926  // may not decommit the connection's allocator. A memory leak could
2927  // occur if the allocator is not decommited when a pin is disconnected.
2928  HRESULT hr = m_pAllocator->Decommit();
2929  if( FAILED( hr ) ) {
2930  return hr;
2931  }
2932 
2933  m_pAllocator->Release();
2934  m_pAllocator = NULL;
2935  }
2936 
2937  return S_OK;
2938 }
2939 
2940 
2941 /* Do something with this media sample - this base class checks to see if the
2942  format has changed with this media sample and if so checks that the filter
2943  will accept it, generating a run time error if not. Once we have raised a
2944  run time error we set a flag so that no more samples will be accepted
2945 
2946  It is important that any filter should override this method and implement
2947  synchronization so that samples are not processed when the pin is
2948  disconnected etc
2949 */
2950 
2951 STDMETHODIMP
2952 CBaseInputPin::Receive(IMediaSample *pSample)
2953 {
2954  CheckPointer(pSample,E_POINTER);
2955  ValidateReadPtr(pSample,sizeof(IMediaSample));
2956  ASSERT(pSample);
2957 
2958  HRESULT hr = CheckStreaming();
2959  if (S_OK != hr) {
2960  return hr;
2961  }
2962 
2963 #ifdef DXMPERF
2964  PERFLOG_RECEIVE( m_pName ? m_pName : L"CBaseInputPin", (IPin *) m_Connected, (IPin *) this, pSample, &m_mt );
2965 #endif // DXMPERF
2966 
2967 
2968  /* Check for IMediaSample2 */
2969  IMediaSample2 *pSample2;
2970  if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
2971  hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps);
2972  pSample2->Release();
2973  if (FAILED(hr)) {
2974  return hr;
2975  }
2976  } else {
2977  /* Get the properties the hard way */
2978  m_SampleProps.cbData = sizeof(m_SampleProps);
2979  m_SampleProps.dwTypeSpecificFlags = 0;
2980  m_SampleProps.dwStreamId = AM_STREAM_MEDIA;
2981  m_SampleProps.dwSampleFlags = 0;
2982  if (S_OK == pSample->IsDiscontinuity()) {
2983  m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
2984  }
2985  if (S_OK == pSample->IsPreroll()) {
2986  m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL;
2987  }
2988  if (S_OK == pSample->IsSyncPoint()) {
2989  m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
2990  }
2991  if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart,
2992  &m_SampleProps.tStop))) {
2993  m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID |
2994  AM_SAMPLE_STOPVALID;
2995  }
2996  if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) {
2997  m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
2998  }
2999  pSample->GetPointer(&m_SampleProps.pbBuffer);
3000  m_SampleProps.lActual = pSample->GetActualDataLength();
3001  m_SampleProps.cbBuffer = pSample->GetSize();
3002  }
3003 
3004  /* Has the format changed in this sample */
3005 
3006  if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) {
3007  return NOERROR;
3008  }
3009 
3010  /* Check the derived class accepts this format */
3011  /* This shouldn't fail as the source must call QueryAccept first */
3012 
3013  hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType);
3014 
3015  if (hr == NOERROR) {
3016  return NOERROR;
3017  }
3018 
3019  /* Raise a runtime error if we fail the media type */
3020 
3021  m_bRunTimeError = TRUE;
3022  EndOfStream();
3023  m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
3024  return VFW_E_INVALIDMEDIATYPE;
3025 }
3026 
3027 
3028 /* Receive multiple samples */
3029 STDMETHODIMP
3031  __in_ecount(nSamples) IMediaSample **pSamples,
3032  long nSamples,
3033  __out long *nSamplesProcessed)
3034 {
3035  CheckPointer(pSamples,E_POINTER);
3036  ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *));
3037 
3038  HRESULT hr = S_OK;
3039  *nSamplesProcessed = 0;
3040  while (nSamples-- > 0) {
3041  hr = Receive(pSamples[*nSamplesProcessed]);
3042 
3043  /* S_FALSE means don't send any more */
3044  if (hr != S_OK) {
3045  break;
3046  }
3047  (*nSamplesProcessed)++;
3048  }
3049  return hr;
3050 }
3051 
3052 /* See if Receive() might block */
3053 STDMETHODIMP
3055 {
3056  /* Ask all the output pins if they block
3057  If there are no output pin assume we do block
3058  */
3059  int cPins = m_pFilter->GetPinCount();
3060  int cOutputPins = 0;
3061  for (int c = 0; c < cPins; c++) {
3062  CBasePin *pPin = m_pFilter->GetPin(c);
3063  if (NULL == pPin) {
3064  break;
3065  }
3066  PIN_DIRECTION pd;
3067  HRESULT hr = pPin->QueryDirection(&pd);
3068  if (FAILED(hr)) {
3069  return hr;
3070  }
3071 
3072  if (pd == PINDIR_OUTPUT) {
3073 
3074  IPin *pConnected;
3075  hr = pPin->ConnectedTo(&pConnected);
3076  if (SUCCEEDED(hr)) {
3077  ASSERT(pConnected != NULL);
3078  cOutputPins++;
3079  IMemInputPin *pInputPin;
3080  hr = pConnected->QueryInterface(
3081  IID_IMemInputPin,
3082  (void **)&pInputPin);
3083  pConnected->Release();
3084  if (SUCCEEDED(hr)) {
3085  hr = pInputPin->ReceiveCanBlock();
3086  pInputPin->Release();
3087  if (hr != S_FALSE) {
3088  return S_OK;
3089  }
3090  } else {
3091  /* There's a transport we don't understand here */
3092  return S_OK;
3093  }
3094  }
3095  }
3096  }
3097  return cOutputPins == 0 ? S_OK : S_FALSE;
3098 }
3099 
3100 // Default handling for BeginFlush - call at the beginning
3101 // of your implementation (makes sure that all Receive calls
3102 // fail). After calling this, you need to free any queued data
3103 // and then call downstream.
3104 STDMETHODIMP
3106 {
3107  // BeginFlush is NOT synchronized with streaming but is part of
3108  // a control action - hence we synchronize with the filter
3109  CAutoLock lck(m_pLock);
3110 
3111  // if we are already in mid-flush, this is probably a mistake
3112  // though not harmful - try to pick it up for now so I can think about it
3113  ASSERT(!m_bFlushing);
3114 
3115  // first thing to do is ensure that no further Receive calls succeed
3116  m_bFlushing = TRUE;
3117 
3118  // now discard any data and call downstream - must do that
3119  // in derived classes
3120  return S_OK;
3121 }
3122 
3123 // default handling for EndFlush - call at end of your implementation
3124 // - before calling this, ensure that there is no queued data and no thread
3125 // pushing any more without a further receive, then call downstream,
3126 // then call this method to clear the m_bFlushing flag and re-enable
3127 // receives
3128 STDMETHODIMP
3130 {
3131  // Endlush is NOT synchronized with streaming but is part of
3132  // a control action - hence we synchronize with the filter
3133  CAutoLock lck(m_pLock);
3134 
3135  // almost certainly a mistake if we are not in mid-flush
3137 
3138  // before calling, sync with pushing thread and ensure
3139  // no more data is going downstream, then call EndFlush on
3140  // downstream pins.
3141 
3142  // now re-enable Receives
3143  m_bFlushing = FALSE;
3144 
3145  // No more errors
3146  m_bRunTimeError = FALSE;
3147 
3148  return S_OK;
3149 }
3150 
3151 
3152 STDMETHODIMP
3153 CBaseInputPin::Notify(IBaseFilter * pSender, Quality q)
3154 {
3155  UNREFERENCED_PARAMETER(q);
3156  CheckPointer(pSender,E_POINTER);
3157  ValidateReadPtr(pSender,sizeof(IBaseFilter));
3158  DbgBreak("IQuality::Notify called on an input pin");
3159  return NOERROR;
3160 } // Notify
3161 
3162 /* Free up or unprepare allocator's memory, this is called through
3163  IMediaFilter which is responsible for locking the object first */
3164 
3165 HRESULT
3167 {
3168  m_bRunTimeError = FALSE;
3169  if (m_pAllocator == NULL) {
3170  return VFW_E_NO_ALLOCATOR;
3171  }
3172 
3173  m_bFlushing = FALSE;
3174 
3175  return m_pAllocator->Decommit();
3176 }
3177 
3178 // what requirements do we have of the allocator - override if you want
3179 // to support other people's allocators but need a specific alignment
3180 // or prefix.
3181 STDMETHODIMP
3182 CBaseInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps)
3183 {
3184  UNREFERENCED_PARAMETER(pProps);
3185  return E_NOTIMPL;
3186 }
3187 
3188 // Check if it's OK to process data
3189 //
3190 HRESULT
3192 {
3193  // Shouldn't be able to get any data if we're not connected!
3194  ASSERT(IsConnected());
3195 
3196  // Don't process stuff in Stopped state
3197  if (IsStopped()) {
3198  return VFW_E_WRONG_STATE;
3199  }
3200  if (m_bFlushing) {
3201  return S_FALSE;
3202  }
3203  if (m_bRunTimeError) {
3204  return VFW_E_RUNTIME_ERROR;
3205  }
3206  return S_OK;
3207 }
3208 
3209 // Pass on the Quality notification q to
3210 // a. Our QualityControl sink (if we have one) or else
3211 // b. to our upstream filter
3212 // and if that doesn't work, throw it away with a bad return code
3213 HRESULT
3215 {
3216  // We pass the message on, which means that we find the quality sink
3217  // for our input pin and send it there
3218 
3219  DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform")));
3220  if (m_pQSink!=NULL) {
3221  return m_pQSink->Notify(m_pFilter, q);
3222  } else {
3223  // no sink set, so pass it upstream
3224  HRESULT hr;
3225  IQualityControl * pIQC;
3226 
3227  hr = VFW_E_NOT_FOUND; // default
3228  if (m_Connected) {
3229  m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
3230 
3231  if (pIQC!=NULL) {
3232  hr = pIQC->Notify(m_pFilter, q);
3233  pIQC->Release();
3234  }
3235  }
3236  return hr;
3237  }
3238 
3239 } // PassNotify
3240 
3241 //=====================================================================
3242 //=====================================================================
3243 // Memory allocation class, implements CMediaSample
3244 //=====================================================================
3245 //=====================================================================
3246 
3247 
3248 /* NOTE The implementation of this class calls the CUnknown constructor with
3249  a NULL outer unknown pointer. This has the effect of making us a self
3250  contained class, ie any QueryInterface, AddRef or Release calls will be
3251  routed to the class's NonDelegatingUnknown methods. You will typically
3252  find that the classes that do this then override one or more of these
3253  virtual functions to provide more specialised behaviour. A good example
3254  of this is where a class wants to keep the QueryInterface internal but
3255  still wants it's lifetime controlled by the external object */
3256 
3257 /* The last two parameters have default values of NULL and zero */
3258 
3260  __in_opt CBaseAllocator *pAllocator,
3261  __inout_opt HRESULT *phr,
3262  __in_bcount_opt(length) LPBYTE pBuffer,
3263  LONG length) :
3264  m_pBuffer(pBuffer), // Initialise the buffer
3265  m_cbBuffer(length), // And it's length
3266  m_lActual(length), // By default, actual = length
3267  m_pMediaType(NULL), // No media type change
3268  m_dwFlags(0), // Nothing set
3269  m_cRef(0), // 0 ref count
3270  m_dwTypeSpecificFlags(0), // Type specific flags
3271  m_dwStreamId(AM_STREAM_MEDIA), // Stream id
3272  m_pAllocator(pAllocator) // Allocator
3273 {
3274 #ifdef DXMPERF
3275  PERFLOG_CTOR( pName ? pName : L"CMediaSample", (IMediaSample *) this );
3276 #endif // DXMPERF
3277 
3278  /* We must have an owner and it must also be derived from class
3279  CBaseAllocator BUT we do not hold a reference count on it */
3280 
3281  ASSERT(pAllocator);
3282 
3283  if (length < 0) {
3284  *phr = VFW_E_BUFFER_OVERFLOW;
3285  m_cbBuffer = 0;
3286  }
3287 }
3288 
3289 #ifdef UNICODE
3290 CMediaSample::CMediaSample(__in_opt LPCSTR pName,
3291  __in_opt CBaseAllocator *pAllocator,
3292  __inout_opt HRESULT *phr,
3293  __in_bcount_opt(length) LPBYTE pBuffer,
3294  LONG length) :
3295  m_pBuffer(pBuffer), // Initialise the buffer
3296  m_cbBuffer(length), // And it's length
3297  m_lActual(length), // By default, actual = length
3298  m_pMediaType(NULL), // No media type change
3299  m_dwFlags(0), // Nothing set
3300  m_cRef(0), // 0 ref count
3301  m_dwTypeSpecificFlags(0), // Type specific flags
3302  m_dwStreamId(AM_STREAM_MEDIA), // Stream id
3303  m_pAllocator(pAllocator) // Allocator
3304 {
3305 #ifdef DXMPERF
3306  PERFLOG_CTOR( L"CMediaSample", (IMediaSample *) this );
3307 #endif // DXMPERF
3308 
3309  /* We must have an owner and it must also be derived from class
3310  CBaseAllocator BUT we do not hold a reference count on it */
3311 
3312  ASSERT(pAllocator);
3313 }
3314 #endif
3315 
3316 /* Destructor deletes the media type memory */
3317 
3319 {
3320 #ifdef DXMPERF
3321  PERFLOG_DTOR( L"CMediaSample", (IMediaSample *) this );
3322 #endif // DXMPERF
3323 
3324  if (m_pMediaType) {
3326  }
3327 }
3328 
3329 /* Override this to publicise our interfaces */
3330 
3331 STDMETHODIMP
3332 CMediaSample::QueryInterface(REFIID riid, __deref_out void **ppv)
3333 {
3334  if (riid == IID_IMediaSample ||
3335  riid == IID_IMediaSample2 ||
3336  riid == IID_IUnknown) {
3337  return GetInterface((IMediaSample *) this, ppv);
3338  } else {
3339  *ppv = NULL;
3340  return E_NOINTERFACE;
3341  }
3342 }
3343 
3345 CMediaSample::AddRef()
3346 {
3347  return InterlockedIncrement(&m_cRef);
3348 }
3349 
3350 
3351 // -- CMediaSample lifetimes --
3352 //
3353 // On final release of this sample buffer it is not deleted but
3354 // returned to the freelist of the owning memory allocator
3355 //
3356 // The allocator may be waiting for the last buffer to be placed on the free
3357 // list in order to decommit all the memory, so the ReleaseBuffer() call may
3358 // result in this sample being deleted. We also need to hold a refcount on
3359 // the allocator to stop that going away until we have finished with this.
3360 // However, we cannot release the allocator before the ReleaseBuffer, as the
3361 // release may cause us to be deleted. Similarly we can't do it afterwards.
3362 //
3363 // Thus we must leave it to the allocator to hold an addref on our behalf.
3364 // When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer
3365 // is called, he releases himself, possibly causing us and him to be deleted.
3366 
3367 
3369 CMediaSample::Release()
3370 {
3371  /* Decrement our own private reference count */
3372  LONG lRef;
3373  if (m_cRef == 1) {
3374  lRef = 0;
3375  m_cRef = 0;
3376  } else {
3377  lRef = InterlockedDecrement(&m_cRef);
3378  }
3379  ASSERT(lRef >= 0);
3380 
3381  DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"),
3382  this, m_cRef));
3383 
3384  /* Did we release our final reference count */
3385  if (lRef == 0) {
3386  /* Free all resources */
3387  if (m_dwFlags & Sample_TypeChanged) {
3388  SetMediaType(NULL);
3389  }
3390  ASSERT(m_pMediaType == NULL);
3391  m_dwFlags = 0;
3393  m_dwStreamId = AM_STREAM_MEDIA;
3394 
3395  /* This may cause us to be deleted */
3396  // Our refcount is reliably 0 thus no-one will mess with us
3397  m_pAllocator->ReleaseBuffer(this);
3398  }
3399  return (ULONG)lRef;
3400 }
3401 
3402 
3403 // set the buffer pointer and length. Used by allocators that
3404 // want variable sized pointers or pointers into already-read data.
3405 // This is only available through a CMediaSample* not an IMediaSample*
3406 // and so cannot be changed by clients.
3407 HRESULT
3408 CMediaSample::SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes)
3409 {
3410  if (cBytes < 0) {
3411  return VFW_E_BUFFER_OVERFLOW;
3412  }
3413  m_pBuffer = ptr; // new buffer area (could be null)
3414  m_cbBuffer = cBytes; // length of buffer
3415  m_lActual = cBytes; // length of data in buffer (assume full)
3416 
3417  return S_OK;
3418 }
3419 
3420 
3421 // get me a read/write pointer to this buffer's memory. I will actually
3422 // want to use sizeUsed bytes.
3423 STDMETHODIMP
3424 CMediaSample::GetPointer(__deref_out BYTE ** ppBuffer)
3425 {
3426  ValidateReadWritePtr(ppBuffer,sizeof(BYTE *));
3427 
3428  // creator must have set pointer either during
3429  // constructor or by SetPointer
3430  ASSERT(m_pBuffer);
3431 
3432  *ppBuffer = m_pBuffer;
3433  return NOERROR;
3434 }
3435 
3436 
3437 // return the size in bytes of this buffer
3438 STDMETHODIMP_(LONG)
3439 CMediaSample::GetSize(void)
3440 {
3441  return m_cbBuffer;
3442 }
3443 
3444 
3445 // get the stream time at which this sample should start and finish.
3446 STDMETHODIMP
3448  __out REFERENCE_TIME * pTimeStart, // put time here
3449  __out REFERENCE_TIME * pTimeEnd
3450 )
3451 {
3452  ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME));
3453  ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME));
3454 
3455  if (!(m_dwFlags & Sample_StopValid)) {
3456  if (!(m_dwFlags & Sample_TimeValid)) {
3457  return VFW_E_SAMPLE_TIME_NOT_SET;
3458  } else {
3459  *pTimeStart = m_Start;
3460 
3461  // Make sure old stuff works
3462  *pTimeEnd = m_Start + 1;
3463  return VFW_S_NO_STOP_TIME;
3464  }
3465  }
3466 
3467  *pTimeStart = m_Start;
3468  *pTimeEnd = m_End;
3469  return NOERROR;
3470 }
3471 
3472 
3473 // Set the stream time at which this sample should start and finish.
3474 // NULL pointers means the time is reset
3475 STDMETHODIMP
3477  __in_opt REFERENCE_TIME * pTimeStart,
3478  __in_opt REFERENCE_TIME * pTimeEnd
3479 )
3480 {
3481  if (pTimeStart == NULL) {
3482  ASSERT(pTimeEnd == NULL);
3484  } else {
3485  if (pTimeEnd == NULL) {
3486  m_Start = *pTimeStart;
3489  } else {
3490  ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME));
3491  ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME));
3492  ASSERT(*pTimeEnd >= *pTimeStart);
3493 
3494  m_Start = *pTimeStart;
3495  m_End = *pTimeEnd;
3497  }
3498  }
3499  return NOERROR;
3500 }
3501 
3502 
3503 // get the media times (eg bytes) for this sample
3504 STDMETHODIMP
3506  __out LONGLONG * pTimeStart,
3507  __out LONGLONG * pTimeEnd
3508 )
3509 {
3510  ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG));
3511  ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG));
3512 
3513  if (!(m_dwFlags & Sample_MediaTimeValid)) {
3514  return VFW_E_MEDIA_TIME_NOT_SET;
3515  }
3516 
3517  *pTimeStart = m_MediaStart;
3518  *pTimeEnd = (m_MediaStart + m_MediaEnd);
3519  return NOERROR;
3520 }
3521 
3522 
3523 // Set the media times for this sample
3524 STDMETHODIMP
3526  __in_opt LONGLONG * pTimeStart,
3527  __in_opt LONGLONG * pTimeEnd
3528 )
3529 {
3530  if (pTimeStart == NULL) {
3531  ASSERT(pTimeEnd == NULL);
3533  } else {
3534  if (NULL == pTimeEnd) {
3535  return E_POINTER;
3536  }
3537  ValidateReadPtr(pTimeStart,sizeof(LONGLONG));
3538  ValidateReadPtr(pTimeEnd,sizeof(LONGLONG));
3539  ASSERT(*pTimeEnd >= *pTimeStart);
3540 
3541  m_MediaStart = *pTimeStart;
3542  m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart);
3544  }
3545  return NOERROR;
3546 }
3547 
3548 
3549 STDMETHODIMP
3551 {
3552  if (m_dwFlags & Sample_SyncPoint) {
3553  return S_OK;
3554  } else {
3555  return S_FALSE;
3556  }
3557 }
3558 
3559 
3560 STDMETHODIMP
3561 CMediaSample::SetSyncPoint(BOOL bIsSyncPoint)
3562 {
3563  if (bIsSyncPoint) {
3565  } else {
3567  }
3568  return NOERROR;
3569 }
3570 
3571 // returns S_OK if there is a discontinuity in the data (this same is
3572 // not a continuation of the previous stream of data
3573 // - there has been a seek).
3574 STDMETHODIMP
3576 {
3578  return S_OK;
3579  } else {
3580  return S_FALSE;
3581  }
3582 }
3583 
3584 // set the discontinuity property - TRUE if this sample is not a
3585 // continuation, but a new sample after a seek.
3586 STDMETHODIMP
3588 {
3589  // should be TRUE or FALSE
3590  if (bDiscont) {
3592  } else {
3594  }
3595  return S_OK;
3596 }
3597 
3598 STDMETHODIMP
3600 {
3601  if (m_dwFlags & Sample_Preroll) {
3602  return S_OK;
3603  } else {
3604  return S_FALSE;
3605  }
3606 }
3607 
3608 
3609 STDMETHODIMP
3611 {
3612  if (bIsPreroll) {
3614  } else {
3616  }
3617  return NOERROR;
3618 }
3619 
3620 STDMETHODIMP_(LONG)
3621 CMediaSample::GetActualDataLength(void)
3622 {
3623  return m_lActual;
3624 }
3625 
3626 
3627 STDMETHODIMP
3629 {
3630  if (lActual > m_cbBuffer || lActual < 0) {
3631  ASSERT(lActual <= GetSize());
3632  return VFW_E_BUFFER_OVERFLOW;
3633  }
3634  m_lActual = lActual;
3635  return NOERROR;
3636 }
3637 
3638 
3639 /* These allow for limited format changes in band */
3640 
3641 STDMETHODIMP
3642 CMediaSample::GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType)
3643 {
3644  ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *));
3645  ASSERT(ppMediaType);
3646 
3647  /* Do we have a new media type for them */
3648 
3649  if (!(m_dwFlags & Sample_TypeChanged)) {
3650  ASSERT(m_pMediaType == NULL);
3651  *ppMediaType = NULL;
3652  return S_FALSE;
3653  }
3654 
3656 
3657  /* Create a copy of our media type */
3658 
3659  *ppMediaType = CreateMediaType(m_pMediaType);
3660  if (*ppMediaType == NULL) {
3661  return E_OUTOFMEMORY;
3662  }
3663  return NOERROR;
3664 }
3665 
3666 
3667 /* Mark this sample as having a different format type */
3668 
3669 STDMETHODIMP
3670 CMediaSample::SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType)
3671 {
3672  /* Delete the current media type */
3673 
3674  if (m_pMediaType) {
3676  m_pMediaType = NULL;
3677  }
3678 
3679  /* Mechanism for resetting the format type */
3680 
3681  if (pMediaType == NULL) {
3683  return NOERROR;
3684  }
3685 
3686  ASSERT(pMediaType);
3687  ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE));
3688 
3689  /* Take a copy of the media type */
3690 
3691  m_pMediaType = CreateMediaType(pMediaType);
3692  if (m_pMediaType == NULL) {
3694  return E_OUTOFMEMORY;
3695  }
3696 
3698  return NOERROR;
3699 }
3700 
3701 // Set and get properties (IMediaSample2)
3703  DWORD cbProperties,
3704  __out_bcount(cbProperties) BYTE * pbProperties
3705 )
3706 {
3707  if (0 != cbProperties) {
3708  CheckPointer(pbProperties, E_POINTER);
3709  // Return generic stuff up to the length
3710  AM_SAMPLE2_PROPERTIES Props;
3711  Props.cbData = min(cbProperties, sizeof(Props));
3712  Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid;
3713  Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags;
3714  Props.pbBuffer = m_pBuffer;
3715  Props.cbBuffer = m_cbBuffer;
3716  Props.lActual = m_lActual;
3717  Props.tStart = m_Start;
3718  Props.tStop = m_End;
3719  Props.dwStreamId = m_dwStreamId;
3720  if (m_dwFlags & AM_SAMPLE_TYPECHANGED) {
3721  Props.pMediaType = m_pMediaType;
3722  } else {
3723  Props.pMediaType = NULL;
3724  }
3725  CopyMemory(pbProperties, &Props, Props.cbData);
3726  }
3727  return S_OK;
3728 }
3729 
3730 #define CONTAINS_FIELD(type, field, offset) \
3731  ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset)
3732 
3734  DWORD cbProperties,
3735  __in_bcount(cbProperties) const BYTE * pbProperties
3736 )
3737 {
3738 
3739  /* Generic properties */
3740  AM_MEDIA_TYPE *pMediaType = NULL;
3741 
3742  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) {
3743  CheckPointer(pbProperties, E_POINTER);
3744  AM_SAMPLE2_PROPERTIES *pProps =
3745  (AM_SAMPLE2_PROPERTIES *)pbProperties;
3746 
3747  /* Don't use more data than is actually there */
3748  if (pProps->cbData < cbProperties) {
3749  cbProperties = pProps->cbData;
3750  }
3751  /* We only handle IMediaSample2 */
3752  if (cbProperties > sizeof(*pProps) ||
3753  pProps->cbData > sizeof(*pProps)) {
3754  return E_INVALIDARG;
3755  }
3756  /* Do checks first, the assignments (for backout) */
3757  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
3758  /* Check the flags */
3759  if (pProps->dwSampleFlags &
3761  return E_INVALIDARG;
3762  }
3763  /* Check a flag isn't being set for a property
3764  not being provided
3765  */
3766  if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) &&
3767  !(m_dwFlags & AM_SAMPLE_TIMEVALID) &&
3768  !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
3769  return E_INVALIDARG;
3770  }
3771  }
3772  /* NB - can't SET the pointer or size */
3773  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) {
3774 
3775  /* Check pbBuffer */
3776  if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) {
3777  return E_INVALIDARG;
3778  }
3779  }
3780  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) {
3781 
3782  /* Check cbBuffer */
3783  if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) {
3784  return E_INVALIDARG;
3785  }
3786  }
3787  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) &&
3788  CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
3789 
3790  /* Check lActual */
3791  if (pProps->cbBuffer < pProps->lActual) {
3792  return E_INVALIDARG;
3793  }
3794  }
3795 
3796  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
3797 
3798  /* Check pMediaType */
3799  if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
3800  CheckPointer(pProps->pMediaType, E_POINTER);
3801  pMediaType = CreateMediaType(pProps->pMediaType);
3802  if (pMediaType == NULL) {
3803  return E_OUTOFMEMORY;
3804  }
3805  }
3806  }
3807 
3808  /* Now do the assignments */
3809  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) {
3810  m_dwStreamId = pProps->dwStreamId;
3811  }
3812  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
3813  /* Set the flags */
3814  m_dwFlags = pProps->dwSampleFlags |
3816  m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
3817  } else {
3818  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) {
3819  m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
3820  }
3821  }
3822 
3823  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
3824  /* Set lActual */
3825  m_lActual = pProps->lActual;
3826  }
3827 
3828  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
3829 
3830  /* Set the times */
3831  m_End = pProps->tStop;
3832  }
3833  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) {
3834 
3835  /* Set the times */
3836  m_Start = pProps->tStart;
3837  }
3838 
3839  if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
3840  /* Set pMediaType */
3841  if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
3842  if (m_pMediaType != NULL) {
3844  }
3845  m_pMediaType = pMediaType;
3846  }
3847  }
3848 
3849  /* Fix up the type changed flag to correctly reflect the current state
3850  If, for instance the input contained no type change but the
3851  output does then if we don't do this we'd lose the
3852  output media type.
3853  */
3854  if (m_pMediaType) {
3856  } else {
3858  }
3859  }
3860 
3861  return S_OK;
3862 }
3863 
3864 
3865 //
3866 // The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(),
3867 // IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the
3868 // connected input pin. The application thread calls Block(). The
3869 // following class members can only be called by the streaming thread.
3870 //
3871 // Deliver()
3872 // DeliverNewSegment()
3873 // StartUsingOutputPin()
3874 // StopUsingOutputPin()
3875 // ChangeOutputFormat()
3876 // ChangeMediaType()
3877 // DynamicReconnect()
3878 //
3879 // The following class members can only be called by the application thread.
3880 //
3881 // Block()
3882 // SynchronousBlockOutputPin()
3883 // AsynchronousBlockOutputPin()
3884 //
3885 
3887  __in_opt LPCTSTR pObjectName,
3888  __in CBaseFilter *pFilter,
3889  __in CCritSec *pLock,
3890  __inout HRESULT *phr,
3891  __in_opt LPCWSTR pName) :
3892  CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
3893  m_hStopEvent(NULL),
3894  m_pGraphConfig(NULL),
3895  m_bPinUsesReadOnlyAllocator(FALSE),
3896  m_BlockState(NOT_BLOCKED),
3897  m_hUnblockOutputPinEvent(NULL),
3898  m_hNotifyCallerPinBlockedEvent(NULL),
3899  m_dwBlockCallerThreadID(0),
3900  m_dwNumOutstandingOutputPinUsers(0)
3901 {
3902  HRESULT hr = Initialize();
3903  if( FAILED( hr ) ) {
3904  *phr = hr;
3905  return;
3906  }
3907 }
3908 
3909 #ifdef UNICODE
3911  __in_opt LPCSTR pObjectName,
3912  __in CBaseFilter *pFilter,
3913  __in CCritSec *pLock,
3914  __inout HRESULT *phr,
3915  __in_opt LPCWSTR pName) :
3916  CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
3917  m_hStopEvent(NULL),
3918  m_pGraphConfig(NULL),
3919  m_bPinUsesReadOnlyAllocator(FALSE),
3920  m_BlockState(NOT_BLOCKED),
3921  m_hUnblockOutputPinEvent(NULL),
3922  m_hNotifyCallerPinBlockedEvent(NULL),
3923  m_dwBlockCallerThreadID(0),
3924  m_dwNumOutstandingOutputPinUsers(0)
3925 {
3926  HRESULT hr = Initialize();
3927  if( FAILED( hr ) ) {
3928  *phr = hr;
3929  return;
3930  }
3931 }
3932 #endif
3933 
3935 {
3937  // This call should not fail because we have access to m_hUnblockOutputPinEvent
3938  // and m_hUnblockOutputPinEvent is a valid event.
3939  EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent));
3940  }
3941 
3943  // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent
3944  // and m_hNotifyCallerPinBlockedEvent is a valid event.
3946  }
3947 }
3948 
3949 HRESULT CDynamicOutputPin::Initialize(void)
3950 {
3951  m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor.
3952  TRUE, // This is a manual reset event.
3953  TRUE, // The event is initially signaled.
3954  NULL ); // The event is not named.
3955 
3956  // CreateEvent() returns NULL if an error occurs.
3958  return AmGetLastErrorToHResult();
3959  }
3960 
3961  // Set flag to say we can reconnect while streaming.
3962  SetReconnectWhenActive(true);
3963 
3964  return S_OK;
3965 }
3966 
3967 STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
3968 {
3969  if(riid == IID_IPinFlowControl) {
3970  return GetInterface(static_cast<IPinFlowControl*>(this), ppv);
3971  } else {
3973  }
3974 }
3975 
3977 {
3978  CAutoLock cObjectLock(m_pLock);
3979  return DisconnectInternal();
3980 }
3981 
3982 STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent)
3983 {
3984  const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK;
3985 
3986  // Check for illegal flags.
3987  if(dwBlockFlags & ~VALID_FLAGS) {
3988  return E_INVALIDARG;
3989  }
3990 
3991  // Make sure the event is unsignaled.
3992  if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) {
3993  if( !::ResetEvent( hEvent ) ) {
3994  return AmGetLastErrorToHResult();
3995  }
3996  }
3997 
3998  // No flags are set if we are unblocking the output pin.
3999  if(0 == dwBlockFlags) {
4000 
4001  // This parameter should be NULL because unblock operations are always synchronous.
4002  // There is no need to notify the caller when the event is done.
4003  if(NULL != hEvent) {
4004  return E_INVALIDARG;
4005  }
4006  }
4007 
4008  #ifdef DEBUG
4009  AssertValid();
4010  #endif // DEBUG
4011 
4012  HRESULT hr;
4013 
4014  if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) {
4015  // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous.
4016  // If hEvent is not NULL, the block is asynchronous.
4017  if(NULL == hEvent) {
4019  } else {
4020  hr = AsynchronousBlockOutputPin(hEvent);
4021  }
4022  } else {
4023  hr = UnblockOutputPin();
4024  }
4025 
4026  #ifdef DEBUG
4027  AssertValid();
4028  #endif // DEBUG
4029 
4030  if(FAILED(hr)) {
4031  return hr;
4032  }
4033 
4034  return S_OK;
4035 }
4036 
4038 {
4039  HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes.
4040  FALSE, // This is an automatic reset event.
4041  FALSE, // The event is initially unsignaled.
4042  NULL ); // The event is not named.
4043 
4044  // CreateEvent() returns NULL if an error occurs.
4045  if(NULL == hNotifyCallerPinBlockedEvent) {
4046  return AmGetLastErrorToHResult();
4047  }
4048 
4049  HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent);
4050  if(FAILED(hr)) {
4051  // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
4052  // and hNotifyCallerPinBlockedEvent is a valid event.
4053  EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
4054 
4055  return hr;
4056  }
4057 
4058  hr = WaitEvent(hNotifyCallerPinBlockedEvent);
4059 
4060  // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
4061  // and hNotifyCallerPinBlockedEvent is a valid event.
4062  EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
4063 
4064  if(FAILED(hr)) {
4065  return hr;
4066  }
4067 
4068  return S_OK;
4069 }
4070 
4071 HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent)
4072 {
4073  // This function holds the m_BlockStateLock because it uses
4074  // m_dwBlockCallerThreadID, m_BlockState and
4075  // m_hNotifyCallerPinBlockedEvent.
4076  CAutoLock alBlockStateLock(&m_BlockStateLock);
4077 
4078  if(NOT_BLOCKED != m_BlockState) {
4079  if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) {
4080  return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD;
4081  } else {
4082  return VFW_E_PIN_ALREADY_BLOCKED;
4083  }
4084  }
4085 
4086  BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(),
4087  hNotifyCallerPinBlockedEvent,
4088  ::GetCurrentProcess(),
4090  EVENT_MODIFY_STATE,
4091  FALSE,
4092  0 );
4093  if( !fSuccess ) {
4094  return AmGetLastErrorToHResult();
4095  }
4096 
4098  m_dwBlockCallerThreadID = ::GetCurrentThreadId();
4099 
4100  // The output pin cannot be blocked if the streaming thread is
4101  // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive()
4102  // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it
4103  // cannot be blocked if the streaming thread is calling DynamicReconnect(),
4104  // ChangeMediaType() or ChangeOutputFormat().
4106 
4107  // The output pin can be immediately blocked.
4108  BlockOutputPin();
4109  }
4110 
4111  return S_OK;
4112 }
4113 
4115 {
4116  // The caller should always hold the m_BlockStateLock because this function
4117  // uses m_BlockState and m_hNotifyCallerPinBlockedEvent.
4119 
4120  // This function should not be called if the streaming thread is modifying
4121  // the connection state or it's passing data downstream.
4123 
4124  // This should not fail because we successfully created the event
4125  // and we have the security permissions to change it's state.
4127 
4128  // This event should not fail because AsynchronousBlockOutputPin() successfully
4129  // duplicated this handle and we have the appropriate security permissions.
4132 
4135 }
4136 
4138 {
4139  // UnblockOutputPin() holds the m_BlockStateLock because it
4140  // uses m_BlockState, m_dwBlockCallerThreadID and
4141  // m_hNotifyCallerPinBlockedEvent.
4142  CAutoLock alBlockStateLock(&m_BlockStateLock);
4143 
4144  if(NOT_BLOCKED == m_BlockState) {
4145  return S_FALSE;
4146  }
4147 
4148  // This should not fail because we successfully created the event
4149  // and we have the security permissions to change it's state.
4151 
4152  // Cancel the block operation if it's still pending.
4154  // This event should not fail because AsynchronousBlockOutputPin() successfully
4155  // duplicated this handle and we have the appropriate security permissions.
4158  }
4159 
4163 
4164  return S_OK;
4165 }
4166 
4168 {
4169  // The caller should not hold m_BlockStateLock. If the caller does,
4170  // a deadlock could occur.
4172 
4173  CAutoLock alBlockStateLock(&m_BlockStateLock);
4174 
4175  #ifdef DEBUG
4176  AssertValid();
4177  #endif // DEBUG
4178 
4179  // Are we in the middle of a block operation?
4180  while(BLOCKED == m_BlockState) {
4182 
4183  // If this ASSERT fires, a deadlock could occur. The caller should make sure
4184  // that this thread never acquires the Block State lock more than once.
4186 
4187  // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event
4188  // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired.
4189  // See the Windows SDK documentation for more information on
4190  // WaitForMultipleObjects().
4191  const DWORD UNBLOCK = WAIT_OBJECT_0;
4192  const DWORD STOP = WAIT_OBJECT_0 + 1;
4193 
4194  HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent };
4195  DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE);
4196 
4197  DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE );
4198 
4200 
4201  #ifdef DEBUG
4202  AssertValid();
4203  #endif // DEBUG
4204 
4205  switch( dwReturnValue ) {
4206  case UNBLOCK:
4207  break;
4208 
4209  case STOP:
4210  return VFW_E_STATE_CHANGED;
4211 
4212  case WAIT_FAILED:
4213  return AmGetLastErrorToHResult();
4214 
4215  default:
4216  DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." );
4217  return E_UNEXPECTED;
4218  }
4219  }
4220 
4222 
4223  #ifdef DEBUG
4224  AssertValid();
4225  #endif // DEBUG
4226 
4227  return S_OK;
4228 }
4229 
4231 {
4232  CAutoLock alBlockStateLock(&m_BlockStateLock);
4233 
4234  #ifdef DEBUG
4235  AssertValid();
4236  #endif // DEBUG
4237 
4239 
4241  BlockOutputPin();
4242  }
4243 
4244  #ifdef DEBUG
4245  AssertValid();
4246  #endif // DEBUG
4247 }
4248 
4250 {
4251  CAutoLock alBlockStateLock(&m_BlockStateLock);
4252 
4253  return (m_dwNumOutstandingOutputPinUsers > 0);
4254 }
4255 
4256 void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent)
4257 {
4258  // This pointer is not addrefed because filters are not allowed to
4259  // hold references to the filter graph manager. See the documentation for
4260  // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information.
4261  m_pGraphConfig = pGraphConfig;
4262 
4263  m_hStopEvent = hStopEvent;
4264 }
4265 
4267 {
4268  // Make sure the user initialized the object by calling SetConfigInfo().
4269  if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) {
4270  DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. );
4271  return E_FAIL;
4272  }
4273 
4274  // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4275  // The ASSERT can also fire if the event if destroyed and then Active() is called. An event
4276  // handle is invalid if 1) the event does not exist or the user does not have the security
4277  // permissions to use the event.
4278  EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
4279 
4280  return CBaseOutputPin::Active();
4281 }
4282 
4284 {
4285  // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4286  // The ASSERT can also fire if the event if destroyed and then Active() is called. An event
4287  // handle is invalid if 1) the event does not exist or the user does not have the security
4288  // permissions to use the event.
4289  EXECUTE_ASSERT(SetEvent(m_hStopEvent));
4290 
4291  return CBaseOutputPin::Inactive();
4292 }
4293 
4295 {
4296  // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4297  // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
4298  // An event handle is invalid if 1) the event does not exist or the user does not have the security
4299  // permissions to use the event.
4300  EXECUTE_ASSERT(SetEvent(m_hStopEvent));
4301 
4303 }
4304 
4306 {
4307  // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4308  // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
4309  // An event handle is invalid if 1) the event does not exist or the user does not have the security
4310  // permissions to use the event.
4311  EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
4312 
4314 }
4315 
4316 
4317 // ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly
4318 // reconnects the output pin.
4320  (
4321  const AM_MEDIA_TYPE *pmt,
4322  REFERENCE_TIME tSegmentStart,
4323  REFERENCE_TIME tSegmentStop,
4324  double dSegmentRate
4325  )
4326 {
4327  // The caller should call StartUsingOutputPin() before calling this
4328  // method.
4329  ASSERT(StreamingThreadUsingOutputPin());
4330 
4331  // Callers should always pass a valid media type to ChangeOutputFormat() .
4332  ASSERT(NULL != pmt);
4333 
4334  CMediaType cmt(*pmt);
4335  HRESULT hr = ChangeMediaType(&cmt);
4336  if (FAILED(hr)) {
4337  return hr;
4338  }
4339 
4340  hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate);
4341  if( FAILED( hr ) ) {
4342  return hr;
4343  }
4344 
4345  return S_OK;
4346 }
4347 
4349 {
4350  // The caller should call StartUsingOutputPin() before calling this
4351  // method.
4353 
4354  // This function assumes the filter graph is running.
4355  ASSERT(!IsStopped());
4356 
4357  if(!IsConnected()) {
4358  return VFW_E_NOT_CONNECTED;
4359  }
4360 
4361  /* First check if the downstream pin will accept a dynamic
4362  format change
4363  */
4364  QzCComPtr<IPinConnection> pConnection;
4365 
4366  m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection);
4367  if(pConnection != NULL) {
4368 
4369  if(S_OK == pConnection->DynamicQueryAccept(pmt)) {
4370 
4371  HRESULT hr = ChangeMediaTypeHelper(pmt);
4372  if(FAILED(hr)) {
4373  return hr;
4374  }
4375 
4376  return S_OK;
4377  }
4378  }
4379 
4380  /* Can't do the dynamic connection */
4381  return DynamicReconnect(pmt);
4382 }
4383 
4384 HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt)
4385 {
4386  // The caller should call StartUsingOutputPin() before calling this
4387  // method.
4389 
4390  HRESULT hr = m_Connected->ReceiveConnection(this, pmt);
4391  if(FAILED(hr)) {
4392  return hr;
4393  }
4394 
4395  hr = SetMediaType(pmt);
4396  if(FAILED(hr)) {
4397  return hr;
4398  }
4399 
4400  // Does this pin use the local memory transport?
4401  if(NULL != m_pInputPin) {
4402  // This function assumes that m_pInputPin and m_Connected are
4403  // two different interfaces to the same object.
4405 
4406  ALLOCATOR_PROPERTIES apInputPinRequirements;
4407  apInputPinRequirements.cbAlign = 0;
4408  apInputPinRequirements.cbBuffer = 0;
4409  apInputPinRequirements.cbPrefix = 0;
4410  apInputPinRequirements.cBuffers = 0;
4411 
4412  m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements);
4413 
4414  // A zero allignment does not make any sense.
4415  if(0 == apInputPinRequirements.cbAlign) {
4416  apInputPinRequirements.cbAlign = 1;
4417  }
4418 
4419  hr = m_pAllocator->Decommit();
4420  if(FAILED(hr)) {
4421  return hr;
4422  }
4423 
4424  hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements);
4425  if(FAILED(hr)) {
4426  return hr;
4427  }
4428 
4429  hr = m_pAllocator->Commit();
4430  if(FAILED(hr)) {
4431  return hr;
4432  }
4433 
4435  if(FAILED(hr)) {
4436  return hr;
4437  }
4438  }
4439 
4440  return S_OK;
4441 }
4442 
4443 // this method has to be called from the thread that is pushing data,
4444 // and it's the caller's responsibility to make sure that the thread
4445 // has no outstand samples because they cannot be delivered after a
4446 // reconnect
4447 //
4449 {
4450  // The caller should call StartUsingOutputPin() before calling this
4451  // method.
4453 
4454  if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) {
4455  return E_FAIL;
4456  }
4457 
4458  HRESULT hr = m_pGraphConfig->Reconnect(
4459  this,
4460  NULL,
4461  pmt,
4462  NULL,
4463  m_hStopEvent,
4464  AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS );
4465 
4466  return hr;
4467 }
4468 
4469 HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin)
4470 {
4471  HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
4472  if(SUCCEEDED(hr)) {
4473  if(!IsStopped() && m_pAllocator) {
4474  hr = m_pAllocator->Commit();
4475  ASSERT(hr != VFW_E_ALREADY_COMMITTED);
4476  }
4477  }
4478 
4479  return hr;
4480 }
4481 
4482 #ifdef DEBUG
4483 void CDynamicOutputPin::AssertValid(void)
4484 {
4485  // Make sure the object was correctly initialized.
4486 
4487  // This ASSERT only fires if the object failed to initialize
4488  // and the user ignored the constructor's return code (phr).
4490 
4491  // If either of these ASSERTs fire, the user did not correctly call
4492  // SetConfigInfo().
4493  ASSERT(NULL != m_hStopEvent);
4495 
4496  // Make sure the block state is consistent.
4497 
4498  CAutoLock alBlockStateLock(&m_BlockStateLock);
4499 
4500  // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED.
4502 
4503  // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete
4504  // immediately.
4507 
4508  // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and
4509  // the user is not trying to block the pin.
4511 
4512  // If this ASSERT fires, the streaming thread is using the output pin and the
4513  // output pin is blocked.
4517 }
4518 #endif // DEBUG
4519 
4521 {
4522  const DWORD EVENT_SIGNALED = WAIT_OBJECT_0;
4523 
4524  DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE);
4525 
4526  switch( dwReturnValue ) {
4527  case EVENT_SIGNALED:
4528  return S_OK;
4529 
4530  case WAIT_FAILED:
4531  return AmGetLastErrorToHResult();
4532 
4533  default:
4534  DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." );
4535  return E_UNEXPECTED;
4536  }
4537 }
4538 
4539 //=====================================================================
4540 //=====================================================================
4541 // Implements CBaseAllocator
4542 //=====================================================================
4543 //=====================================================================
4544 
4545 
4546 /* Constructor overrides the default settings for the free list to request
4547  that it be alertable (ie the list can be cast to a handle which can be
4548  passed to WaitForSingleObject). Both of the allocator lists also ask for
4549  object locking, the all list matches the object default settings but I
4550  have included them here just so it is obvious what kind of list it is */
4551 
4553  __inout_opt LPUNKNOWN pUnk,
4554  __inout HRESULT *phr,
4555  BOOL bEvent,
4556  BOOL fEnableReleaseCallback
4557  ) :
4558  CUnknown(pName, pUnk),
4559  m_lAllocated(0),
4560  m_bChanged(FALSE),
4561  m_bCommitted(FALSE),
4562  m_bDecommitInProgress(FALSE),
4563  m_lSize(0),
4564  m_lCount(0),
4565  m_lAlignment(0),
4566  m_lPrefix(0),
4567  m_hSem(NULL),
4568  m_lWaiting(0),
4569  m_fEnableReleaseCallback(fEnableReleaseCallback),
4570  m_pNotify(NULL)
4571 {
4572 #ifdef DXMPERF
4573  PERFLOG_CTOR( pName ? pName : L"CBaseAllocator", (IMemAllocator *) this );
4574 #endif // DXMPERF
4575 
4576  if (bEvent) {
4577  m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
4578  if (m_hSem == NULL) {
4579  *phr = E_OUTOFMEMORY;
4580  return;
4581  }
4582  }
4583 }
4584 
4585 #ifdef UNICODE
4586 CBaseAllocator::CBaseAllocator(__in_opt LPCSTR pName,
4587  __inout_opt LPUNKNOWN pUnk,
4588  __inout HRESULT *phr,
4589  BOOL bEvent,
4590  BOOL fEnableReleaseCallback) :
4591  CUnknown(pName, pUnk),
4592  m_lAllocated(0),
4593  m_bChanged(FALSE),
4594  m_bCommitted(FALSE),
4595  m_bDecommitInProgress(FALSE),
4596  m_lSize(0),
4597  m_lCount(0),
4598  m_lAlignment(0),
4599  m_lPrefix(0),
4600  m_hSem(NULL),
4601  m_lWaiting(0),
4602  m_fEnableReleaseCallback(fEnableReleaseCallback),
4603  m_pNotify(NULL)
4604 {
4605 #ifdef DXMPERF
4606  PERFLOG_CTOR( L"CBaseAllocator", (IMemAllocator *) this );
4607 #endif // DXMPERF
4608 
4609  if (bEvent) {
4610  m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
4611  if (m_hSem == NULL) {
4612  *phr = E_OUTOFMEMORY;
4613  return;
4614  }
4615  }
4616 }
4617 #endif
4618 
4619 /* Destructor */
4620 
4622 {
4623  // we can't call Decommit here since that would mean a call to a
4624  // pure virtual in destructor.
4625  // We must assume that the derived class has gone into decommit state in
4626  // its destructor.
4627 #ifdef DXMPERF
4628  PERFLOG_DTOR( L"CBaseAllocator", (IMemAllocator *) this );
4629 #endif // DXMPERF
4630 
4631  ASSERT(!m_bCommitted);
4632  if (m_hSem != NULL) {
4633  EXECUTE_ASSERT(CloseHandle(m_hSem));
4634  }
4635  if (m_pNotify) {
4636  m_pNotify->Release();
4637  }
4638 }
4639 
4640 
4641 /* Override this to publicise our interfaces */
4642 
4643 STDMETHODIMP
4644 CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
4645 {
4646  /* Do we know about this interface */
4647 
4648  if (riid == IID_IMemAllocator ||
4649  riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) {
4650  return GetInterface((IMemAllocatorCallbackTemp *) this, ppv);
4651  } else {
4653  }
4654 }
4655 
4656 
4657 /* This sets the size and count of the required samples. The memory isn't
4658  actually allocated until Commit() is called, if memory has already been
4659  allocated then assuming no samples are outstanding the user may call us
4660  to change the buffering, the memory will be released in Commit() */
4661 
4662 STDMETHODIMP
4664  __in ALLOCATOR_PROPERTIES* pRequest,
4665  __out ALLOCATOR_PROPERTIES* pActual)
4666 {
4667  CheckPointer(pRequest, E_POINTER);
4668  CheckPointer(pActual, E_POINTER);
4669  ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
4670  CAutoLock cObjectLock(this);
4671 
4672  ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
4673 
4674  ASSERT(pRequest->cbBuffer > 0);
4675 
4676  /* Check the alignment requested */
4677  if (pRequest->cbAlign != 1) {
4678  DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"),
4679  pRequest->cbAlign));
4680  return VFW_E_BADALIGN;
4681  }
4682 
4683  /* Can't do this if already committed, there is an argument that says we
4684  should not reject the SetProperties call if there are buffers still
4685  active. However this is called by the source filter, which is the same
4686  person who is holding the samples. Therefore it is not unreasonable
4687  for them to free all their samples before changing the requirements */
4688 
4689  if (m_bCommitted) {
4690  return VFW_E_ALREADY_COMMITTED;
4691  }
4692 
4693  /* Must be no outstanding buffers */
4694 
4695  if (m_lAllocated != m_lFree.GetCount()) {
4696  return VFW_E_BUFFERS_OUTSTANDING;
4697  }
4698 
4699  /* There isn't any real need to check the parameters as they
4700  will just be rejected when the user finally calls Commit */
4701 
4702  pActual->cbBuffer = m_lSize = pRequest->cbBuffer;
4703  pActual->cBuffers = m_lCount = pRequest->cBuffers;
4704  pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
4705  pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
4706 
4707  m_bChanged = TRUE;
4708  return NOERROR;
4709 }
4710 
4711 STDMETHODIMP
4713  __out ALLOCATOR_PROPERTIES * pActual)
4714 {
4715  CheckPointer(pActual,E_POINTER);
4716  ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
4717 
4718  CAutoLock cObjectLock(this);
4719  pActual->cbBuffer = m_lSize;
4720  pActual->cBuffers = m_lCount;
4721  pActual->cbAlign = m_lAlignment;
4722  pActual->cbPrefix = m_lPrefix;
4723  return NOERROR;
4724 }
4725 
4726 // get container for a sample. Blocking, synchronous call to get the
4727 // next free buffer (as represented by an IMediaSample interface).
4728 // on return, the time etc properties will be invalid, but the buffer
4729 // pointer and size will be correct.
4730 
4731 HRESULT CBaseAllocator::GetBuffer(__deref_out IMediaSample **ppBuffer,
4732  __in_opt REFERENCE_TIME *pStartTime,
4733  __in_opt REFERENCE_TIME *pEndTime,
4734  DWORD dwFlags
4735  )
4736 {
4737  UNREFERENCED_PARAMETER(pStartTime);
4738  UNREFERENCED_PARAMETER(pEndTime);
4739  UNREFERENCED_PARAMETER(dwFlags);
4740  CMediaSample *pSample;
4741 
4742  *ppBuffer = NULL;
4743  for (;;)
4744  {
4745  { // scope for lock
4746  CAutoLock cObjectLock(this);
4747 
4748  /* Check we are committed */
4749  if (!m_bCommitted) {
4750  return VFW_E_NOT_COMMITTED;
4751  }
4752  pSample = (CMediaSample *) m_lFree.RemoveHead();
4753  if (pSample == NULL) {
4754  SetWaiting();
4755  }
4756  }
4757 
4758  /* If we didn't get a sample then wait for the list to signal */
4759 
4760  if (pSample) {
4761  break;
4762  }
4763  if (dwFlags & AM_GBF_NOWAIT) {
4764  return VFW_E_TIMEOUT;
4765  }
4766  ASSERT(m_hSem != NULL);
4767  WaitForSingleObject(m_hSem, INFINITE);
4768  }
4769 
4770  /* Addref the buffer up to one. On release
4771  back to zero instead of being deleted, it will requeue itself by
4772  calling the ReleaseBuffer member function. NOTE the owner of a
4773  media sample must always be derived from CBaseAllocator */
4774 
4775 
4776  ASSERT(pSample->m_cRef == 0);
4777  pSample->m_cRef = 1;
4778  *ppBuffer = pSample;
4779 
4780 #ifdef DXMPERF
4781  PERFLOG_GETBUFFER( (IMemAllocator *) this, pSample );
4782 #endif // DXMPERF
4783 
4784  return NOERROR;
4785 }
4786 
4787 
4788 /* Final release of a CMediaSample will call this */
4789 
4790 STDMETHODIMP
4791 CBaseAllocator::ReleaseBuffer(IMediaSample * pSample)
4792 {
4793  CheckPointer(pSample,E_POINTER);
4794  ValidateReadPtr(pSample,sizeof(IMediaSample));
4795 
4796 #ifdef DXMPERF
4797  PERFLOG_RELBUFFER( (IMemAllocator *) this, pSample );
4798 #endif // DXMPERF
4799 
4800 
4801  BOOL bRelease = FALSE;
4802  {
4803  CAutoLock cal(this);
4804 
4805  /* Put back on the free list */
4806 
4807  m_lFree.Add((CMediaSample *)pSample);
4808  if (m_lWaiting != 0) {
4809  NotifySample();
4810  }
4811 
4812  // if there is a pending Decommit, then we need to complete it by
4813  // calling Free() when the last buffer is placed on the free list
4814 
4815  LONG l1 = m_lFree.GetCount();
4816  if (m_bDecommitInProgress && (l1 == m_lAllocated)) {
4817  Free();
4818  m_bDecommitInProgress = FALSE;
4819  bRelease = TRUE;
4820  }
4821  }
4822 
4823  if (m_pNotify) {
4824 
4826 
4827  //
4828  // Note that this is not synchronized with setting up a notification
4829  // method.
4830  //
4831  m_pNotify->NotifyRelease();
4832  }
4833 
4834  /* For each buffer there is one AddRef, made in GetBuffer and released
4835  here. This may cause the allocator and all samples to be deleted */
4836 
4837  if (bRelease) {
4838  Release();
4839  }
4840  return NOERROR;
4841 }
4842 
4843 STDMETHODIMP
4845  IMemAllocatorNotifyCallbackTemp* pNotify
4846  )
4847 {
4849  CAutoLock lck(this);
4850  if (pNotify) {
4851  pNotify->AddRef();
4852  }
4853  if (m_pNotify) {
4854  m_pNotify->Release();
4855  }
4856  m_pNotify = pNotify;
4857  return S_OK;
4858 }
4859 
4860 STDMETHODIMP
4862  __out LONG* plBuffersFree
4863  )
4864 {
4866  CAutoLock cObjectLock(this);
4867  *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount();
4868  return NOERROR;
4869 }
4870 
4871 void
4873 {
4874  if (m_lWaiting != 0) {
4875  ASSERT(m_hSem != NULL);
4876  ReleaseSemaphore(m_hSem, m_lWaiting, 0);
4877  m_lWaiting = 0;
4878  }
4879 }
4880 
4881 STDMETHODIMP
4883 {
4884  /* Check we are not decommitted */
4885  CAutoLock cObjectLock(this);
4886 
4887  // cannot need to alloc or re-alloc if we are committed
4888  if (m_bCommitted) {
4889  return NOERROR;
4890  }
4891 
4892  /* Allow GetBuffer calls */
4893 
4894  m_bCommitted = TRUE;
4895 
4896  // is there a pending decommit ? if so, just cancel it
4897  if (m_bDecommitInProgress) {
4898  m_bDecommitInProgress = FALSE;
4899 
4900  // don't call Alloc at this point. He cannot allow SetProperties
4901  // between Decommit and the last free, so the buffer size cannot have
4902  // changed. And because some of the buffers are not free yet, he
4903  // cannot re-alloc anyway.
4904  return NOERROR;
4905  }
4906 
4907  DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize));
4908 
4909  // actually need to allocate the samples
4910  HRESULT hr = Alloc();
4911  if (FAILED(hr)) {
4912  m_bCommitted = FALSE;
4913  return hr;
4914  }
4915  AddRef();
4916  return NOERROR;
4917 }
4918 
4919 
4920 STDMETHODIMP
4922 {
4923  BOOL bRelease = FALSE;
4924  {
4925  /* Check we are not already decommitted */
4926  CAutoLock cObjectLock(this);
4927  if (m_bCommitted == FALSE) {
4928  if (m_bDecommitInProgress == FALSE) {
4929  return NOERROR;
4930  }
4931  }
4932 
4933  /* No more GetBuffer calls will succeed */
4934  m_bCommitted = FALSE;
4935 
4936  // are any buffers outstanding?
4937  if (m_lFree.GetCount() < m_lAllocated) {
4938  // please complete the decommit when last buffer is freed
4939  m_bDecommitInProgress = TRUE;
4940  } else {
4941  m_bDecommitInProgress = FALSE;
4942 
4943  // need to complete the decommit here as there are no
4944  // outstanding buffers
4945 
4946  Free();
4947  bRelease = TRUE;
4948  }
4949 
4950  // Tell anyone waiting that they can go now so we can
4951  // reject their call
4952 #pragma warning(push)
4953 #ifndef _PREFAST_
4954 #pragma warning(disable:4068)
4955 #endif
4956 #pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "Suppress warning related to Free() invalidating 'this' which is no applicable to CBaseAllocator::Free()")
4957  NotifySample();
4958 
4959 #pragma warning(pop)
4960  }
4961 
4962  if (bRelease) {
4963  Release();
4964  }
4965  return NOERROR;
4966 }
4967 
4968 
4969 /* Base definition of allocation which checks we are ok to go ahead and do
4970  the full allocation. We return S_FALSE if the requirements are the same */
4971 
4972 HRESULT
4974 {
4975  /* Error if he hasn't set the size yet */
4976  if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) {
4977  return VFW_E_SIZENOTSET;
4978  }
4979 
4980  /* should never get here while buffers outstanding */
4981  ASSERT(m_lFree.GetCount() == m_lAllocated);
4982 
4983  /* If the requirements haven't changed then don't reallocate */
4984  if (m_bChanged == FALSE) {
4985  return S_FALSE;
4986  }
4987 
4988  return NOERROR;
4989 }
4990 
4991 /* Implement CBaseAllocator::CSampleList::Remove(pSample)
4992  Removes pSample from the list
4993 */
4994 void
4995 CBaseAllocator::CSampleList::Remove(__inout CMediaSample * pSample)
4996 {
4997  CMediaSample **pSearch;
4998  for (pSearch = &m_List;
4999  *pSearch != NULL;
5000  pSearch = &(CBaseAllocator::NextSample(*pSearch))) {
5001  if (*pSearch == pSample) {
5002  *pSearch = CBaseAllocator::NextSample(pSample);
5003  CBaseAllocator::NextSample(pSample) = NULL;
5004  m_nOnList--;
5005  return;
5006  }
5007  }
5008  DbgBreak("Couldn't find sample in list");
5009 }
5010 
5011 //=====================================================================
5012 //=====================================================================
5013 // Implements CMemAllocator
5014 //=====================================================================
5015 //=====================================================================
5016 
5017 
5018 /* This goes in the factory template table to create new instances */
5019 CUnknown *CMemAllocator::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr)
5020 {
5021  CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr);
5022  return pUnkRet;
5023 }
5024 
5026  __in_opt LPCTSTR pName,
5027  __inout_opt LPUNKNOWN pUnk,
5028  __inout HRESULT *phr)
5029  : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
5030  m_pBuffer(NULL)
5031 {
5032 }
5033 
5034 #ifdef UNICODE
5036  __in_opt LPCSTR pName,
5037  __inout_opt LPUNKNOWN pUnk,
5038  __inout HRESULT *phr)
5039  : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
5040  m_pBuffer(NULL)
5041 {
5042 }
5043 #endif
5044 
5045 /* This sets the size and count of the required samples. The memory isn't
5046  actually allocated until Commit() is called, if memory has already been
5047  allocated then assuming no samples are outstanding the user may call us
5048  to change the buffering, the memory will be released in Commit() */
5049 STDMETHODIMP
5051  __in ALLOCATOR_PROPERTIES* pRequest,
5052  __out ALLOCATOR_PROPERTIES* pActual)
5053 {
5054  CheckPointer(pActual,E_POINTER);
5055  ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
5056  CAutoLock cObjectLock(this);
5057 
5058  ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
5059 
5060  ASSERT(pRequest->cbBuffer > 0);
5061 
5062  SYSTEM_INFO SysInfo;
5063  GetSystemInfo(&SysInfo);
5064 
5065  /* Check the alignment request is a power of 2 */
5066  if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) {
5067  DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"),
5068  pRequest->cbAlign));
5069  }
5070  /* Check the alignment requested */
5071  if (pRequest->cbAlign == 0 ||
5072  (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) {
5073  DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"),
5074  pRequest->cbAlign, SysInfo.dwAllocationGranularity));
5075  return VFW_E_BADALIGN;
5076  }
5077 
5078  /* Can't do this if already committed, there is an argument that says we
5079  should not reject the SetProperties call if there are buffers still
5080  active. However this is called by the source filter, which is the same
5081  person who is holding the samples. Therefore it is not unreasonable
5082  for them to free all their samples before changing the requirements */
5083 
5084  if (m_bCommitted == TRUE) {
5085  return VFW_E_ALREADY_COMMITTED;
5086  }
5087 
5088  /* Must be no outstanding buffers */
5089 
5090  if (m_lFree.GetCount() < m_lAllocated) {
5091  return VFW_E_BUFFERS_OUTSTANDING;
5092  }
5093 
5094  /* There isn't any real need to check the parameters as they
5095  will just be rejected when the user finally calls Commit */
5096 
5097  // round length up to alignment - remember that prefix is included in
5098  // the alignment
5099  LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix;
5100  LONG lRemainder = lSize % pRequest->cbAlign;
5101  if (lRemainder != 0) {
5102  lSize = lSize - lRemainder + pRequest->cbAlign;
5103  }
5104  pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix);
5105 
5106  pActual->cBuffers = m_lCount = pRequest->cBuffers;
5107  pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
5108  pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
5109 
5110  m_bChanged = TRUE;
5111  return NOERROR;
5112 }
5113 
5114 // override this to allocate our resources when Commit is called.
5115 //
5116 // note that our resources may be already allocated when this is called,
5117 // since we don't free them on Decommit. We will only be called when in
5118 // decommit state with all buffers free.
5119 //
5120 // object locked by caller
5121 HRESULT
5123 {
5124  CAutoLock lck(this);
5125 
5126  /* Check he has called SetProperties */
5127  HRESULT hr = CBaseAllocator::Alloc();
5128  if (FAILED(hr)) {
5129  return hr;
5130  }
5131 
5132  /* If the requirements haven't changed then don't reallocate */
5133  if (hr == S_FALSE) {
5134  ASSERT(m_pBuffer);
5135  return NOERROR;
5136  }
5137  ASSERT(hr == S_OK); // we use this fact in the loop below
5138 
5139  /* Free the old resources */
5140  if (m_pBuffer) {
5141  ReallyFree();
5142  }
5143 
5144  /* Make sure we've got reasonable values */
5145  if ( m_lSize < 0 || m_lPrefix < 0 || m_lCount < 0 ) {
5146  return E_OUTOFMEMORY;
5147  }
5148 
5149  /* Compute the aligned size */
5150  LONG lAlignedSize = m_lSize + m_lPrefix;
5151 
5152  /* Check overflow */
5153  if (lAlignedSize < m_lSize) {
5154  return E_OUTOFMEMORY;
5155  }
5156 
5157  if (m_lAlignment > 1) {
5158  LONG lRemainder = lAlignedSize % m_lAlignment;
5159  if (lRemainder != 0) {
5160  LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder;
5161  if (lNewSize < lAlignedSize) {
5162  return E_OUTOFMEMORY;
5163  }
5164  lAlignedSize = lNewSize;
5165  }
5166  }
5167 
5168  /* Create the contiguous memory block for the samples
5169  making sure it's properly aligned (64K should be enough!)
5170  */
5171  ASSERT(lAlignedSize % m_lAlignment == 0);
5172 
5173  LONGLONG lToAllocate = m_lCount * (LONGLONG)lAlignedSize;
5174 
5175  /* Check overflow */
5176  if (lToAllocate > MAXLONG) {
5177  return E_OUTOFMEMORY;
5178  }
5179 
5180  m_pBuffer = (PBYTE)VirtualAlloc(NULL,
5181  (LONG)lToAllocate,
5182  MEM_COMMIT,
5183  PAGE_READWRITE);
5184 
5185  if (m_pBuffer == NULL) {
5186  return E_OUTOFMEMORY;
5187  }
5188 
5189  LPBYTE pNext = m_pBuffer;
5190  CMediaSample *pSample;
5191 
5192  ASSERT(m_lAllocated == 0);
5193 
5194  // Create the new samples - we have allocated m_lSize bytes for each sample
5195  // plus m_lPrefix bytes per sample as a prefix. We set the pointer to
5196  // the memory after the prefix - so that GetPointer() will return a pointer
5197  // to m_lSize bytes.
5198  for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) {
5199 
5200 
5201  pSample = new CMediaSample(
5202  NAME("Default memory media sample"),
5203  this,
5204  &hr,
5205  pNext + m_lPrefix, // GetPointer() value
5206  m_lSize); // not including prefix
5207 
5208  ASSERT(SUCCEEDED(hr));
5209  if (pSample == NULL) {
5210  return E_OUTOFMEMORY;
5211  }
5212 
5213  // This CANNOT fail
5214  m_lFree.Add(pSample);
5215  }
5216 
5217  m_bChanged = FALSE;
5218  return NOERROR;
5219 }
5220 
5221 
5222 // override this to free up any resources we have allocated.
5223 // called from the base class on Decommit when all buffers have been
5224 // returned to the free list.
5225 //
5226 // caller has already locked the object.
5227 
5228 // in our case, we keep the memory until we are deleted, so
5229 // we do nothing here. The memory is deleted in the destructor by
5230 // calling ReallyFree()
5231 void
5233 {
5234  return;
5235 }
5236 
5237 
5238 // called from the destructor (and from Alloc if changing size/count) to
5239 // actually free up the memory
5240 void
5242 {
5243  /* Should never be deleting this unless all buffers are freed */
5244 
5245  ASSERT(m_lAllocated == m_lFree.GetCount());
5246 
5247  /* Free up all the CMediaSamples */
5248 
5249  CMediaSample *pSample;
5250  for (;;) {
5251  pSample = m_lFree.RemoveHead();
5252  if (pSample != NULL) {
5253  delete pSample;
5254  } else {
5255  break;
5256  }
5257  }
5258 
5259  m_lAllocated = 0;
5260 
5261  // free the block of buffer memory
5262  if (m_pBuffer) {
5263  EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE));
5264  m_pBuffer = NULL;
5265  }
5266 }
5267 
5268 
5269 /* Destructor frees our memory resources */
5270 
5272 {
5273  Decommit();
5274  ReallyFree();
5275 }
5276 
5277 // ------------------------------------------------------------------------
5278 // filter registration through IFilterMapper. used if IFilterMapper is
5279 // not found (Quartz 1.0 install)
5280 
5281 STDAPI
5283  , IFilterMapper * pIFM
5284  , BOOL bRegister )
5285 {
5286  DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter")));
5287 
5288  // check we've got data
5289  //
5290  if( NULL == psetupdata ) return S_FALSE;
5291 
5292 
5293  // unregister filter
5294  // (as pins are subkeys of filter's CLSID key
5295  // they do not need to be removed separately).
5296  //
5297  DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter")));
5298  HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) );
5299 
5300 
5301  if( bRegister )
5302  {
5303  // register filter
5304  //
5305  DbgLog((LOG_TRACE, 3, TEXT("= = register filter")));
5306  hr = pIFM->RegisterFilter( *(psetupdata->clsID)
5307  , psetupdata->strName
5308  , psetupdata->dwMerit );
5309  if( SUCCEEDED(hr) )
5310  {
5311  // all its pins
5312  //
5313  DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins")));
5314  for( UINT m1=0; m1 < psetupdata->nPins; m1++ )
5315  {
5316  hr = pIFM->RegisterPin( *(psetupdata->clsID)
5317  , psetupdata->lpPin[m1].strName
5318  , psetupdata->lpPin[m1].bRendered
5319  , psetupdata->lpPin[m1].bOutput
5320  , psetupdata->lpPin[m1].bZero
5321  , psetupdata->lpPin[m1].bMany
5322  , *(psetupdata->lpPin[m1].clsConnectsToFilter)
5323  , psetupdata->lpPin[m1].strConnectsToPin );
5324 
5325  if( SUCCEEDED(hr) )
5326  {
5327  // and each pin's media types
5328  //
5329  DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types")));
5330  for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ )
5331  {
5332  hr = pIFM->RegisterPinType( *(psetupdata->clsID)
5333  , psetupdata->lpPin[m1].strName
5334  , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType)
5335  , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) );
5336  if( FAILED(hr) ) break;
5337  }
5338  if( FAILED(hr) ) break;
5339  }
5340  if( FAILED(hr) ) break;
5341  }
5342  }
5343  }
5344 
5345  // handle one acceptable "error" - that
5346  // of filter not being registered!
5347  // (couldn't find a suitable #define'd
5348  // name for the error!)
5349  //
5350  if( 0x80070002 == hr)
5351  return NOERROR;
5352  else
5353  return hr;
5354 }
5355 
5356 // Remove warnings about unreferenced inline functions
5357 #pragma warning(disable:4514)
5358 
CDynamicOutputPin::PENDING
@ PENDING
Definition: amfilter.h:1024
CBasePin::CBasePin
CBasePin(__in_opt LPCTSTR pObjectName, __in CBaseFilter *pFilter, __in CCritSec *pLock, __inout HRESULT *phr, __in_opt LPCWSTR pName, PIN_DIRECTION dir)
Definition: amfilter.cpp:1481
AMovieSetupRegisterFilter
STDAPI AMovieSetupRegisterFilter(const AMOVIESETUP_FILTER *const psetupdata, IFilterMapper *pIFM, BOOL bRegister)
Definition: amfilter.cpp:5282
CBaseMediaFilter::NonDelegatingQueryInterface
DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:132
CBaseInputPin::PassNotify
HRESULT PassNotify(Quality &q)
Definition: amfilter.cpp:3214
CBaseOutputPin::BeginFlush
STDMETHODIMP BeginFlush(void)
Definition: amfilter.cpp:2749
CBasePin::NonDelegatingQueryInterface
DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:1610
CMediaSample::GetPointer
STDMETHODIMP GetPointer(__deref_out BYTE **ppBuffer)
Definition: amfilter.cpp:3424
CBaseOutputPin::InitAllocator
virtual HRESULT InitAllocator(__deref_out IMemAllocator **ppAlloc)
Definition: amfilter.cpp:2555
DbgRegisterObjectCreation
#define DbgRegisterObjectCreation(pObjectName)
Definition: wxdebug.h:187
CMediaSample::m_lActual
LONG m_lActual
Definition: amfilter.h:1217
DbgRegisterObjectDestruction
#define DbgRegisterObjectDestruction(dwCookie)
Definition: wxdebug.h:188
CBaseInputPin::m_bReadOnly
BYTE m_bReadOnly
Definition: amfilter.h:830
CBasePin::m_pLock
CCritSec * m_pLock
Definition: amfilter.h:338
CBaseMediaFilter::m_State
FILTER_STATE m_State
Definition: amfilter.h:62
CBaseFilter::NotifyEvent
HRESULT NotifyEvent(long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
Definition: amfilter.cpp:811
CBaseAllocator::m_bChanged
BOOL m_bChanged
Definition: amfilter.h:1435
CMediaSample::SetProperties
STDMETHODIMP SetProperties(DWORD cbProperties, __in_bcount(cbProperties) const BYTE *pbProperties)
Definition: amfilter.cpp:3733
CONTAINS_FIELD
#define CONTAINS_FIELD(type, field, offset)
Definition: amfilter.cpp:3730
CBaseAllocator::m_lCount
long m_lCount
Definition: amfilter.h:1430
ValidateReadPtr
#define ValidateReadPtr(p, cb)
Definition: wxdebug.h:239
CDynamicOutputPin::m_dwBlockCallerThreadID
DWORD m_dwBlockCallerThreadID
Definition: amfilter.h:1051
CDynamicOutputPin::m_hNotifyCallerPinBlockedEvent
HANDLE m_hNotifyCallerPinBlockedEvent
Definition: amfilter.h:1043
CEnumPins::Next
STDMETHODIMP Next(ULONG cPins, __out_ecount(cPins) IPin **ppPins, __out_opt ULONG *pcFetched)
Definition: amfilter.cpp:1086
CBasePin::Active
virtual HRESULT Active(void)
Definition: amfilter.cpp:2375
CMemAllocator::~CMemAllocator
~CMemAllocator()
Definition: amfilter.cpp:5271
CBaseFilter::m_tStart
CRefTime m_tStart
Definition: amfilter.h:158
CritCheckIn
#define CritCheckIn(x)
Definition: wxutil.h:75
HANDLE
short HANDLE
Definition: ajatypes.h:318
_AMOVIESETUP_FILTER::strName
const WCHAR * strName
Definition: combase.h:119
CEnumPins
Definition: amfilter.h:582
CBasePin
Definition: amfilter.h:330
CDynamicOutputPin::StartUsingOutputPin
virtual HRESULT StartUsingOutputPin(void)
Definition: amfilter.cpp:4167
CBaseOutputPin::EndOfStream
STDMETHODIMP EndOfStream(void)
Definition: amfilter.cpp:2741
CBaseAllocator::m_lAllocated
long m_lAllocated
Definition: amfilter.h:1431
CBaseFilter::IncrementPinVersion
void IncrementPinVersion()
Definition: amfilter.cpp:869
CDynamicOutputPin::ChangeOutputFormat
HRESULT ChangeOutputFormat(const AM_MEDIA_TYPE *pmt, REFERENCE_TIME tSegmentStart, REFERENCE_TIME tSegmentStop, double dSegmentRate)
Definition: amfilter.cpp:4320
CMediaSample::m_cRef
LONG m_cRef
Definition: amfilter.h:1228
CBaseOutputPin::DecideBufferSize
virtual HRESULT DecideBufferSize(IMemAllocator *pAlloc, __inout ALLOCATOR_PROPERTIES *ppropInputRequest) PURE
CMediaType::IsPartiallySpecified
BOOL IsPartiallySpecified(void) const
Definition: mtype.cpp:306
CEnumMediaTypes::CEnumMediaTypes
CEnumMediaTypes(__in CBasePin *pPin, __in_opt CEnumMediaTypes *pEnumMediaTypes)
Definition: amfilter.cpp:1229
CMediaType::Type
const GUID * Type() const
Definition: mtype.h:39
streams.h
KASSERT
#define KASSERT(_x_)
Definition: wxdebug.h:203
CDynamicOutputPin::Disconnect
STDMETHODIMP Disconnect(void)
Definition: amfilter.cpp:3976
NULL
#define NULL
Definition: ntv2caption608types.h:19
CMediaType::Set
HRESULT Set(const CMediaType &rt)
Definition: mtype.cpp:108
CBasePin::m_pQSink
IQualityControl * m_pQSink
Definition: amfilter.h:344
CBasePin::SetSink
STDMETHODIMP SetSink(IQualityControl *piqc)
Definition: amfilter.cpp:2413
CBaseOutputPin::CBaseOutputPin
CBaseOutputPin(__in_opt LPCTSTR pObjectName, __in CBaseFilter *pFilter, __in CCritSec *pLock, __inout HRESULT *phr, __in_opt LPCWSTR pName)
Definition: amfilter.cpp:2457
CBaseInputPin::Notify
STDMETHODIMP Notify(IBaseFilter *pSender, Quality q)
Definition: amfilter.cpp:3153
CUnknown::NonDelegatingQueryInterface
STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **)
Definition: combase.cpp:135
CDynamicOutputPin::BlockOutputPin
void BlockOutputPin(void)
Definition: amfilter.cpp:4114
CMediaSample::Sample_StopValid
@ Sample_StopValid
Definition: amfilter.h:1202
NUMELMS
#define NUMELMS(aa)
Definition: types.h:430
LOG_TRACE
@ LOG_TRACE
Definition: wxdebug.h:45
CCritSec::Unlock
void Unlock()
Definition: wxutil.h:52
CBaseAllocator::GetBuffer
STDMETHODIMP GetBuffer(__deref_out IMediaSample **ppBuffer, __in_opt REFERENCE_TIME *pStartTime, __in_opt REFERENCE_TIME *pEndTime, DWORD dwFlags)
Definition: amfilter.cpp:4731
DbgBreak
#define DbgBreak(_x_)
Definition: wxdebug.h:201
NAME
#define NAME(_x_)
Definition: wxdebug.h:179
CBaseOutputPin::DeliverNewSegment
virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
Definition: amfilter.cpp:2784
CBasePin::CheckMediaType
virtual HRESULT CheckMediaType(const CMediaType *) PURE
CBasePin::SetMediaType
virtual HRESULT SetMediaType(const CMediaType *)
Definition: amfilter.cpp:1991
CEnumMediaTypes::Reset
STDMETHODIMP Reset()
Definition: amfilter.cpp:1450
CBasePin::QueryId
STDMETHODIMP QueryId(__deref_out LPWSTR *Id)
Definition: amfilter.cpp:2271
CBaseInputPin::GetAllocatorRequirements
STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps)
Definition: amfilter.cpp:3182
CEnumMediaTypes::Skip
STDMETHODIMP Skip(ULONG cMediaTypes)
Definition: amfilter.cpp:1420
CMediaSample::SetMediaTime
STDMETHODIMP SetMediaTime(__in_opt LONGLONG *pTimeStart, __in_opt LONGLONG *pTimeEnd)
Definition: amfilter.cpp:3525
MAX_TIME
const LONGLONG MAX_TIME
Definition: refclock.h:17
CBaseOutputPin::Deliver
virtual HRESULT Deliver(IMediaSample *)
Definition: amfilter.cpp:2685
CBaseFilter::Pause
STDMETHODIMP Pause()
Definition: amfilter.cpp:555
CBaseOutputPin::Inactive
HRESULT Inactive(void)
Definition: amfilter.cpp:2729
CreateMediaType
AM_MEDIA_TYPE *WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc)
Definition: mtype.cpp:371
PERFLOG_RECEIVE
#define PERFLOG_RECEIVE(name, source, dest, sample, pmt)
Definition: dxmperf.h:61
CBaseFilter::GetPinCount
virtual int GetPinCount() PURE
CBaseAllocator::Decommit
STDMETHODIMP Decommit()
Definition: amfilter.cpp:4921
PERFLOG_RUN
#define PERFLOG_RUN(name, iface, time, oldstate)
Definition: dxmperf.h:62
CAutoLock
Definition: wxutil.h:83
CBaseList::RemoveAll
void RemoveAll()
Definition: wxlist.cpp:150
CEnumMediaTypes::Clone
STDMETHODIMP Clone(__deref_out IEnumMediaTypes **ppEnum)
Definition: amfilter.cpp:1311
CBasePin::m_bTryMyTypesFirst
bool m_bTryMyTypesFirst
Definition: amfilter.h:341
CEnumMediaTypes
Definition: amfilter.h:652
CBaseOutputPin::m_pInputPin
IMemInputPin * m_pInputPin
Definition: amfilter.h:718
CBaseOutputPin::GetDeliveryBuffer
virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample **ppSample, __in_opt REFERENCE_TIME *pStartTime, __in_opt REFERENCE_TIME *pEndTime, DWORD dwFlags)
Definition: amfilter.cpp:2648
CMediaSample::~CMediaSample
virtual ~CMediaSample()
Definition: amfilter.cpp:3318
CBaseFilter::m_pSink
IMediaEventSink * m_pSink
Definition: amfilter.h:165
CMediaSample::m_dwStreamId
DWORD m_dwStreamId
Definition: amfilter.h:1226
CBasePin::IsConnected
BOOL IsConnected(void)
Definition: amfilter.h:499
CDynamicOutputPin::m_BlockStateLock
CCritSec m_BlockStateLock
Definition: amfilter.h:1031
CBasePin::m_bCanReconnectWhenActive
bool m_bCanReconnectWhenActive
Definition: amfilter.h:340
CBaseAllocator::m_lAlignment
long m_lAlignment
Definition: amfilter.h:1433
STDMETHODIMP_
STDMETHODIMP_(ULONG) CUnknown
Definition: combase.cpp:163
AmGetLastErrorToHResult
HRESULT AmGetLastErrorToHResult()
Definition: wxutil.cpp:688
CDynamicOutputPin::DynamicReconnect
HRESULT DynamicReconnect(const CMediaType *pmt)
Definition: amfilter.cpp:4448
CBaseMediaFilter::StreamTime
virtual HRESULT StreamTime(CRefTime &rtStream)
Definition: amfilter.cpp:267
CBasePin::SetReconnectWhenActive
void SetReconnectWhenActive(bool bCanReconnect)
Definition: amfilter.h:554
CEnumPins::Clone
STDMETHODIMP Clone(__deref_out IEnumPins **ppEnum)
Definition: amfilter.cpp:1062
CBaseInputPin::NotifyAllocator
STDMETHODIMP NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly)
Definition: amfilter.cpp:2896
CBaseMediaFilter::m_clsid
CLSID m_clsid
Definition: amfilter.h:69
CBaseFilter::GetClassID
STDMETHODIMP GetClassID(__out CLSID *pClsID)
Definition: amfilter.cpp:446
CBasePin::m_dir
PIN_DIRECTION m_dir
Definition: amfilter.h:337
CMediaType
Definition: mtype.h:18
CMediaSample::m_Start
REFERENCE_TIME m_Start
Definition: amfilter.h:1221
PERFLOG_CONNECT
#define PERFLOG_CONNECT(connector, connectee, status, pmt)
Definition: dxmperf.h:68
CBaseFilter::m_PinVersion
LONG m_PinVersion
Definition: amfilter.h:166
CMediaSample::m_MediaStart
LONGLONG m_MediaStart
Definition: amfilter.h:1223
CBaseOutputPin::DecideAllocator
virtual HRESULT DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **pAlloc)
Definition: amfilter.cpp:2575
CBaseOutputPin::CheckConnect
HRESULT CheckConnect(IPin *pPin)
Definition: amfilter.cpp:2506
CBasePin::Run
virtual HRESULT Run(REFERENCE_TIME tStart)
Definition: amfilter.cpp:2385
CopyMediaType
HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
Definition: mtype.cpp:397
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail::void
j template void())
Definition: json.hpp:4893
CBaseFilter::~CBaseFilter
~CBaseFilter()
Definition: amfilter.cpp:423
CBaseAllocator::GetProperties
STDMETHODIMP GetProperties(__out ALLOCATOR_PROPERTIES *pProps)
Definition: amfilter.cpp:4712
CDynamicOutputPin::WaitEvent
static HRESULT WaitEvent(HANDLE hEvent)
Definition: amfilter.cpp:4520
PERFLOG_GETBUFFER
#define PERFLOG_GETBUFFER(allocator, sample)
Definition: dxmperf.h:66
CBasePin::Inactive
virtual HRESULT Inactive(void)
Definition: amfilter.cpp:2397
CBasePin::GetMediaTypeVersion
virtual LONG GetMediaTypeVersion()
Definition: amfilter.cpp:2356
ValidateReadWritePtr
#define ValidateReadWritePtr(p, cb)
Definition: wxdebug.h:241
QzCComPtr
Definition: wxutil.h:483
CMemAllocator::Alloc
HRESULT Alloc(void)
Definition: amfilter.cpp:5122
CBaseAllocator::NonDelegatingQueryInterface
DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:4644
CBasePin::Disconnect
STDMETHODIMP Disconnect()
Definition: amfilter.cpp:2137
CBaseAllocator::SetProperties
STDMETHODIMP SetProperties(__in ALLOCATOR_PROPERTIES *pRequest, __out ALLOCATOR_PROPERTIES *pActual)
Definition: amfilter.cpp:4663
CBaseAllocator::m_lWaiting
long m_lWaiting
Definition: amfilter.h:1429
QueryPinInfoReleaseFilter
#define QueryPinInfoReleaseFilter(pi)
Definition: amfilter.h:39
CBaseInputPin::Inactive
virtual HRESULT Inactive(void)
Definition: amfilter.cpp:3166
CBaseFilter::StreamTime
virtual HRESULT StreamTime(CRefTime &rtStream)
Definition: amfilter.cpp:648
_AMOVIESETUP_FILTER::dwMerit
DWORD dwMerit
Definition: combase.h:120
CDynamicOutputPin::StopUsingOutputPin
virtual void StopUsingOutputPin(void)
Definition: amfilter.cpp:4230
CBaseFilter::NonDelegatingQueryInterface
DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:299
CBasePin::DisplayPinInfo
void DisplayPinInfo(IPin *pReceivePin)
Definition: amfilter.h:362
CBasePin::QueryPinInfo
STDMETHODIMP QueryPinInfo(__out PIN_INFO *pInfo)
Definition: amfilter.cpp:2234
CBaseMediaFilter::m_pClock
IReferenceClock * m_pClock
Definition: amfilter.h:63
CBaseAllocator::m_lSize
long m_lSize
Definition: amfilter.h:1432
ValidateWritePtr
#define ValidateWritePtr(p, cb)
Definition: wxdebug.h:240
DbgCheckModuleLevel
#define DbgCheckModuleLevel(Type, Level)
Definition: wxdebug.h:191
CBasePin::TryMediaTypes
HRESULT TryMediaTypes(IPin *pReceivePin, __in_opt const CMediaType *pmt, IEnumMediaTypes *pEnum)
Definition: amfilter.cpp:1847
CMediaSample::m_dwTypeSpecificFlags
DWORD m_dwTypeSpecificFlags
Definition: amfilter.h:1215
CBaseFilter::ReconnectPin
HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt)
Definition: amfilter.cpp:834
CEnumMediaTypes::Next
STDMETHODIMP Next(ULONG cMediaTypes, __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes, __out_opt ULONG *pcFetched)
Definition: amfilter.cpp:1345
CBaseAllocator::m_pNotify
IMemAllocatorNotifyCallbackTemp * m_pNotify
Definition: amfilter.h:1444
CDynamicOutputPin::DeliverEndFlush
HRESULT DeliverEndFlush(void)
Definition: amfilter.cpp:4305
LOG_ERROR
@ LOG_ERROR
Definition: wxdebug.h:48
CUnknown::m_cRef
volatile LONG m_cRef
Definition: combase.h:207
_AMOVIESETUP_FILTER::clsID
const CLSID * clsID
Definition: combase.h:118
CBaseAllocator::NotifySample
void NotifySample()
Definition: amfilter.cpp:4872
CEnumMediaTypes::QueryInterface
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:1276
CMemAllocator::CreateInstance
static CUnknown * CreateInstance(__inout_opt LPUNKNOWN, __inout HRESULT *)
Definition: amfilter.cpp:5019
pName
CHAR * pName
Definition: amvideo.cpp:26
CMediaSample::CMediaSample
CMediaSample(__in_opt LPCTSTR pName, __in_opt CBaseAllocator *pAllocator, __inout_opt HRESULT *phr, __in_bcount_opt(length) LPBYTE pBuffer=NULL, LONG length=0)
Definition: amfilter.cpp:3259
_AMOVIESETUP_FILTER::nPins
UINT nPins
Definition: combase.h:121
CBaseInputPin::CheckStreaming
virtual HRESULT CheckStreaming()
Definition: amfilter.cpp:3191
CMediaSample::SetPointer
HRESULT SetPointer(__in_bcount(cBytes) BYTE *ptr, LONG cBytes)
Definition: amfilter.cpp:3408
DbgLog
#define DbgLog(_x_)
Definition: wxdebug.h:183
CBaseAllocator::m_fEnableReleaseCallback
BOOL m_fEnableReleaseCallback
Definition: amfilter.h:1446
CBaseFilter::m_pClock
IReferenceClock * m_pClock
Definition: amfilter.h:157
CDynamicOutputPin::m_hUnblockOutputPinEvent
HANDLE m_hUnblockOutputPinEvent
Definition: amfilter.h:1037
CEnumPins::~CEnumPins
virtual ~CEnumPins()
Definition: amfilter.cpp:1014
CBaseMediaFilter::m_tStart
CRefTime m_tStart
Definition: amfilter.h:67
_AMOVIESETUP_FILTER
Definition: combase.h:116
dxmperf.h
CBaseMediaFilter::GetClassID
STDMETHODIMP GetClassID(__out CLSID *pClsID)
Definition: amfilter.cpp:147
PERFLOG_DELIVER
#define PERFLOG_DELIVER(name, source, dest, sample, pmt)
Definition: dxmperf.h:60
CBaseInputPin::m_SampleProps
AM_SAMPLE2_PROPERTIES m_SampleProps
Definition: amfilter.h:837
CreateMemoryAllocator
STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator)
Definition: amfilter.cpp:41
CMediaSample::m_pAllocator
CBaseAllocator * m_pAllocator
Definition: amfilter.h:1219
CBaseFilter::JoinFilterGraph
STDMETHODIMP JoinFilterGraph(__inout_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName)
Definition: amfilter.cpp:744
CBaseOutputPin::EndFlush
STDMETHODIMP EndFlush(void)
Definition: amfilter.cpp:2756
CBaseMediaFilter::Run
STDMETHODIMP Run(REFERENCE_TIME tStart)
Definition: amfilter.cpp:244
CMediaSample::m_cbBuffer
LONG m_cbBuffer
Definition: amfilter.h:1218
CCritSec
Definition: wxutil.h:18
riid
__in REFIID riid
Definition: dllentry.cpp:192
CBasePin::m_dRate
double m_dRate
Definition: amfilter.h:350
PERFLOG_JOINGRAPH
#define PERFLOG_JOINGRAPH(name, iface, graph)
Definition: dxmperf.h:65
CMemAllocator::CMemAllocator
CMemAllocator(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, __inout HRESULT *)
Definition: amfilter.cpp:5025
CDynamicOutputPin::Inactive
HRESULT Inactive(void)
Definition: amfilter.cpp:4283
CMediaSample::IsPreroll
STDMETHODIMP IsPreroll(void)
Definition: amfilter.cpp:3599
CBaseFilter::QueryFilterInfo
STDMETHODIMP QueryFilterInfo(__out FILTER_INFO *pInfo)
Definition: amfilter.cpp:724
CDynamicOutputPin::m_BlockState
BLOCK_STATE m_BlockState
Definition: amfilter.h:1046
CMemAllocator::Free
void Free(void)
Definition: amfilter.cpp:5232
CBaseAllocator::SetNotify
STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify)
Definition: amfilter.cpp:4844
DeleteMediaType
void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt)
Definition: mtype.cpp:353
CDynamicOutputPin::DeliverBeginFlush
HRESULT DeliverBeginFlush(void)
Definition: amfilter.cpp:4294
CBaseAllocator::GetFreeCount
STDMETHODIMP GetFreeCount(__out LONG *plBuffersFree)
Definition: amfilter.cpp:4861
CMediaSample::GetMediaType
STDMETHODIMP GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType)
Definition: amfilter.cpp:3642
CMediaSample::m_End
REFERENCE_TIME m_End
Definition: amfilter.h:1222
CBasePin::AttemptConnection
HRESULT AttemptConnection(IPin *pReceivePin, const CMediaType *pmt)
Definition: amfilter.cpp:1755
CBaseAllocator::m_hSem
HANDLE m_hSem
Definition: amfilter.h:1428
CBaseFilter::QueryVendorInfo
STDMETHODIMP QueryVendorInfo(__deref_out LPWSTR *pVendorInfo)
Definition: amfilter.cpp:799
CBasePin::GetMediaType
virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType)
Definition: amfilter.cpp:2340
CMediaSample::GetTime
STDMETHODIMP GetTime(__out REFERENCE_TIME *pTimeStart, __out REFERENCE_TIME *pTimeEnd)
Definition: amfilter.cpp:3447
LOG_MEMORY
@ LOG_MEMORY
Definition: wxdebug.h:46
CBasePin::BreakConnect
virtual HRESULT BreakConnect()
Definition: amfilter.cpp:2029
CBaseOutputPin::CompleteConnect
virtual HRESULT CompleteConnect(IPin *pReceivePin)
Definition: amfilter.cpp:2488
PERFLOG_RXCONNECT
#define PERFLOG_RXCONNECT(connector, connectee, status, pmt)
Definition: dxmperf.h:69
CBaseFilter::m_State
FILTER_STATE m_State
Definition: amfilter.h:156
CMediaSample::GetProperties
STDMETHODIMP GetProperties(DWORD cbProperties, __out_bcount(cbProperties) BYTE *pbProperties)
Definition: amfilter.cpp:3702
CBaseInputPin::~CBaseInputPin
virtual ~CBaseInputPin()
Definition: amfilter.cpp:2835
CBaseOutputPin
Definition: amfilter.h:712
CMediaSample
Definition: amfilter.h:1185
PERFLOG_STOP
#define PERFLOG_STOP(name, iface, oldstate)
Definition: dxmperf.h:64
CBaseOutputPin::DeliverEndOfStream
virtual HRESULT DeliverEndOfStream(void)
Definition: amfilter.cpp:2702
CBaseInputPin::ReceiveMultiple
STDMETHODIMP ReceiveMultiple(__in_ecount(nSamples) IMediaSample **pSamples, long nSamples, __out long *nSamplesProcessed)
Definition: amfilter.cpp:3030
CONNECT_TRACE_LEVEL
#define CONNECT_TRACE_LEVEL
Definition: amfilter.cpp:89
CBaseFilter::Unregister
STDMETHODIMP Unregister()
Definition: amfilter.cpp:917
CDynamicOutputPin::m_dwNumOutstandingOutputPinUsers
DWORD m_dwNumOutstandingOutputPinUsers
Definition: amfilter.h:1061
CopyMemory
#define CopyMemory(a, b, c)
Definition: ntv2baremetaldriverinterface.h:16
CBaseAllocator::m_bCommitted
BOOL m_bCommitted
Definition: amfilter.h:1438
CBasePin::m_Connected
IPin * m_Connected
Definition: amfilter.h:336
CBaseOutputPin::m_pAllocator
IMemAllocator * m_pAllocator
Definition: amfilter.h:717
CBaseAllocator::Alloc
virtual HRESULT Alloc(void)
Definition: amfilter.cpp:4973
CBaseAllocator::~CBaseAllocator
virtual ~CBaseAllocator()
Definition: amfilter.cpp:4621
CMediaSample::Sample_SyncPoint
@ Sample_SyncPoint
Definition: amfilter.h:1195
CDynamicOutputPin::CDynamicOutputPin
CDynamicOutputPin(__in_opt LPCTSTR pObjectName, __in CBaseFilter *pFilter, __in CCritSec *pLock, __inout HRESULT *phr, __in_opt LPCWSTR pName)
Definition: amfilter.cpp:3886
CBaseMediaFilter::GetSyncSource
STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock)
Definition: amfilter.cpp:195
CBasePin::QueryDirection
STDMETHODIMP QueryDirection(__out PIN_DIRECTION *pPinDir)
Definition: amfilter.cpp:2258
CEnumMediaTypes::~CEnumMediaTypes
virtual ~CEnumMediaTypes()
Definition: amfilter.cpp:1264
CBaseInputPin::ReceiveCanBlock
STDMETHODIMP ReceiveCanBlock()
Definition: amfilter.cpp:3054
CBaseFilter::FindPin
STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin)
Definition: amfilter.cpp:691
EXECUTE_ASSERT
#define EXECUTE_ASSERT(_x_)
Definition: wxdebug.h:207
CUnknown
Definition: combase.h:200
PERFLOG_DTOR
#define PERFLOG_DTOR(name, iface)
Definition: dxmperf.h:59
CBasePin::QueryAccept
STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE *pmt)
Definition: amfilter.cpp:2287
IsEqualObject
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
Definition: combase.cpp:224
CBasePin::CheckConnect
virtual HRESULT CheckConnect(IPin *)
Definition: amfilter.cpp:2007
CBasePin::m_tStart
CRefTime m_tStart
Definition: amfilter.h:348
CBasePin::EndOfStream
STDMETHODIMP EndOfStream(void)
Definition: amfilter.cpp:2406
CBasePin::ConnectionMediaType
STDMETHODIMP ConnectionMediaType(__out AM_MEDIA_TYPE *pmt)
Definition: amfilter.cpp:2213
CDynamicOutputPin::SynchronousBlockOutputPin
HRESULT SynchronousBlockOutputPin(void)
Definition: amfilter.cpp:4037
CBasePin::DisplayTypeInfo
void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt)
Definition: amfilter.h:363
CMediaSample::SetDiscontinuity
STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity)
Definition: amfilter.cpp:3587
CDynamicOutputPin::NOT_BLOCKED
@ NOT_BLOCKED
Definition: amfilter.h:1023
CMediaSample::SetMediaType
STDMETHODIMP SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType)
Definition: amfilter.cpp:3670
CBaseInputPin::NonDelegatingQueryInterface
DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:2846
CBaseFilter::m_pName
WCHAR * m_pName
Definition: amfilter.h:163
CBaseInputPin::CBaseInputPin
CBaseInputPin(__in_opt LPCTSTR pObjectName, __in CBaseFilter *pFilter, __in CCritSec *pLock, __inout HRESULT *phr, __in_opt LPCWSTR pName)
Definition: amfilter.cpp:2805
CBasePin::CompleteConnect
virtual HRESULT CompleteConnect(IPin *pReceivePin)
Definition: amfilter.cpp:1979
CGenericList::AddTail
__out_opt POSITION AddTail(__in OBJECT *pObj)
Definition: wxlist.h:533
CMediaSample::Sample_TimeValid
@ Sample_TimeValid
Definition: amfilter.h:1199
CEnumPins::QueryInterface
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:1027
CMediaSample::Sample_Discontinuity
@ Sample_Discontinuity
Definition: amfilter.h:1197
PERFLOG_CTOR
#define PERFLOG_CTOR(name, iface)
Definition: dxmperf.h:58
CBaseFilter::GetPin
virtual CBasePin * GetPin(int n) PURE
CRefTime
Definition: reftime.h:49
CBaseAllocator::Free
virtual void Free(void) PURE
CBaseInputPin::m_bFlushing
BYTE m_bFlushing
Definition: amfilter.h:834
CDynamicOutputPin::~CDynamicOutputPin
~CDynamicOutputPin()
Definition: amfilter.cpp:3934
CDynamicOutputPin::Block
STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent)
Definition: amfilter.cpp:3982
false
#define false
Definition: ntv2devicefeatures.h:25
PERFLOG_PAUSE
#define PERFLOG_PAUSE(name, iface, oldstate)
Definition: dxmperf.h:63
CEnumPins::Skip
STDMETHODIMP Skip(ULONG cPins)
Definition: amfilter.cpp:1159
_AMOVIESETUP_FILTER::lpPin
const AMOVIESETUP_PIN * lpPin
Definition: combase.h:122
CBasePin::m_bRunTimeError
bool m_bRunTimeError
Definition: amfilter.h:339
CMemAllocator::m_pBuffer
LPBYTE m_pBuffer
Definition: amfilter.h:1542
CBaseMediaFilter::Pause
STDMETHODIMP Pause()
Definition: amfilter.cpp:225
CBasePin::IsStopped
BOOL IsStopped()
Definition: amfilter.h:504
CDynamicOutputPin::CompleteConnect
virtual HRESULT CompleteConnect(IPin *pReceivePin)
Definition: amfilter.cpp:4469
CBaseFilter
Definition: amfilter.h:148
CEnumPins::Reset
STDMETHODIMP Reset()
Definition: amfilter.cpp:1189
CBaseInputPin::EndFlush
STDMETHODIMP EndFlush(void)
Definition: amfilter.cpp:3129
CreatePosPassThru
STDAPI CreatePosPassThru(__in_opt LPUNKNOWN pAgg, BOOL bRenderer, IPin *pPin, __deref_out IUnknown **ppPassThru)
Definition: amfilter.cpp:52
CMediaSample::Sample_Preroll
@ Sample_Preroll
Definition: amfilter.h:1196
CEnumPins::CEnumPins
CEnumPins(__in CBaseFilter *pFilter, __in_opt CEnumPins *pEnumPins)
Definition: amfilter.cpp:974
CBasePin::Notify
STDMETHODIMP Notify(IBaseFilter *pSender, Quality q)
Definition: amfilter.cpp:2423
ULONG
ULONG(__stdcall *_RegisterTraceGuids)(__in IN WMIDPREQUEST RequestAddress
CBaseFilter::Run
STDMETHODIMP Run(REFERENCE_TIME tStart)
Definition: amfilter.cpp:600
CBaseFilter::m_pLock
CCritSec * m_pLock
Definition: amfilter.h:161
CBasePin::m_pFilter
CBaseFilter * m_pFilter
Definition: amfilter.h:343
CBaseFilter::GetSyncSource
STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock)
Definition: amfilter.cpp:493
CMemAllocator::SetProperties
STDMETHODIMP SetProperties(__in ALLOCATOR_PROPERTIES *pRequest, __out ALLOCATOR_PROPERTIES *pActual)
Definition: amfilter.cpp:5050
AMGetWideString
STDAPI AMGetWideString(LPCWSTR psz, __deref_out LPWSTR *ppszReturn)
Definition: wxutil.cpp:571
CDynamicOutputPin::StreamingThreadUsingOutputPin
virtual bool StreamingThreadUsingOutputPin(void)
Definition: amfilter.cpp:4249
CBaseInputPin::GetAllocator
STDMETHODIMP GetAllocator(__deref_out IMemAllocator **ppAllocator)
Definition: amfilter.cpp:2870
CBasePin::EnumMediaTypes
STDMETHODIMP EnumMediaTypes(__deref_out IEnumMediaTypes **ppEnum)
Definition: amfilter.cpp:2315
CBaseOutputPin::DeliverBeginFlush
virtual HRESULT DeliverBeginFlush(void)
Definition: amfilter.cpp:2763
CBaseMediaFilter::Stop
STDMETHODIMP Stop()
Definition: amfilter.cpp:213
CDynamicOutputPin::ChangeMediaType
HRESULT ChangeMediaType(const CMediaType *pmt)
Definition: amfilter.cpp:4348
CBaseOutputPin::DeliverEndFlush
virtual HRESULT DeliverEndFlush(void)
Definition: amfilter.cpp:2774
CBaseFilter::CBaseFilter
CBaseFilter(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __in CCritSec *pLock, REFCLSID clsid)
Definition: amfilter.cpp:330
CBasePin::Name
LPWSTR Name()
Definition: amfilter.h:551
CBaseAllocator::CBaseAllocator
CBaseAllocator(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, __inout HRESULT *, BOOL bEvent=TRUE, BOOL fEnableReleaseCallback=FALSE)
Definition: amfilter.cpp:4552
CGenericList::Find
__out_opt POSITION Find(__in OBJECT *pObj) const
Definition: wxlist.h:542
CBasePin::m_tStop
CRefTime m_tStop
Definition: amfilter.h:349
CMediaType::Subtype
const GUID * Subtype() const
Definition: mtype.h:41
CMediaSample::m_MediaEnd
LONG m_MediaEnd
Definition: amfilter.h:1224
CDynamicOutputPin::UnblockOutputPin
HRESULT UnblockOutputPin(void)
Definition: amfilter.cpp:4137
CMediaSample::GetMediaTime
STDMETHODIMP GetMediaTime(__out LONGLONG *pTimeStart, __out LONGLONG *pTimeEnd)
Definition: amfilter.cpp:3505
CBaseFilter::EnumPins
STDMETHODIMP EnumPins(__deref_out IEnumPins **ppEnum)
Definition: amfilter.cpp:674
CCritSec::Lock
void Lock()
Definition: wxutil.h:48
CBaseMediaFilter::SetSyncSource
STDMETHODIMP SetSyncSource(__inout_opt IReferenceClock *pClock)
Definition: amfilter.cpp:172
CBaseFilter::Register
STDMETHODIMP Register()
Definition: amfilter.cpp:876
CBaseInputPin::BeginFlush
STDMETHODIMP BeginFlush(void)
Definition: amfilter.cpp:3105
CBaseAllocator
Definition: amfilter.h:1339
CritCheckOut
#define CritCheckOut(x)
Definition: wxutil.h:76
CBasePin::m_mt
CMediaType m_mt
Definition: amfilter.h:346
CMediaSample::Sample_MediaTimeValid
@ Sample_MediaTimeValid
Definition: amfilter.h:1200
CDynamicOutputPin::m_bPinUsesReadOnlyAllocator
BOOL m_bPinUsesReadOnlyAllocator
Definition: amfilter.h:1072
CBasePin::~CBasePin
virtual ~CBasePin()
Definition: amfilter.cpp:1589
CBaseAllocator::SetWaiting
void SetWaiting()
Definition: amfilter.h:1514
CBasePin::NewSegment
STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
Definition: amfilter.cpp:2437
CMediaSample::IsDiscontinuity
STDMETHODIMP IsDiscontinuity(void)
Definition: amfilter.cpp:3575
CBaseAllocator::Commit
STDMETHODIMP Commit()
Definition: amfilter.cpp:4882
CDynamicOutputPin::BLOCKED
@ BLOCKED
Definition: amfilter.h:1025
CMediaSample::SetTime
STDMETHODIMP SetTime(__in_opt REFERENCE_TIME *pTimeStart, __in_opt REFERENCE_TIME *pTimeEnd)
Definition: amfilter.cpp:3476
CBaseAllocator::ReleaseBuffer
STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer)
Definition: amfilter.cpp:4791
CBasePin::ReceiveConnection
STDMETHODIMP ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
Definition: amfilter.cpp:2040
CBaseFilter::SetSyncSource
STDMETHODIMP SetSyncSource(__in_opt IReferenceClock *pClock)
Definition: amfilter.cpp:470
CBaseAllocator::m_bDecommitInProgress
BOOL m_bDecommitInProgress
Definition: amfilter.h:1441
CBasePin::m_TypeVersion
LONG m_TypeVersion
Definition: amfilter.h:345
CBaseFilter::GetSetupData
virtual __out_opt LPAMOVIESETUP_FILTER GetSetupData()
Definition: amfilter.h:317
CMemAllocator::ReallyFree
void ReallyFree(void)
Definition: amfilter.cpp:5241
CBasePin::DisconnectInternal
STDMETHODIMP DisconnectInternal()
Definition: amfilter.cpp:2150
PERFLOG_RELBUFFER
#define PERFLOG_RELBUFFER(allocator, sample)
Definition: dxmperf.h:67
CDynamicOutputPin::SetConfigInfo
void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent)
Definition: amfilter.cpp:4256
CBaseFilter::Stop
STDMETHODIMP Stop()
Definition: amfilter.cpp:512
CheckPointer
#define CheckPointer(p, ret)
Definition: wxdebug.h:225
CMediaSample::SetActualDataLength
STDMETHODIMP SetActualDataLength(LONG lActual)
Definition: amfilter.cpp:3628
CBaseFilter::m_clsid
CLSID m_clsid
Definition: amfilter.h:159
CMediaSample::SetPreroll
STDMETHODIMP SetPreroll(BOOL bIsPreroll)
Definition: amfilter.cpp:3610
CBasePin::m_pName
WCHAR * m_pName
Definition: amfilter.h:335
CDynamicOutputPin::m_hStopEvent
HANDLE m_hStopEvent
Definition: amfilter.h:1066
CBaseFilter::GetState
STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State)
Definition: amfilter.cpp:456
CDynamicOutputPin::m_pGraphConfig
IGraphConfig * m_pGraphConfig
Definition: amfilter.h:1067
CDynamicOutputPin::Active
HRESULT Active(void)
Definition: amfilter.cpp:4266
CMediaSample::SetSyncPoint
STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint)
Definition: amfilter.cpp:3561
CMediaSample::QueryInterface
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:3332
CBaseInputPin::BreakConnect
HRESULT BreakConnect()
Definition: amfilter.cpp:2921
ASSERT
#define ASSERT(_x_)
Definition: wxdebug.h:205
CBaseAllocator::m_lFree
CSampleList m_lFree
Definition: amfilter.h:1390
CMediaSample::IsSyncPoint
STDMETHODIMP IsSyncPoint(void)
Definition: amfilter.cpp:3550
CMediaSample::Sample_ValidFlags
@ Sample_ValidFlags
Definition: amfilter.h:1203
CBaseInputPin::Receive
STDMETHODIMP Receive(IMediaSample *pSample)
Definition: amfilter.cpp:2952
CBasePin::Connect
STDMETHODIMP Connect(IPin *pReceivePin, __in_opt const AM_MEDIA_TYPE *pmt)
Definition: amfilter.cpp:1698
CBaseMediaFilter::CBaseMediaFilter
CBaseMediaFilter(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __in CCritSec *pLock, REFCLSID clsid)
Definition: amfilter.cpp:100
CBaseMediaFilter::GetState
STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State)
Definition: amfilter.cpp:158
CBasePin::IncrementTypeVersion
void IncrementTypeVersion()
Definition: amfilter.cpp:2364
GetInterface
STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv)
Definition: combase.cpp:213
CMediaSample::Sample_TypeChanged
@ Sample_TypeChanged
Definition: amfilter.h:1198
hr
__out HRESULT & hr
Definition: pstream.cpp:145
PERFLOG_DISCONNECT
#define PERFLOG_DISCONNECT(disconnector, disconnectee, status)
Definition: dxmperf.h:70
CBaseMediaFilter::~CBaseMediaFilter
virtual ~CBaseMediaFilter()
Definition: amfilter.cpp:115
CBaseInputPin::m_pAllocator
IMemAllocator * m_pAllocator
Definition: amfilter.h:825
CBasePin::ConnectedTo
STDMETHODIMP ConnectedTo(__deref_out IPin **pPin)
Definition: amfilter.cpp:2189
CBaseFilter::GetPinVersion
virtual LONG GetPinVersion()
Definition: amfilter.cpp:861
CDynamicOutputPin::NonDelegatingQueryInterface
DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
Definition: amfilter.cpp:3967
CMediaSample::m_pMediaType
AM_MEDIA_TYPE * m_pMediaType
Definition: amfilter.h:1225
CDynamicOutputPin::AsynchronousBlockOutputPin
HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent)
Definition: amfilter.cpp:4071
CBaseOutputPin::BreakConnect
HRESULT BreakConnect()
Definition: amfilter.cpp:2525
CMediaSample::m_dwFlags
DWORD m_dwFlags
Definition: amfilter.h:1211
CBaseFilter::m_pGraph
IFilterGraph * m_pGraph
Definition: amfilter.h:164
CBaseMediaFilter::m_pLock
CCritSec * m_pLock
Definition: amfilter.h:71
CBaseAllocator::m_lPrefix
long m_lPrefix
Definition: amfilter.h:1434
CBaseOutputPin::Active
HRESULT Active(void)
Definition: amfilter.cpp:2716
CBasePin::AgreeMediaType
HRESULT AgreeMediaType(IPin *pReceivePin, const CMediaType *pmt)
Definition: amfilter.cpp:1925