amfilter.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:149k
源码类别:

P2P编程

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // File: AMFilter.cpp
  3. //
  4. // Desc: DirectShow base classes - implements class hierarchy for streams
  5. //       architecture.
  6. //
  7. // Copyright (c) Microsoft Corporation.  All rights reserved.
  8. //------------------------------------------------------------------------------
  9. //=====================================================================
  10. //=====================================================================
  11. // The following classes are declared in this header:
  12. //
  13. //
  14. // CBaseMediaFilter            Basic IMediaFilter support (abstract class)
  15. // CBaseFilter                 Support for IBaseFilter (incl. IMediaFilter)
  16. // CEnumPins                   Enumerate input and output pins
  17. // CEnumMediaTypes             Enumerate the preferred pin formats
  18. // CBasePin                    Abstract base class for IPin interface
  19. //    CBaseOutputPin           Adds data provider member functions
  20. //    CBaseInputPin            Implements IMemInputPin interface
  21. // CMediaSample                Basic transport unit for IMemInputPin
  22. // CBaseAllocator              General list guff for most allocators
  23. //    CMemAllocator            Implements memory buffer allocation
  24. //
  25. //=====================================================================
  26. //=====================================================================
  27. #include <streams.h>
  28. //=====================================================================
  29. // Helpers
  30. //=====================================================================
  31. STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator)
  32. {
  33.     return CoCreateInstance(CLSID_MemoryAllocator,
  34.                             0,
  35.                             CLSCTX_INPROC_SERVER,
  36.                             IID_IMemAllocator,
  37.                             (void **)ppAllocator);
  38. }
  39. //  Put this one here rather than in ctlutil.cpp to avoid linking
  40. //  anything brought in by ctlutil.cpp
  41. STDAPI CreatePosPassThru(
  42.     LPUNKNOWN pAgg,
  43.     BOOL bRenderer,
  44.     IPin *pPin,
  45.     IUnknown **ppPassThru
  46. )
  47. {
  48.     *ppPassThru = NULL;
  49.     IUnknown *pUnkSeek;
  50.     HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru,
  51.                                   pAgg,
  52.                                   CLSCTX_INPROC_SERVER,
  53.                                   IID_IUnknown,
  54.                                   (void **)&pUnkSeek
  55.                                  );
  56.     if (FAILED(hr)) {
  57.         return hr;
  58.     }
  59.     ISeekingPassThru *pPassThru;
  60.     hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru);
  61.     if (FAILED(hr)) {
  62.         pUnkSeek->Release();
  63.         return hr;
  64.     }
  65.     hr = pPassThru->Init(bRenderer, pPin);
  66.     pPassThru->Release();
  67.     if (FAILED(hr)) {
  68.         pUnkSeek->Release();
  69.         return hr;
  70.     }
  71.     *ppPassThru = pUnkSeek;
  72.     return S_OK;
  73. }
  74. #define CONNECT_TRACE_LEVEL 3
  75. //=====================================================================
  76. //=====================================================================
  77. // Implements CBaseMediaFilter
  78. //=====================================================================
  79. //=====================================================================
  80. /* Constructor */
  81. CBaseMediaFilter::CBaseMediaFilter(const TCHAR  *pName,
  82.                    LPUNKNOWN    pUnk,
  83.                    CCritSec *pLock,
  84.                    REFCLSID clsid) :
  85.     CUnknown(pName, pUnk),
  86.     m_pLock(pLock),
  87.     m_clsid(clsid),
  88.     m_State(State_Stopped),
  89.     m_pClock(NULL)
  90. {
  91. }
  92. /* Destructor */
  93. CBaseMediaFilter::~CBaseMediaFilter()
  94. {
  95.     // must be stopped, but can't call Stop here since
  96.     // our critsec has been destroyed.
  97.     /* Release any clock we were using */
  98.     if (m_pClock) {
  99.         m_pClock->Release();
  100.         m_pClock = NULL;
  101.     }
  102. }
  103. /* Override this to say what interfaces we support and where */
  104. STDMETHODIMP
  105. CBaseMediaFilter::NonDelegatingQueryInterface(
  106.     REFIID riid,
  107.     void ** ppv)
  108. {
  109.     if (riid == IID_IMediaFilter) {
  110.         return GetInterface((IMediaFilter *) this, ppv);
  111.     } else if (riid == IID_IPersist) {
  112.         return GetInterface((IPersist *) this, ppv);
  113.     } else {
  114.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  115.     }
  116. }
  117. /* Return the filter's clsid */
  118. STDMETHODIMP
  119. CBaseMediaFilter::GetClassID(CLSID *pClsID)
  120. {
  121.     CheckPointer(pClsID,E_POINTER);
  122.     ValidateReadWritePtr(pClsID,sizeof(CLSID));
  123.     *pClsID = m_clsid;
  124.     return NOERROR;
  125. }
  126. /* Override this if your state changes are not done synchronously */
  127. STDMETHODIMP
  128. CBaseMediaFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
  129. {
  130.     UNREFERENCED_PARAMETER(dwMSecs);
  131.     CheckPointer(State,E_POINTER);
  132.     ValidateReadWritePtr(State,sizeof(FILTER_STATE));
  133.     *State = m_State;
  134.     return S_OK;
  135. }
  136. /* Set the clock we will use for synchronisation */
  137. STDMETHODIMP
  138. CBaseMediaFilter::SetSyncSource(IReferenceClock *pClock)
  139. {
  140.     CAutoLock cObjectLock(m_pLock);
  141.     // Ensure the new one does not go away - even if the same as the old
  142.     if (pClock) {
  143.         pClock->AddRef();
  144.     }
  145.     // if we have a clock, release it
  146.     if (m_pClock) {
  147.         m_pClock->Release();
  148.     }
  149.     // Set the new reference clock (might be NULL)
  150.     // Should we query it to ensure it is a clock?  Consider for a debug build.
  151.     m_pClock = pClock;
  152.     return NOERROR;
  153. }
  154. /* Return the clock we are using for synchronisation */
  155. STDMETHODIMP
  156. CBaseMediaFilter::GetSyncSource(IReferenceClock **pClock)
  157. {
  158.     CheckPointer(pClock,E_POINTER);
  159.     ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
  160.     CAutoLock cObjectLock(m_pLock);
  161.     if (m_pClock) {
  162.         // returning an interface... addref it...
  163.         m_pClock->AddRef();
  164.     }
  165.     *pClock = (IReferenceClock*)m_pClock;
  166.     return NOERROR;
  167. }
  168. /* Put the filter into a stopped state */
  169. STDMETHODIMP
  170. CBaseMediaFilter::Stop()
  171. {
  172.     CAutoLock cObjectLock(m_pLock);
  173.     m_State = State_Stopped;
  174.     return S_OK;
  175. }
  176. /* Put the filter into a paused state */
  177. STDMETHODIMP
  178. CBaseMediaFilter::Pause()
  179. {
  180.     CAutoLock cObjectLock(m_pLock);
  181.     m_State = State_Paused;
  182.     return S_OK;
  183. }
  184. // Put the filter into a running state.
  185. // The time parameter is the offset to be added to the samples'
  186. // stream time to get the reference time at which they should be presented.
  187. //
  188. // you can either add these two and compare it against the reference clock,
  189. // or you can call CBaseMediaFilter::StreamTime and compare that against
  190. // the sample timestamp.
  191. STDMETHODIMP
  192. CBaseMediaFilter::Run(REFERENCE_TIME tStart)
  193. {
  194.     CAutoLock cObjectLock(m_pLock);
  195.     // remember the stream time offset
  196.     m_tStart = tStart;
  197.     if (m_State == State_Stopped){
  198.         HRESULT hr = Pause();
  199.         if (FAILED(hr)) {
  200.             return hr;
  201.         }
  202.     }
  203.     m_State = State_Running;
  204.     return S_OK;
  205. }
  206. //
  207. // return the current stream time - samples with start timestamps of this
  208. // time or before should be rendered by now
  209. HRESULT
  210. CBaseMediaFilter::StreamTime(CRefTime& rtStream)
  211. {
  212.     // Caller must lock for synchronization
  213.     // We can't grab the filter lock because we want to be able to call
  214.     // this from worker threads without deadlocking
  215.     if (m_pClock == NULL) {
  216.         return VFW_E_NO_CLOCK;
  217.     }
  218.     // get the current reference time
  219.     HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
  220.     if (FAILED(hr)) {
  221.         return hr;
  222.     }
  223.     // subtract the stream offset to get stream time
  224.     rtStream -= m_tStart;
  225.     return S_OK;
  226. }
  227. //=====================================================================
  228. //=====================================================================
  229. // Implements CBaseFilter
  230. //=====================================================================
  231. //=====================================================================
  232. /* Override this to say what interfaces we support and where */
  233. STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid,
  234.                                                       void **ppv)
  235. {
  236.     /* Do we have this interface */
  237.     if (riid == IID_IBaseFilter) {
  238.         return GetInterface((IBaseFilter *) this, ppv);
  239.     } else if (riid == IID_IMediaFilter) {
  240.         return GetInterface((IMediaFilter *) this, ppv);
  241.     } else if (riid == IID_IPersist) {
  242.         return GetInterface((IPersist *) this, ppv);
  243.     } else if (riid == IID_IAMovieSetup) {
  244.         return GetInterface((IAMovieSetup *) this, ppv);
  245.     } else {
  246.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  247.     }
  248. }
  249. #ifdef DEBUG
  250. STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease()
  251. {
  252.     if (m_cRef == 1) {
  253.         KASSERT(m_pGraph == NULL);
  254.     }
  255.     return CUnknown::NonDelegatingRelease();
  256. }
  257. #endif
  258. /* Constructor */
  259. CBaseFilter::CBaseFilter(const TCHAR    *pName,
  260.              LPUNKNOWN  pUnk,
  261.              CCritSec   *pLock,
  262.              REFCLSID   clsid) :
  263.     CUnknown( pName, pUnk ),
  264.     m_pLock(pLock),
  265.     m_clsid(clsid),
  266.     m_State(State_Stopped),
  267.     m_pClock(NULL),
  268.     m_pGraph(NULL),
  269.     m_pSink(NULL),
  270.     m_pName(NULL),
  271.     m_PinVersion(1)
  272. {
  273.     ASSERT(pLock != NULL);
  274. }
  275. /* Passes in a redundant HRESULT argument */
  276. CBaseFilter::CBaseFilter(TCHAR     *pName,
  277.                          LPUNKNOWN  pUnk,
  278.                          CCritSec  *pLock,
  279.                          REFCLSID   clsid,
  280.                          HRESULT   *phr) :
  281.     CUnknown( pName, pUnk ),
  282.     m_pLock(pLock),
  283.     m_clsid(clsid),
  284.     m_State(State_Stopped),
  285.     m_pClock(NULL),
  286.     m_pGraph(NULL),
  287.     m_pSink(NULL),
  288.     m_pName(NULL),
  289.     m_PinVersion(1)
  290. {
  291.     ASSERT(pLock != NULL);
  292.     UNREFERENCED_PARAMETER(phr);
  293. }
  294. #ifdef UNICODE
  295. CBaseFilter::CBaseFilter(const CHAR *pName,
  296.              LPUNKNOWN  pUnk,
  297.              CCritSec   *pLock,
  298.              REFCLSID   clsid) :
  299.     CUnknown( pName, pUnk ),
  300.     m_pLock(pLock),
  301.     m_clsid(clsid),
  302.     m_State(State_Stopped),
  303.     m_pClock(NULL),
  304.     m_pGraph(NULL),
  305.     m_pSink(NULL),
  306.     m_pName(NULL),
  307.     m_PinVersion(1)
  308. {
  309.     ASSERT(pLock != NULL);
  310. }
  311. CBaseFilter::CBaseFilter(CHAR     *pName,
  312.                          LPUNKNOWN  pUnk,
  313.                          CCritSec  *pLock,
  314.                          REFCLSID   clsid,
  315.                          HRESULT   *phr) :
  316.     CUnknown( pName, pUnk ),
  317.     m_pLock(pLock),
  318.     m_clsid(clsid),
  319.     m_State(State_Stopped),
  320.     m_pClock(NULL),
  321.     m_pGraph(NULL),
  322.     m_pSink(NULL),
  323.     m_pName(NULL),
  324.     m_PinVersion(1)
  325. {
  326.     ASSERT(pLock != NULL);
  327.     UNREFERENCED_PARAMETER(phr);
  328. }
  329. #endif
  330. /* Destructor */
  331. CBaseFilter::~CBaseFilter()
  332. {
  333.     // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink
  334.     // When we did we had the circular reference problem.  Nothing would go away.
  335.     delete[] m_pName;
  336.     // must be stopped, but can't call Stop here since
  337.     // our critsec has been destroyed.
  338.     /* Release any clock we were using */
  339.     if (m_pClock) {
  340.         m_pClock->Release();
  341.         m_pClock = NULL;
  342.     }
  343. }
  344. /* Return the filter's clsid */
  345. STDMETHODIMP
  346. CBaseFilter::GetClassID(CLSID *pClsID)
  347. {
  348.     CheckPointer(pClsID,E_POINTER);
  349.     ValidateReadWritePtr(pClsID,sizeof(CLSID));
  350.     *pClsID = m_clsid;
  351.     return NOERROR;
  352. }
  353. /* Override this if your state changes are not done synchronously */
  354. STDMETHODIMP
  355. CBaseFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
  356. {
  357.     UNREFERENCED_PARAMETER(dwMSecs);
  358.     CheckPointer(State,E_POINTER);
  359.     ValidateReadWritePtr(State,sizeof(FILTER_STATE));
  360.     *State = m_State;
  361.     return S_OK;
  362. }
  363. /* Set the clock we will use for synchronisation */
  364. STDMETHODIMP
  365. CBaseFilter::SetSyncSource(IReferenceClock *pClock)
  366. {
  367.     CAutoLock cObjectLock(m_pLock);
  368.     // Ensure the new one does not go away - even if the same as the old
  369.     if (pClock) {
  370.         pClock->AddRef();
  371.     }
  372.     // if we have a clock, release it
  373.     if (m_pClock) {
  374.         m_pClock->Release();
  375.     }
  376.     // Set the new reference clock (might be NULL)
  377.     // Should we query it to ensure it is a clock?  Consider for a debug build.
  378.     m_pClock = pClock;
  379.     return NOERROR;
  380. }
  381. /* Return the clock we are using for synchronisation */
  382. STDMETHODIMP
  383. CBaseFilter::GetSyncSource(IReferenceClock **pClock)
  384. {
  385.     CheckPointer(pClock,E_POINTER);
  386.     ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
  387.     CAutoLock cObjectLock(m_pLock);
  388.     if (m_pClock) {
  389.         // returning an interface... addref it...
  390.         m_pClock->AddRef();
  391.     }
  392.     *pClock = (IReferenceClock*)m_pClock;
  393.     return NOERROR;
  394. }
  395. // override CBaseMediaFilter Stop method, to deactivate any pins this
  396. // filter has.
  397. STDMETHODIMP
  398. CBaseFilter::Stop()
  399. {
  400.     CAutoLock cObjectLock(m_pLock);
  401.     HRESULT hr = NOERROR;
  402.     // notify all pins of the state change
  403.     if (m_State != State_Stopped) {
  404.         int cPins = GetPinCount();
  405.         for (int c = 0; c < cPins; c++) {
  406.             CBasePin *pPin = GetPin(c);
  407.             // Disconnected pins are not activated - this saves pins worrying
  408.             // about this state themselves. We ignore the return code to make
  409.             // sure everyone is inactivated regardless. The base input pin
  410.             // class can return an error if it has no allocator but Stop can
  411.             // be used to resync the graph state after something has gone bad
  412.             if (pPin->IsConnected()) {
  413.                 HRESULT hrTmp = pPin->Inactive();
  414.                 if (FAILED(hrTmp) && SUCCEEDED(hr)) {
  415.                     hr = hrTmp;
  416.                 }
  417.             }
  418.         }
  419.     }
  420.     m_State = State_Stopped;
  421.     return hr;
  422. }
  423. // override CBaseMediaFilter Pause method to activate any pins
  424. // this filter has (also called from Run)
  425. STDMETHODIMP
  426. CBaseFilter::Pause()
  427. {
  428.     CAutoLock cObjectLock(m_pLock);
  429.     // notify all pins of the change to active state
  430.     if (m_State == State_Stopped) {
  431.         int cPins = GetPinCount();
  432.         for (int c = 0; c < cPins; c++) {
  433.             CBasePin *pPin = GetPin(c);
  434.             // Disconnected pins are not activated - this saves pins
  435.             // worrying about this state themselves
  436.             if (pPin->IsConnected()) {
  437.                 HRESULT hr = pPin->Active();
  438.                 if (FAILED(hr)) {
  439.                     return hr;
  440.                 }
  441.             }
  442.         }
  443.     }
  444.     m_State = State_Paused;
  445.     return S_OK;
  446. }
  447. // Put the filter into a running state.
  448. // The time parameter is the offset to be added to the samples'
  449. // stream time to get the reference time at which they should be presented.
  450. //
  451. // you can either add these two and compare it against the reference clock,
  452. // or you can call CBaseFilter::StreamTime and compare that against
  453. // the sample timestamp.
  454. STDMETHODIMP
  455. CBaseFilter::Run(REFERENCE_TIME tStart)
  456. {
  457.     CAutoLock cObjectLock(m_pLock);
  458.     // remember the stream time offset
  459.     m_tStart = tStart;
  460.     if (m_State == State_Stopped){
  461.     HRESULT hr = Pause();
  462.     if (FAILED(hr)) {
  463.         return hr;
  464.     }
  465.     }
  466.     // notify all pins of the change to active state
  467.     if (m_State != State_Running) {
  468.         int cPins = GetPinCount();
  469.         for (int c = 0; c < cPins; c++) {
  470.             CBasePin *pPin = GetPin(c);
  471.             // Disconnected pins are not activated - this saves pins
  472.             // worrying about this state themselves
  473.             if (pPin->IsConnected()) {
  474.                 HRESULT hr = pPin->Run(tStart);
  475.                 if (FAILED(hr)) {
  476.                     return hr;
  477.                 }
  478.             }
  479.         }
  480.     }
  481.     m_State = State_Running;
  482.     return S_OK;
  483. }
  484. //
  485. // return the current stream time - samples with start timestamps of this
  486. // time or before should be rendered by now
  487. HRESULT
  488. CBaseFilter::StreamTime(CRefTime& rtStream)
  489. {
  490.     // Caller must lock for synchronization
  491.     // We can't grab the filter lock because we want to be able to call
  492.     // this from worker threads without deadlocking
  493.     if (m_pClock == NULL) {
  494.         return VFW_E_NO_CLOCK;
  495.     }
  496.     // get the current reference time
  497.     HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
  498.     if (FAILED(hr)) {
  499.         return hr;
  500.     }
  501.     // subtract the stream offset to get stream time
  502.     rtStream -= m_tStart;
  503.     return S_OK;
  504. }
  505. /* Create an enumerator for the pins attached to this filter */
  506. STDMETHODIMP
  507. CBaseFilter::EnumPins(IEnumPins **ppEnum)
  508. {
  509.     CheckPointer(ppEnum,E_POINTER);
  510.     ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
  511.     /* Create a new ref counted enumerator */
  512.     *ppEnum = new CEnumPins(this,
  513.                         NULL);
  514.     return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
  515. }
  516. // default behaviour of FindPin is to assume pins are named
  517. // by their pin names
  518. STDMETHODIMP
  519. CBaseFilter::FindPin(
  520.     LPCWSTR Id,
  521.     IPin ** ppPin
  522. )
  523. {
  524.     CheckPointer(ppPin,E_POINTER);
  525.     ValidateReadWritePtr(ppPin,sizeof(IPin *));
  526.     //  We're going to search the pin list so maintain integrity
  527.     CAutoLock lck(m_pLock);
  528.     int iCount = GetPinCount();
  529.     for (int i = 0; i < iCount; i++) {
  530.         CBasePin *pPin = GetPin(i);
  531.         ASSERT(pPin != NULL);
  532.         if (0 == lstrcmpW(pPin->Name(), Id)) {
  533.             //  Found one that matches
  534.             //
  535.             //  AddRef() and return it
  536.             *ppPin = pPin;
  537.             pPin->AddRef();
  538.             return S_OK;
  539.         }
  540.     }
  541.     *ppPin = NULL;
  542.     return VFW_E_NOT_FOUND;
  543. }
  544. /* Return information about this filter */
  545. STDMETHODIMP
  546. CBaseFilter::QueryFilterInfo(FILTER_INFO * pInfo)
  547. {
  548.     CheckPointer(pInfo,E_POINTER);
  549.     ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO));
  550.     if (m_pName) {
  551.         lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR));
  552.     } else {
  553.         pInfo->achName[0] = L'';
  554.     }
  555.     pInfo->pGraph = m_pGraph;
  556.     if (m_pGraph)
  557.         m_pGraph->AddRef();
  558.     return NOERROR;
  559. }
  560. /* Provide the filter with a filter graph */
  561. STDMETHODIMP
  562. CBaseFilter::JoinFilterGraph(
  563.     IFilterGraph * pGraph,
  564.     LPCWSTR pName)
  565. {
  566.     CAutoLock cObjectLock(m_pLock);
  567.     // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink)
  568.     m_pGraph = pGraph;
  569.     if (m_pGraph) {
  570.         HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink,
  571.                         (void**) &m_pSink);
  572.         if (FAILED(hr)) {
  573.             ASSERT(m_pSink == NULL);
  574.         }
  575.         else m_pSink->Release();        // we do NOT keep a reference on it.
  576.     } else {
  577.         // if graph pointer is null, then we should
  578.         // also release the IMediaEventSink on the same object - we don't
  579.         // refcount it, so just set it to null
  580.         m_pSink = NULL;
  581.     }
  582.     if (m_pName) {
  583.         delete[] m_pName;
  584.         m_pName = NULL;
  585.     }
  586.     if (pName) {
  587.         DWORD nameLen = lstrlenW(pName)+1;
  588.         m_pName = new WCHAR[nameLen];
  589.         if (m_pName) {
  590.             CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR));
  591.         } else {
  592.             // !!! error here?
  593.             ASSERT(FALSE);
  594.         }
  595.     }
  596.     return NOERROR;
  597. }
  598. // return a Vendor information string. Optional - may return E_NOTIMPL.
  599. // memory returned should be freed using CoTaskMemFree
  600. // default implementation returns E_NOTIMPL
  601. STDMETHODIMP
  602. CBaseFilter::QueryVendorInfo(
  603.     LPWSTR* pVendorInfo)
  604. {
  605.     UNREFERENCED_PARAMETER(pVendorInfo);
  606.     return E_NOTIMPL;
  607. }
  608. // send an event notification to the filter graph if we know about it.
  609. // returns S_OK if delivered, S_FALSE if the filter graph does not sink
  610. // events, or an error otherwise.
  611. HRESULT
  612. CBaseFilter::NotifyEvent(
  613.     long EventCode,
  614.     LONG_PTR EventParam1,
  615.     LONG_PTR EventParam2)
  616. {
  617.     // Snapshot so we don't have to lock up
  618.     IMediaEventSink *pSink = m_pSink;
  619.     if (pSink) {
  620.         if (EC_COMPLETE == EventCode) {
  621.             EventParam2 = (LONG_PTR)(IBaseFilter*)this;
  622.         }
  623.         return pSink->Notify(EventCode, EventParam1, EventParam2);
  624.     } else {
  625.         return E_NOTIMPL;
  626.     }
  627. }
  628. // Request reconnect
  629. // pPin is the pin to reconnect
  630. // pmt is the type to reconnect with - can be NULL
  631. // Calls ReconnectEx on the filter graph
  632. HRESULT
  633. CBaseFilter::ReconnectPin(
  634.     IPin *pPin,
  635.     AM_MEDIA_TYPE const *pmt
  636. )
  637. {
  638.     IFilterGraph2 *pGraph2;
  639.     if (m_pGraph != NULL) {
  640.         HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2);
  641.         if (SUCCEEDED(hr)) {
  642.             hr = pGraph2->ReconnectEx(pPin, pmt);
  643.             pGraph2->Release();
  644.             return hr;
  645.         } else {
  646.             return m_pGraph->Reconnect(pPin);
  647.         }
  648.     } else {
  649.         return E_NOINTERFACE;
  650.     }
  651. }
  652. /* This is the same idea as the media type version does for type enumeration
  653.    on pins but for the list of pins available. So if the list of pins you
  654.    provide changes dynamically then either override this virtual function
  655.    to provide the version number, or more simply call IncrementPinVersion */
  656. LONG CBaseFilter::GetPinVersion()
  657. {
  658.     return m_PinVersion;
  659. }
  660. /* Increment the current pin version cookie */
  661. void CBaseFilter::IncrementPinVersion()
  662. {
  663.     InterlockedIncrement(&m_PinVersion);
  664. }
  665. /* register filter */
  666. STDMETHODIMP CBaseFilter::Register()
  667. {
  668.     // get setup data, if it exists
  669.     //
  670.     LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
  671.     // check we've got data
  672.     //
  673.     if( NULL == psetupdata ) return S_FALSE;
  674.     // init is ref counted so call just in case
  675.     // we're being called cold.
  676.     //
  677.     HRESULT hr = CoInitialize( (LPVOID)NULL );
  678.     ASSERT( SUCCEEDED(hr) );
  679.     // get hold of IFilterMapper
  680.     //
  681.     IFilterMapper *pIFM;
  682.     hr = CoCreateInstance( CLSID_FilterMapper
  683.                              , NULL
  684.                              , CLSCTX_INPROC_SERVER
  685.                              , IID_IFilterMapper
  686.                              , (void **)&pIFM       );
  687.     if( SUCCEEDED(hr) )
  688.     {
  689.         hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE );
  690.         pIFM->Release();
  691.     }
  692.     // and clear up
  693.     //
  694.     CoFreeUnusedLibraries();
  695.     CoUninitialize();
  696.     return NOERROR;
  697. }
  698. /* unregister filter */
  699. STDMETHODIMP CBaseFilter::Unregister()
  700. {
  701.     // get setup data, if it exists
  702.     //
  703.     LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
  704.     // check we've got data
  705.     //
  706.     if( NULL == psetupdata ) return S_FALSE;
  707.     // OLE init is ref counted so call
  708.     // just in case we're being called cold.
  709.     //
  710.     HRESULT hr = CoInitialize( (LPVOID)NULL );
  711.     ASSERT( SUCCEEDED(hr) );
  712.     // get hold of IFilterMapper
  713.     //
  714.     IFilterMapper *pIFM;
  715.     hr = CoCreateInstance( CLSID_FilterMapper
  716.                              , NULL
  717.                              , CLSCTX_INPROC_SERVER
  718.                              , IID_IFilterMapper
  719.                              , (void **)&pIFM       );
  720.     if( SUCCEEDED(hr) )
  721.     {
  722.         hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE );
  723.         // release interface
  724.         //
  725.         pIFM->Release();
  726.     }
  727.     // clear up
  728.     //
  729.     CoFreeUnusedLibraries();
  730.     CoUninitialize();
  731.     // handle one acceptable "error" - that
  732.     // of filter not being registered!
  733.     // (couldn't find a suitable #define'd
  734.     // name for the error!)
  735.     //
  736.     if( 0x80070002 == hr)
  737.       return NOERROR;
  738.     else
  739.       return hr;
  740. }
  741. //=====================================================================
  742. //=====================================================================
  743. // Implements CEnumPins
  744. //=====================================================================
  745. //=====================================================================
  746. CEnumPins::CEnumPins(CBaseFilter *pFilter,
  747.              CEnumPins *pEnumPins) :
  748.     m_Position(0),
  749.     m_PinCount(0),
  750.     m_pFilter(pFilter),
  751.     m_cRef(1),               // Already ref counted
  752.     m_PinCache(NAME("Pin Cache"))
  753. {
  754. #ifdef DEBUG
  755.     m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0);
  756. #endif
  757.     /* We must be owned by a filter derived from CBaseFilter */
  758.     ASSERT(pFilter != NULL);
  759.     /* Hold a reference count on our filter */
  760.     m_pFilter->AddRef();
  761.     /* Are we creating a new enumerator */
  762.     if (pEnumPins == NULL) {
  763.         m_Version = m_pFilter->GetPinVersion();
  764.         m_PinCount = m_pFilter->GetPinCount();
  765.     } else {
  766.         ASSERT(m_Position <= m_PinCount);
  767.         m_Position = pEnumPins->m_Position;
  768.         m_PinCount = pEnumPins->m_PinCount;
  769.         m_Version = pEnumPins->m_Version;
  770.         m_PinCache.AddTail(&(pEnumPins->m_PinCache));
  771.     }
  772. }
  773. /* Destructor releases the reference count on our filter NOTE since we hold
  774.    a reference count on the filter who created us we know it is safe to
  775.    release it, no access can be made to it afterwards though as we have just
  776.    caused the last reference count to go and the object to be deleted */
  777. CEnumPins::~CEnumPins()
  778. {
  779.     m_pFilter->Release();
  780. #ifdef DEBUG
  781.     DbgRegisterObjectDestruction(m_dwCookie);
  782. #endif
  783. }
  784. /* Override this to say what interfaces we support where */
  785. STDMETHODIMP
  786. CEnumPins::QueryInterface(REFIID riid,void **ppv)
  787. {
  788.     CheckPointer(ppv, E_POINTER);
  789.     /* Do we have this interface */
  790.     if (riid == IID_IEnumPins || riid == IID_IUnknown) {
  791.         return GetInterface((IEnumPins *) this, ppv);
  792.     } else {
  793.         *ppv = NULL;
  794.         return E_NOINTERFACE;
  795.     }
  796. }
  797. STDMETHODIMP_(ULONG)
  798. CEnumPins::AddRef()
  799. {
  800.     return InterlockedIncrement(&m_cRef);
  801. }
  802. STDMETHODIMP_(ULONG)
  803. CEnumPins::Release()
  804. {
  805.     ULONG cRef = InterlockedDecrement(&m_cRef);
  806.     if (cRef == 0) {
  807.         delete this;
  808.     }
  809.     return cRef;
  810. }
  811. /* One of an enumerator's basic member functions allows us to create a cloned
  812.    interface that initially has the same state. Since we are taking a snapshot
  813.    of an object (current position and all) we must lock access at the start */
  814. STDMETHODIMP
  815. CEnumPins::Clone(IEnumPins **ppEnum)
  816. {
  817.     CheckPointer(ppEnum,E_POINTER);
  818.     ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
  819.     HRESULT hr = NOERROR;
  820.     /* Check we are still in sync with the filter */
  821.     if (AreWeOutOfSync() == TRUE) {
  822.         *ppEnum = NULL;
  823.         hr =  VFW_E_ENUM_OUT_OF_SYNC;
  824.     } else {
  825.         *ppEnum = new CEnumPins(m_pFilter,
  826.                                 this);
  827.         if (*ppEnum == NULL) {
  828.             hr = E_OUTOFMEMORY;
  829.         }
  830.     }
  831.     return hr;
  832. }
  833. /* Return the next pin after the current position */
  834. STDMETHODIMP
  835. CEnumPins::Next(ULONG cPins,        // place this many pins...
  836.         IPin **ppPins,      // ...in this array
  837.         ULONG *pcFetched)   // actual count passed returned here
  838. {
  839.     CheckPointer(ppPins,E_POINTER);
  840.     ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *));
  841.     ASSERT(ppPins);
  842.     if (pcFetched!=NULL) {
  843.         ValidateWritePtr(pcFetched, sizeof(ULONG));
  844.         *pcFetched = 0;           // default unless we succeed
  845.     }
  846.     // now check that the parameter is valid
  847.     else if (cPins>1) {   // pcFetched == NULL
  848.         return E_INVALIDARG;
  849.     }
  850.     ULONG cFetched = 0;           // increment as we get each one.
  851.     /* Check we are still in sync with the filter */
  852.     if (AreWeOutOfSync() == TRUE) {
  853.     // If we are out of sync, we should refresh the enumerator.
  854.     // This will reset the position and update the other members, but
  855.     // will not clear cache of pins we have already returned.
  856.     Refresh();
  857.     }
  858.     /* Calculate the number of available pins */
  859.     int cRealPins = min(m_PinCount - m_Position, (int) cPins);
  860.     if (cRealPins == 0) {
  861.         return S_FALSE;
  862.     }
  863.     /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed
  864.        so we must QI for the IPin (which increments its reference count)
  865.        If while we are retrieving a pin from the filter an error occurs we
  866.        assume that our internal state is stale with respect to the filter
  867.        (for example someone has deleted a pin) so we
  868.        return VFW_E_ENUM_OUT_OF_SYNC                            */
  869.     while (cRealPins && (m_PinCount - m_Position)) {
  870.         /* Get the next pin object from the filter */
  871.         CBasePin *pPin = m_pFilter->GetPin(m_Position++);
  872.         if (pPin == NULL) {
  873.             // If this happend, and it's not the first time through, then we've got a problem,
  874.             // since we should really go back and release the iPins, which we have previously
  875.             // AddRef'ed.
  876.             ASSERT( cFetched==0 );
  877.             return VFW_E_ENUM_OUT_OF_SYNC;
  878.         }
  879.         /* We only want to return this pin, if it is not in our cache */
  880.         if (0 == m_PinCache.Find(pPin))
  881.         {
  882.             /* From the object get an IPin interface */
  883.             *ppPins = pPin;
  884.             pPin->AddRef();
  885.             cFetched++;
  886.             ppPins++;
  887.             m_PinCache.AddTail(pPin);
  888.             cRealPins--;
  889.         }
  890.     }
  891.     if (pcFetched!=NULL) {
  892.         *pcFetched = cFetched;
  893.     }
  894.     return (cPins==cFetched ? NOERROR : S_FALSE);
  895. }
  896. /* Skip over one or more entries in the enumerator */
  897. STDMETHODIMP
  898. CEnumPins::Skip(ULONG cPins)
  899. {
  900.     /* Check we are still in sync with the filter */
  901.     if (AreWeOutOfSync() == TRUE) {
  902.         return VFW_E_ENUM_OUT_OF_SYNC;
  903.     }
  904.     /* Work out how many pins are left to skip over */
  905.     /* We could position at the end if we are asked to skip too many... */
  906.     /* ..which would match the base implementation for CEnumMediaTypes::Skip */
  907.     ULONG PinsLeft = m_PinCount - m_Position;
  908.     if (cPins > PinsLeft) {
  909.         return S_FALSE;
  910.     }
  911.     m_Position += cPins;
  912.     return NOERROR;
  913. }
  914. /* Set the current position back to the start */
  915. /* Reset has 4 simple steps:
  916.  *
  917.  * Set position to head of list
  918.  * Sync enumerator with object being enumerated
  919.  * Clear the cache of pins already returned
  920.  * return S_OK
  921.  */
  922. STDMETHODIMP
  923. CEnumPins::Reset()
  924. {
  925.     m_Version = m_pFilter->GetPinVersion();
  926.     m_PinCount = m_pFilter->GetPinCount();
  927.     m_Position = 0;
  928.     // Clear the cache
  929.     m_PinCache.RemoveAll();
  930.     return S_OK;
  931. }
  932. /* Set the current position back to the start */
  933. /* Refresh has 3 simple steps:
  934.  *
  935.  * Set position to head of list
  936.  * Sync enumerator with object being enumerated
  937.  * return S_OK
  938.  */
  939. STDMETHODIMP
  940. CEnumPins::Refresh()
  941. {
  942.     m_Version = m_pFilter->GetPinVersion();
  943.     m_PinCount = m_pFilter->GetPinCount();
  944.     m_Position = 0;
  945.     return S_OK;
  946. }
  947. //=====================================================================
  948. //=====================================================================
  949. // Implements CEnumMediaTypes
  950. //=====================================================================
  951. //=====================================================================
  952. CEnumMediaTypes::CEnumMediaTypes(CBasePin *pPin,
  953.                  CEnumMediaTypes *pEnumMediaTypes) :
  954.     m_Position(0),
  955.     m_pPin(pPin),
  956.     m_cRef(1)
  957. {
  958. #ifdef DEBUG
  959.     m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0);
  960. #endif
  961.     /* We must be owned by a pin derived from CBasePin */
  962.     ASSERT(pPin != NULL);
  963.     /* Hold a reference count on our pin */
  964.     m_pPin->AddRef();
  965.     /* Are we creating a new enumerator */
  966.     if (pEnumMediaTypes == NULL) {
  967.         m_Version = m_pPin->GetMediaTypeVersion();
  968.         return;
  969.     }
  970.     m_Position = pEnumMediaTypes->m_Position;
  971.     m_Version = pEnumMediaTypes->m_Version;
  972. }
  973. /* Destructor releases the reference count on our base pin. NOTE since we hold
  974.    a reference count on the pin who created us we know it is safe to release
  975.    it, no access can be made to it afterwards though as we might have just
  976.    caused the last reference count to go and the object to be deleted */
  977. CEnumMediaTypes::~CEnumMediaTypes()
  978. {
  979. #ifdef DEBUG
  980.     DbgRegisterObjectDestruction(m_dwCookie);
  981. #endif
  982.     m_pPin->Release();
  983. }
  984. /* Override this to say what interfaces we support where */
  985. STDMETHODIMP
  986. CEnumMediaTypes::QueryInterface(REFIID riid,void **ppv)
  987. {
  988.     CheckPointer(ppv, E_POINTER);
  989.     /* Do we have this interface */
  990.     if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) {
  991.         return GetInterface((IEnumMediaTypes *) this, ppv);
  992.     } else {
  993.         *ppv = NULL;
  994.         return E_NOINTERFACE;
  995.     }
  996. }
  997. STDMETHODIMP_(ULONG)
  998. CEnumMediaTypes::AddRef()
  999. {
  1000.     return InterlockedIncrement(&m_cRef);
  1001. }
  1002. STDMETHODIMP_(ULONG)
  1003. CEnumMediaTypes::Release()
  1004. {
  1005.     ULONG cRef = InterlockedDecrement(&m_cRef);
  1006.     if (cRef == 0) {
  1007.         delete this;
  1008.     }
  1009.     return cRef;
  1010. }
  1011. /* One of an enumerator's basic member functions allows us to create a cloned
  1012.    interface that initially has the same state. Since we are taking a snapshot
  1013.    of an object (current position and all) we must lock access at the start */
  1014. STDMETHODIMP
  1015. CEnumMediaTypes::Clone(IEnumMediaTypes **ppEnum)
  1016. {
  1017.     CheckPointer(ppEnum,E_POINTER);
  1018.     ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
  1019.     HRESULT hr = NOERROR;
  1020.     /* Check we are still in sync with the pin */
  1021.     if (AreWeOutOfSync() == TRUE) {
  1022.         *ppEnum = NULL;
  1023.         hr = VFW_E_ENUM_OUT_OF_SYNC;
  1024.     } else {
  1025.         *ppEnum = new CEnumMediaTypes(m_pPin,
  1026.                                       this);
  1027.         if (*ppEnum == NULL) {
  1028.             hr =  E_OUTOFMEMORY;
  1029.         }
  1030.     }
  1031.     return hr;
  1032. }
  1033. /* Enumerate the next pin(s) after the current position. The client using this
  1034.    interface passes in a pointer to an array of pointers each of which will
  1035.    be filled in with a pointer to a fully initialised media type format
  1036.    Return NOERROR if it all works,
  1037.           S_FALSE if fewer than cMediaTypes were enumerated.
  1038.           VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by
  1039.                                  state changes in the filter
  1040.    The actual count always correctly reflects the number of types in the array.
  1041. */
  1042. STDMETHODIMP
  1043. CEnumMediaTypes::Next(ULONG cMediaTypes,          // place this many types...
  1044.               AM_MEDIA_TYPE **ppMediaTypes,   // ...in this array
  1045.               ULONG *pcFetched)           // actual count passed
  1046. {
  1047.     CheckPointer(ppMediaTypes,E_POINTER);
  1048.     ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *));
  1049.     /* Check we are still in sync with the pin */
  1050.     if (AreWeOutOfSync() == TRUE) {
  1051.         return VFW_E_ENUM_OUT_OF_SYNC;
  1052.     }
  1053.     if (pcFetched!=NULL) {
  1054.         ValidateWritePtr(pcFetched, sizeof(ULONG));
  1055.         *pcFetched = 0;           // default unless we succeed
  1056.     }
  1057.     // now check that the parameter is valid
  1058.     else if (cMediaTypes>1) {     // pcFetched == NULL
  1059.         return E_INVALIDARG;
  1060.     }
  1061.     ULONG cFetched = 0;           // increment as we get each one.
  1062.     /* Return each media type by asking the filter for them in turn - If we
  1063.        have an error code retured to us while we are retrieving a media type
  1064.        we assume that our internal state is stale with respect to the filter
  1065.        (for example the window size changing) so we return
  1066.        VFW_E_ENUM_OUT_OF_SYNC */
  1067.     while (cMediaTypes) {
  1068.         CMediaType cmt;
  1069.         HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt);
  1070.         if (S_OK != hr) {
  1071.             break;
  1072.         }
  1073.         /* We now have a CMediaType object that contains the next media type
  1074.            but when we assign it to the array position we CANNOT just assign
  1075.            the AM_MEDIA_TYPE structure because as soon as the object goes out of
  1076.            scope it will delete the memory we have just copied. The function
  1077.            we use is CreateMediaType which allocates a task memory block */
  1078.         /*  Transfer across the format block manually to save an allocate
  1079.             and free on the format block and generally go faster */
  1080.         *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
  1081.         if (*ppMediaTypes == NULL) {
  1082.             break;
  1083.         }
  1084.         /*  Do a regular copy */
  1085.         **ppMediaTypes = (AM_MEDIA_TYPE)cmt;
  1086.         /*  Make sure the destructor doesn't free these */
  1087.         cmt.pbFormat = NULL;
  1088.         cmt.cbFormat = NULL;
  1089.         cmt.pUnk     = NULL;
  1090.         ppMediaTypes++;
  1091.         cFetched++;
  1092.         cMediaTypes--;
  1093.     }
  1094.     if (pcFetched!=NULL) {
  1095.         *pcFetched = cFetched;
  1096.     }
  1097.     return ( cMediaTypes==0 ? NOERROR : S_FALSE );
  1098. }
  1099. /* Skip over one or more entries in the enumerator */
  1100. STDMETHODIMP
  1101. CEnumMediaTypes::Skip(ULONG cMediaTypes)
  1102. {
  1103.     //  If we're skipping 0 elements we're guaranteed to skip the
  1104.     //  correct number of elements
  1105.     if (cMediaTypes == 0) {
  1106.         return S_OK;
  1107.     }
  1108.     /* Check we are still in sync with the pin */
  1109.     if (AreWeOutOfSync() == TRUE) {
  1110.         return VFW_E_ENUM_OUT_OF_SYNC;
  1111.     }
  1112.     m_Position += cMediaTypes;
  1113.     /*  See if we're over the end */
  1114.     CMediaType cmt;
  1115.     return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE;
  1116. }
  1117. /* Set the current position back to the start */
  1118. /* Reset has 3 simple steps:
  1119.  *
  1120.  * set position to head of list
  1121.  * sync enumerator with object being enumerated
  1122.  * return S_OK
  1123.  */
  1124. STDMETHODIMP
  1125. CEnumMediaTypes::Reset()
  1126. {
  1127.     m_Position = 0;
  1128.     // Bring the enumerator back into step with the current state.  This
  1129.     // may be a noop but ensures that the enumerator will be valid on the
  1130.     // next call.
  1131.     m_Version = m_pPin->GetMediaTypeVersion();
  1132.     return NOERROR;
  1133. }
  1134. //=====================================================================
  1135. //=====================================================================
  1136. // Implements CBasePin
  1137. //=====================================================================
  1138. //=====================================================================
  1139. /* NOTE The implementation of this class calls the CUnknown constructor with
  1140.    a NULL outer unknown pointer. This has the effect of making us a self
  1141.    contained class, ie any QueryInterface, AddRef or Release calls will be
  1142.    routed to the class's NonDelegatingUnknown methods. You will typically
  1143.    find that the classes that do this then override one or more of these
  1144.    virtual functions to provide more specialised behaviour. A good example
  1145.    of this is where a class wants to keep the QueryInterface internal but
  1146.    still wants its lifetime controlled by the external object */
  1147. /* Constructor */
  1148. CBasePin::CBasePin(TCHAR *pObjectName,
  1149.            CBaseFilter *pFilter,
  1150.            CCritSec *pLock,
  1151.            HRESULT *phr,
  1152.            LPCWSTR pName,
  1153.            PIN_DIRECTION dir) :
  1154.     CUnknown( pObjectName, NULL ),
  1155.     m_pFilter(pFilter),
  1156.     m_pLock(pLock),
  1157.     m_pName(NULL),
  1158.     m_Connected(NULL),
  1159.     m_dir(dir),
  1160.     m_bRunTimeError(FALSE),
  1161.     m_pQSink(NULL),
  1162.     m_TypeVersion(1),
  1163.     m_tStart(),
  1164.     m_tStop(MAX_TIME),
  1165.     m_bCanReconnectWhenActive(false),
  1166.     m_bTryMyTypesFirst(false),
  1167.     m_dRate(1.0)
  1168. {
  1169.     /*  WARNING - pFilter is often not a properly constituted object at
  1170.         this state (in particular QueryInterface may not work) - this
  1171.         is because its owner is often its containing object and we
  1172.         have been called from the containing object's constructor so
  1173.         the filter's owner has not yet had its CUnknown constructor
  1174.         called
  1175.     */
  1176.     ASSERT(pFilter != NULL);
  1177.     ASSERT(pLock != NULL);
  1178.     if (pName) {
  1179.         DWORD nameLen = lstrlenW(pName)+1;
  1180.         m_pName = new WCHAR[nameLen];
  1181.         if (m_pName) {
  1182.             CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR));
  1183.         }
  1184.     }
  1185. #ifdef DEBUG
  1186.     m_cRef = 0;
  1187. #endif
  1188. }
  1189. #ifdef UNICODE
  1190. CBasePin::CBasePin(CHAR *pObjectName,
  1191.            CBaseFilter *pFilter,
  1192.            CCritSec *pLock,
  1193.            HRESULT *phr,
  1194.            LPCWSTR pName,
  1195.            PIN_DIRECTION dir) :
  1196.     CUnknown( pObjectName, NULL ),
  1197.     m_pFilter(pFilter),
  1198.     m_pLock(pLock),
  1199.     m_pName(NULL),
  1200.     m_Connected(NULL),
  1201.     m_dir(dir),
  1202.     m_bRunTimeError(FALSE),
  1203.     m_pQSink(NULL),
  1204.     m_TypeVersion(1),
  1205.     m_tStart(),
  1206.     m_tStop(MAX_TIME),
  1207.     m_bCanReconnectWhenActive(false),
  1208.     m_bTryMyTypesFirst(false),
  1209.     m_dRate(1.0)
  1210. {
  1211.     /*  WARNING - pFilter is often not a properly constituted object at
  1212.         this state (in particular QueryInterface may not work) - this
  1213.         is because its owner is often its containing object and we
  1214.         have been called from the containing object's constructor so
  1215.         the filter's owner has not yet had its CUnknown constructor
  1216.         called
  1217.     */
  1218.     ASSERT(pFilter != NULL);
  1219.     ASSERT(pLock != NULL);
  1220.     if (pName) {
  1221.         DWORD nameLen = lstrlenW(pName)+1;
  1222.         m_pName = new WCHAR[nameLen];
  1223.         if (m_pName) {
  1224.             CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR));
  1225.         }
  1226.     }
  1227. #ifdef DEBUG
  1228.     m_cRef = 0;
  1229. #endif
  1230. }
  1231. #endif
  1232. /* Destructor since a connected pin holds a reference count on us there is
  1233.    no way that we can be deleted unless we are not currently connected */
  1234. CBasePin::~CBasePin()
  1235. {
  1236.     //  We don't call disconnect because if the filter is going away
  1237.     //  all the pins must have a reference count of zero so they must
  1238.     //  have been disconnected anyway - (but check the assumption)
  1239.     ASSERT(m_Connected == FALSE);
  1240.     delete[] m_pName;
  1241.     // check the internal reference count is consistent
  1242.     ASSERT(m_cRef == 0);
  1243. }
  1244. /* Override this to say what interfaces we support and where */
  1245. STDMETHODIMP
  1246. CBasePin::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
  1247. {
  1248.     /* Do we have this interface */
  1249.     if (riid == IID_IPin) {
  1250.         return GetInterface((IPin *) this, ppv);
  1251.     } else if (riid == IID_IQualityControl) {
  1252.         return GetInterface((IQualityControl *) this, ppv);
  1253.     } else {
  1254.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  1255.     }
  1256. }
  1257. /* Override to increment the owning filter's reference count */
  1258. STDMETHODIMP_(ULONG)
  1259. CBasePin::NonDelegatingAddRef()
  1260. {
  1261.     ASSERT(InterlockedIncrement(&m_cRef) > 0);
  1262.     return m_pFilter->AddRef();
  1263. }
  1264. /* Override to decrement the owning filter's reference count */
  1265. STDMETHODIMP_(ULONG)
  1266. CBasePin::NonDelegatingRelease()
  1267. {
  1268.     ASSERT(InterlockedDecrement(&m_cRef) >= 0);
  1269.     return m_pFilter->Release();
  1270. }
  1271. /* Displays pin connection information */
  1272. #ifdef DEBUG
  1273. void
  1274. CBasePin::DisplayPinInfo(IPin *pReceivePin)
  1275. {
  1276.     if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) {
  1277.         PIN_INFO ConnectPinInfo;
  1278.         PIN_INFO ReceivePinInfo;
  1279.         if (FAILED(QueryPinInfo(&ConnectPinInfo))) {
  1280.             (void)StringCchCopyW(ConnectPinInfo.achName, NUMELMS(ConnectPinInfo.achName),L"Bad Pin");
  1281.         } else {
  1282.             QueryPinInfoReleaseFilter(ConnectPinInfo);
  1283.         }
  1284.         if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) {
  1285.             (void)StringCchCopyW(ReceivePinInfo.achName, NUMELMS(ReceivePinInfo.achName),L"Bad Pin");
  1286.         } else {
  1287.             QueryPinInfoReleaseFilter(ReceivePinInfo);
  1288.         }
  1289.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :")));
  1290.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    <%ls>"), ConnectPinInfo.achName));
  1291.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    <%ls>"), ReceivePinInfo.achName));
  1292.     }
  1293. }
  1294. #endif
  1295. /* Displays general information on the pin media type */
  1296. #ifdef DEBUG
  1297. void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt)
  1298. {
  1299.     UNREFERENCED_PARAMETER(pPin);
  1300.     if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) {
  1301.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:")));
  1302.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    major type:  %hs"),
  1303.                GuidNames[*pmt->Type()]));
  1304.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    sub type  :  %hs"),
  1305.                GuidNames[*pmt->Subtype()]));
  1306.     }
  1307. }
  1308. #endif
  1309. /* Asked to connect to a pin. A pin is always attached to an owning filter
  1310.    object so we always delegate our locking to that object. We first of all
  1311.    retrieve a media type enumerator for the input pin and see if we accept
  1312.    any of the formats that it would ideally like, failing that we retrieve
  1313.    our enumerator and see if it will accept any of our preferred types */
  1314. STDMETHODIMP
  1315. CBasePin::Connect(
  1316.     IPin * pReceivePin,
  1317.     const AM_MEDIA_TYPE *pmt   // optional media type
  1318. )
  1319. {
  1320.     CheckPointer(pReceivePin,E_POINTER);
  1321.     ValidateReadPtr(pReceivePin,sizeof(IPin));
  1322.     CAutoLock cObjectLock(m_pLock);
  1323.     DisplayPinInfo(pReceivePin);
  1324.     /* See if we are already connected */
  1325.     if (m_Connected) {
  1326.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected")));
  1327.         return VFW_E_ALREADY_CONNECTED;
  1328.     }
  1329.     /* See if the filter is active */
  1330.     if (!IsStopped() && !m_bCanReconnectWhenActive) {
  1331.         return VFW_E_NOT_STOPPED;
  1332.     }
  1333.     // Find a mutually agreeable media type -
  1334.     // Pass in the template media type. If this is partially specified,
  1335.     // each of the enumerated media types will need to be checked against
  1336.     // it. If it is non-null and fully specified, we will just try to connect
  1337.     // with this.
  1338.     const CMediaType * ptype = (CMediaType*)pmt;
  1339.     HRESULT hr = AgreeMediaType(pReceivePin, ptype);
  1340.     if (FAILED(hr)) {
  1341.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type")));
  1342.         // Since the procedure is already returning an error code, there
  1343.         // is nothing else this function can do to report the error.
  1344.         EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
  1345.         return hr;
  1346.     }
  1347.     DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded")));
  1348.     return NOERROR;
  1349. }
  1350. // given a specific media type, attempt a connection (includes
  1351. // checking that the type is acceptable to this pin)
  1352. HRESULT
  1353. CBasePin::AttemptConnection(
  1354.     IPin* pReceivePin,      // connect to this pin
  1355.     const CMediaType* pmt   // using this type
  1356. )
  1357. {
  1358.     // The caller should hold the filter lock becasue this function
  1359.     // uses m_Connected.  The caller should also hold the filter lock
  1360.     // because this function calls SetMediaType(), IsStopped() and
  1361.     // CompleteConnect().
  1362.     ASSERT(CritCheckIn(m_pLock));
  1363.     // Check that the connection is valid  -- need to do this for every
  1364.     // connect attempt since BreakConnect will undo it.
  1365.     HRESULT hr = CheckConnect(pReceivePin);
  1366.     if (FAILED(hr)) {
  1367.         DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed")));
  1368.         // Since the procedure is already returning an error code, there
  1369.         // is nothing else this function can do to report the error.
  1370.         EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
  1371.         return hr;
  1372.     }
  1373.     DisplayTypeInfo(pReceivePin, pmt);
  1374.     /* Check we will accept this media type */
  1375.     hr = CheckMediaType(pmt);
  1376.     if (hr == NOERROR) {
  1377.         /*  Make ourselves look connected otherwise ReceiveConnection
  1378.             may not be able to complete the connection
  1379.         */
  1380.         m_Connected = pReceivePin;
  1381.         m_Connected->AddRef();
  1382.         hr = SetMediaType(pmt);
  1383.         if (SUCCEEDED(hr)) {
  1384.             /* See if the other pin will accept this type */
  1385.             hr = pReceivePin->ReceiveConnection((IPin *)this, pmt);
  1386.             if (SUCCEEDED(hr)) {
  1387.                 /* Complete the connection */
  1388.                 hr = CompleteConnect(pReceivePin);
  1389.                 if (SUCCEEDED(hr)) {
  1390.                     return hr;
  1391.                 } else {
  1392.                     DbgLog((LOG_TRACE,
  1393.                             CONNECT_TRACE_LEVEL,
  1394.                             TEXT("Failed to complete connection")));
  1395.                     pReceivePin->Disconnect();
  1396.                 }
  1397.             }
  1398.         }
  1399.     } else {
  1400.         // we cannot use this media type
  1401.         // return a specific media type error if there is one
  1402.         // or map a general failure code to something more helpful
  1403.         // (in particular S_FALSE gets changed to an error code)
  1404.         if (SUCCEEDED(hr) ||
  1405.             (hr == E_FAIL) ||
  1406.             (hr == E_INVALIDARG)) {
  1407.             hr = VFW_E_TYPE_NOT_ACCEPTED;
  1408.         }
  1409.     }
  1410.     // BreakConnect and release any connection here in case CheckMediaType
  1411.     // failed, or if we set anything up during a call back during
  1412.     // ReceiveConnection.
  1413.     // Since the procedure is already returning an error code, there
  1414.     // is nothing else this function can do to report the error.
  1415.     EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
  1416.     /*  If failed then undo our state */
  1417.     if (m_Connected) {
  1418.         m_Connected->Release();
  1419.         m_Connected = NULL;
  1420.     }
  1421.     return hr;
  1422. }
  1423. /* Given an enumerator we cycle through all the media types it proposes and
  1424.    firstly suggest them to our derived pin class and if that succeeds try
  1425.    them with the pin in a ReceiveConnection call. This means that if our pin
  1426.    proposes a media type we still check in here that we can support it. This
  1427.    is deliberate so that in simple cases the enumerator can hold all of the
  1428.    media types even if some of them are not really currently available */
  1429. HRESULT CBasePin::TryMediaTypes(
  1430.     IPin *pReceivePin,
  1431.     const CMediaType *pmt,
  1432.     IEnumMediaTypes *pEnum)
  1433. {
  1434.     /* Reset the current enumerator position */
  1435.     HRESULT hr = pEnum->Reset();
  1436.     if (FAILED(hr)) {
  1437.         return hr;
  1438.     }
  1439.     CMediaType *pMediaType = NULL;
  1440.     ULONG ulMediaCount = 0;
  1441.     // attempt to remember a specific error code if there is one
  1442.     HRESULT hrFailure = S_OK;
  1443.     for (;;) {
  1444.         /* Retrieve the next media type NOTE each time round the loop the
  1445.            enumerator interface will allocate another AM_MEDIA_TYPE structure
  1446.            If we are successful then we copy it into our output object, if
  1447.            not then we must delete the memory allocated before returning */
  1448.         hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount);
  1449.         if (hr != S_OK) {
  1450.             if (S_OK == hrFailure) {
  1451.                 hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
  1452.             }
  1453.             return hrFailure;
  1454.         }
  1455.         ASSERT(ulMediaCount == 1);
  1456.         ASSERT(pMediaType);
  1457.         // check that this matches the partial type (if any)
  1458.         if ((pmt == NULL) ||
  1459.             pMediaType->MatchesPartial(pmt)) {
  1460.             hr = AttemptConnection(pReceivePin, pMediaType);
  1461.             // attempt to remember a specific error code
  1462.             if (FAILED(hr) &&
  1463.             SUCCEEDED(hrFailure) &&
  1464.             (hr != E_FAIL) &&
  1465.             (hr != E_INVALIDARG) &&
  1466.             (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
  1467.                 hrFailure = hr;
  1468.             }
  1469.         } else {
  1470.             hr = VFW_E_NO_ACCEPTABLE_TYPES;
  1471.         }
  1472.         DeleteMediaType(pMediaType);
  1473.         if (S_OK == hr) {
  1474.             return hr;
  1475.         }
  1476.     }
  1477. }
  1478. /* This is called to make the connection, including the taask of finding
  1479.    a media type for the pin connection. pmt is the proposed media type
  1480.    from the Connect call: if this is fully specified, we will try that.
  1481.    Otherwise we enumerate and try all the input pin's types first and
  1482.    if that fails we then enumerate and try all our preferred media types.
  1483.    For each media type we check it against pmt (if non-null and partially
  1484.    specified) as well as checking that both pins will accept it.
  1485.  */
  1486. HRESULT CBasePin::AgreeMediaType(
  1487.     IPin *pReceivePin,
  1488.     const CMediaType *pmt)
  1489. {
  1490.     ASSERT(pReceivePin);
  1491.     IEnumMediaTypes *pEnumMediaTypes = NULL;
  1492.     // if the media type is fully specified then use that
  1493.     if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) {
  1494.         // if this media type fails, then we must fail the connection
  1495.         // since if pmt is nonnull we are only allowed to connect
  1496.         // using a type that matches it.
  1497.         return AttemptConnection(pReceivePin, pmt);
  1498.     }
  1499.     /* Try the other pin's enumerator */
  1500.     HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
  1501.     for (int i = 0; i < 2; i++) {
  1502.         HRESULT hr;
  1503.         if (i == (int)m_bTryMyTypesFirst) {
  1504.             hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes);
  1505.         } else {
  1506.             hr = EnumMediaTypes(&pEnumMediaTypes);
  1507.         }
  1508.         if (SUCCEEDED(hr)) {
  1509.             ASSERT(pEnumMediaTypes);
  1510.             hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes);
  1511.             pEnumMediaTypes->Release();
  1512.             if (SUCCEEDED(hr)) {
  1513.                 return NOERROR;
  1514.             } else {
  1515.                 // try to remember specific error codes if there are any
  1516.                 if ((hr != E_FAIL) &&
  1517.                     (hr != E_INVALIDARG) &&
  1518.                     (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
  1519.                     hrFailure = hr;
  1520.                 }
  1521.             }
  1522.         }
  1523.     }
  1524.     return hrFailure;
  1525. }
  1526. /* Called when we want to complete a connection to another filter. Failing
  1527.    this will also fail the connection and disconnect the other pin as well */
  1528. HRESULT
  1529. CBasePin::CompleteConnect(IPin *pReceivePin)
  1530. {
  1531.     UNREFERENCED_PARAMETER(pReceivePin);
  1532.     return NOERROR;
  1533. }
  1534. /* This is called to set the format for a pin connection - CheckMediaType
  1535.    will have been called to check the connection format and if it didn't
  1536.    return an error code then this (virtual) function will be invoked */
  1537. HRESULT
  1538. CBasePin::SetMediaType(const CMediaType *pmt)
  1539. {
  1540.     HRESULT hr = m_mt.Set(*pmt);
  1541.     if (FAILED(hr)) {
  1542.         return hr;
  1543.     }
  1544.     return NOERROR;
  1545. }
  1546. /* This is called during Connect() to provide a virtual method that can do
  1547.    any specific check needed for connection such as QueryInterface. This
  1548.    base class method just checks that the pin directions don't match */
  1549. HRESULT
  1550. CBasePin::CheckConnect(IPin * pPin)
  1551. {
  1552.     /* Check that pin directions DONT match */
  1553.     PIN_DIRECTION pd;
  1554.     pPin->QueryDirection(&pd);
  1555.     ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT));
  1556.     ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT));
  1557.     // we should allow for non-input and non-output connections?
  1558.     if (pd == m_dir) {
  1559.         return VFW_E_INVALID_DIRECTION;
  1560.     }
  1561.     return NOERROR;
  1562. }
  1563. /* This is called when we realise we can't make a connection to the pin and
  1564.    must undo anything we did in CheckConnect - override to release QIs done */
  1565. HRESULT
  1566. CBasePin::BreakConnect()
  1567. {
  1568.     return NOERROR;
  1569. }
  1570. /* Called normally by an output pin on an input pin to try and establish a
  1571.    connection.
  1572. */
  1573. STDMETHODIMP
  1574. CBasePin::ReceiveConnection(
  1575.     IPin * pConnector,      // this is the pin who we will connect to
  1576.     const AM_MEDIA_TYPE *pmt    // this is the media type we will exchange
  1577. )
  1578. {
  1579.     CheckPointer(pConnector,E_POINTER);
  1580.     CheckPointer(pmt,E_POINTER);
  1581.     ValidateReadPtr(pConnector,sizeof(IPin));
  1582.     ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
  1583.     CAutoLock cObjectLock(m_pLock);
  1584.     /* Are we already connected */
  1585.     if (m_Connected) {
  1586.         return VFW_E_ALREADY_CONNECTED;
  1587.     }
  1588.     /* See if the filter is active */
  1589.     if (!IsStopped() && !m_bCanReconnectWhenActive) {
  1590.         return VFW_E_NOT_STOPPED;
  1591.     }
  1592.     HRESULT hr = CheckConnect(pConnector);
  1593.     if (FAILED(hr)) {
  1594.         // Since the procedure is already returning an error code, there
  1595.         // is nothing else this function can do to report the error.
  1596.         EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
  1597.         return hr;
  1598.     }
  1599.     /* Ask derived class if this media type is ok */
  1600.     CMediaType * pcmt = (CMediaType*) pmt;
  1601.     hr = CheckMediaType(pcmt);
  1602.     if (hr != NOERROR) {
  1603.         // no -we don't support this media type
  1604.         // Since the procedure is already returning an error code, there
  1605.         // is nothing else this function can do to report the error.
  1606.         EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
  1607.         // return a specific media type error if there is one
  1608.         // or map a general failure code to something more helpful
  1609.         // (in particular S_FALSE gets changed to an error code)
  1610.         if (SUCCEEDED(hr) ||
  1611.             (hr == E_FAIL) ||
  1612.             (hr == E_INVALIDARG)) {
  1613.             hr = VFW_E_TYPE_NOT_ACCEPTED;
  1614.         }
  1615.         return hr;
  1616.     }
  1617.     /* Complete the connection */
  1618.     m_Connected = pConnector;
  1619.     m_Connected->AddRef();
  1620.     hr = SetMediaType(pcmt);
  1621.     if (SUCCEEDED(hr)) {
  1622.         hr = CompleteConnect(pConnector);
  1623.         if (SUCCEEDED(hr)) {
  1624.             return NOERROR;
  1625.         }
  1626.     }
  1627.     DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection.")));
  1628.     m_Connected->Release();
  1629.     m_Connected = NULL;
  1630.     // Since the procedure is already returning an error code, there
  1631.     // is nothing else this function can do to report the error.
  1632.     EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
  1633.     return hr;
  1634. }
  1635. /* Called when we want to terminate a pin connection */
  1636. STDMETHODIMP
  1637. CBasePin::Disconnect()
  1638. {
  1639.     CAutoLock cObjectLock(m_pLock);
  1640.     /* See if the filter is active */
  1641.     if (!IsStopped()) {
  1642.         return VFW_E_NOT_STOPPED;
  1643.     }
  1644.     return DisconnectInternal();
  1645. }
  1646. STDMETHODIMP
  1647. CBasePin::DisconnectInternal()
  1648. {
  1649.     ASSERT(CritCheckIn(m_pLock));
  1650.     if (m_Connected) {
  1651.         HRESULT hr = BreakConnect();
  1652.         if( FAILED( hr ) ) {
  1653.             // There is usually a bug in the program if BreakConnect() fails.
  1654.             DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." );
  1655.             return hr;
  1656.         }
  1657.         m_Connected->Release();
  1658.         m_Connected = NULL;
  1659.         return S_OK;
  1660.     } else {
  1661.         // no connection - not an error
  1662.         return S_FALSE;
  1663.     }
  1664. }
  1665. /* Return an AddRef()'d pointer to the connected pin if there is one */
  1666. STDMETHODIMP
  1667. CBasePin::ConnectedTo(
  1668.     IPin **ppPin
  1669. )
  1670. {
  1671.     CheckPointer(ppPin,E_POINTER);
  1672.     ValidateReadWritePtr(ppPin,sizeof(IPin *));
  1673.     //
  1674.     //  It's pointless to lock here.
  1675.     //  The caller should ensure integrity.
  1676.     //
  1677.     IPin *pPin = m_Connected;
  1678.     *ppPin = pPin;
  1679.     if (pPin != NULL) {
  1680.         pPin->AddRef();
  1681.         return S_OK;
  1682.     } else {
  1683.         ASSERT(*ppPin == NULL);
  1684.         return VFW_E_NOT_CONNECTED;
  1685.     }
  1686. }
  1687. /* Return the media type of the connection */
  1688. STDMETHODIMP
  1689. CBasePin::ConnectionMediaType(
  1690.     AM_MEDIA_TYPE *pmt
  1691. )
  1692. {
  1693.     CheckPointer(pmt,E_POINTER);
  1694.     ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE));
  1695.     CAutoLock cObjectLock(m_pLock);
  1696.     /*  Copy constructor of m_mt allocates the memory */
  1697.     if (IsConnected()) {
  1698.         CopyMediaType( pmt, &m_mt );
  1699.         return S_OK;
  1700.     } else {
  1701.         ((CMediaType *)pmt)->InitMediaType();
  1702.         return VFW_E_NOT_CONNECTED;
  1703.     }
  1704. }
  1705. /* Return information about the filter we are connect to */
  1706. STDMETHODIMP
  1707. CBasePin::QueryPinInfo(
  1708.     PIN_INFO * pInfo
  1709. )
  1710. {
  1711.     CheckPointer(pInfo,E_POINTER);
  1712.     ValidateReadWritePtr(pInfo,sizeof(PIN_INFO));
  1713.     pInfo->pFilter = m_pFilter;
  1714.     if (m_pFilter) {
  1715.         m_pFilter->AddRef();
  1716.     }
  1717.     if (m_pName) {
  1718.         lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR));
  1719.     } else {
  1720.         pInfo->achName[0] = L'';
  1721.     }
  1722.     pInfo->dir = m_dir;
  1723.     return NOERROR;
  1724. }
  1725. STDMETHODIMP
  1726. CBasePin::QueryDirection(
  1727.     PIN_DIRECTION * pPinDir
  1728. )
  1729. {
  1730.     CheckPointer(pPinDir,E_POINTER);
  1731.     ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION));
  1732.     *pPinDir = m_dir;
  1733.     return NOERROR;
  1734. }
  1735. // Default QueryId to return the pin's name
  1736. STDMETHODIMP
  1737. CBasePin::QueryId(
  1738.     LPWSTR * Id
  1739. )
  1740. {
  1741.     //  We're not going away because someone's got a pointer to us
  1742.     //  so there's no need to lock
  1743.     return AMGetWideString(Name(), Id);
  1744. }
  1745. /* Does this pin support this media type WARNING this interface function does
  1746.    not lock the main object as it is meant to be asynchronous by nature - if
  1747.    the media types you support depend on some internal state that is updated
  1748.    dynamically then you will need to implement locking in a derived class */
  1749. STDMETHODIMP
  1750. CBasePin::QueryAccept(
  1751.     const AM_MEDIA_TYPE *pmt
  1752. )
  1753. {
  1754.     CheckPointer(pmt,E_POINTER);
  1755.     ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
  1756.     /* The CheckMediaType method is valid to return error codes if the media
  1757.        type is horrible, an example might be E_INVALIDARG. What we do here
  1758.        is map all the error codes into either S_OK or S_FALSE regardless */
  1759.     HRESULT hr = CheckMediaType((CMediaType*)pmt);
  1760.     if (FAILED(hr)) {
  1761.         return S_FALSE;
  1762.     }
  1763.     // note that the only defined success codes should be S_OK and S_FALSE...
  1764.     return hr;
  1765. }
  1766. /* This can be called to return an enumerator for the pin's list of preferred
  1767.    media types. An input pin is not obliged to have any preferred formats
  1768.    although it can do. For example, the window renderer has a preferred type
  1769.    which describes a video image that matches the current window size. All
  1770.    output pins should expose at least one preferred format otherwise it is
  1771.    possible that neither pin has any types and so no connection is possible */
  1772. STDMETHODIMP
  1773. CBasePin::EnumMediaTypes(
  1774.     IEnumMediaTypes **ppEnum
  1775. )
  1776. {
  1777.     CheckPointer(ppEnum,E_POINTER);
  1778.     ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
  1779.     /* Create a new ref counted enumerator */
  1780.     *ppEnum = new CEnumMediaTypes(this,
  1781.                               NULL);
  1782.     if (*ppEnum == NULL) {
  1783.         return E_OUTOFMEMORY;
  1784.     }
  1785.     return NOERROR;
  1786. }
  1787. /* This is a virtual function that returns a media type corresponding with
  1788.    place iPosition in the list. This base class simply returns an error as
  1789.    we support no media types by default but derived classes should override */
  1790. HRESULT CBasePin::GetMediaType(int iPosition, CMediaType *pMediaType)
  1791. {
  1792.     UNREFERENCED_PARAMETER(iPosition);
  1793.     UNREFERENCED_PARAMETER(pMediaType);
  1794.     return E_UNEXPECTED;
  1795. }
  1796. /* This is a virtual function that returns the current media type version.
  1797.    The base class initialises the media type enumerators with the value 1
  1798.    By default we always returns that same value. A Derived class may change
  1799.    the list of media types available and after doing so it should increment
  1800.    the version either in a method derived from this, or more simply by just
  1801.    incrementing the m_TypeVersion base pin variable. The type enumerators
  1802.    call this when they want to see if their enumerations are out of date */
  1803. LONG CBasePin::GetMediaTypeVersion()
  1804. {
  1805.     return m_TypeVersion;
  1806. }
  1807. /* Increment the cookie representing the current media type version */
  1808. void CBasePin::IncrementTypeVersion()
  1809. {
  1810.     InterlockedIncrement(&m_TypeVersion);
  1811. }
  1812. /* Called by IMediaFilter implementation when the state changes from Stopped
  1813.    to either paused or running and in derived classes could do things like
  1814.    commit memory and grab hardware resource (the default is to do nothing) */
  1815. HRESULT
  1816. CBasePin::Active(void)
  1817. {
  1818.     return NOERROR;
  1819. }
  1820. /* Called by IMediaFilter implementation when the state changes from
  1821.    to either paused to running and in derived classes could do things like
  1822.    commit memory and grab hardware resource (the default is to do nothing) */
  1823. HRESULT
  1824. CBasePin::Run(REFERENCE_TIME tStart)
  1825. {
  1826.     UNREFERENCED_PARAMETER(tStart);
  1827.     return NOERROR;
  1828. }
  1829. /* Also called by the IMediaFilter implementation when the state changes to
  1830.    Stopped at which point you should decommit allocators and free hardware
  1831.    resources you grabbed in the Active call (default is also to do nothing) */
  1832. HRESULT
  1833. CBasePin::Inactive(void)
  1834. {
  1835.     m_bRunTimeError = FALSE;
  1836.     return NOERROR;
  1837. }
  1838. // Called when no more data will arrive
  1839. STDMETHODIMP
  1840. CBasePin::EndOfStream(void)
  1841. {
  1842.     return S_OK;
  1843. }
  1844. STDMETHODIMP
  1845. CBasePin::SetSink(IQualityControl * piqc)
  1846. {
  1847.     CAutoLock cObjectLock(m_pLock);
  1848.     if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl));
  1849.     m_pQSink = piqc;
  1850.     return NOERROR;
  1851. } // SetSink
  1852. STDMETHODIMP
  1853. CBasePin::Notify(IBaseFilter * pSender, Quality q)
  1854. {
  1855.     UNREFERENCED_PARAMETER(q);
  1856.     UNREFERENCED_PARAMETER(pSender);
  1857.     DbgBreak("IQualityControl::Notify not over-ridden from CBasePin.  (IGNORE is OK)");
  1858.     return E_NOTIMPL;
  1859. } //Notify
  1860. // NewSegment notifies of the start/stop/rate applying to the data
  1861. // about to be received. Default implementation records data and
  1862. // returns S_OK.
  1863. // Override this to pass downstream.
  1864. STDMETHODIMP
  1865. CBasePin::NewSegment(
  1866.                 REFERENCE_TIME tStart,
  1867.                 REFERENCE_TIME tStop,
  1868.                 double dRate)
  1869. {
  1870.     m_tStart = tStart;
  1871.     m_tStop = tStop;
  1872.     m_dRate = dRate;
  1873.     return S_OK;
  1874. }
  1875. //=====================================================================
  1876. //=====================================================================
  1877. // Implements CBaseOutputPin
  1878. //=====================================================================
  1879. //=====================================================================
  1880. CBaseOutputPin::CBaseOutputPin(TCHAR *pObjectName,
  1881.                    CBaseFilter *pFilter,
  1882.                    CCritSec *pLock,
  1883.                    HRESULT *phr,
  1884.                    LPCWSTR pName) :
  1885.     CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
  1886.     m_pAllocator(NULL),
  1887.     m_pInputPin(NULL)
  1888. {
  1889.     ASSERT(pFilter);
  1890. }
  1891. #ifdef UNICODE
  1892. CBaseOutputPin::CBaseOutputPin(CHAR *pObjectName,
  1893.                    CBaseFilter *pFilter,
  1894.                    CCritSec *pLock,
  1895.                    HRESULT *phr,
  1896.                    LPCWSTR pName) :
  1897.     CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
  1898.     m_pAllocator(NULL),
  1899.     m_pInputPin(NULL)
  1900. {
  1901.     ASSERT(pFilter);
  1902. }
  1903. #endif
  1904. /*   This is called after a media type has been proposed
  1905.      Try to complete the connection by agreeing the allocator
  1906. */
  1907. HRESULT
  1908. CBaseOutputPin::CompleteConnect(IPin *pReceivePin)
  1909. {
  1910.     UNREFERENCED_PARAMETER(pReceivePin);
  1911.     return DecideAllocator(m_pInputPin, &m_pAllocator);
  1912. }
  1913. /* This method is called when the output pin is about to try and connect to
  1914.    an input pin. It is at this point that you should try and grab any extra
  1915.    interfaces that you need, in this case IMemInputPin. Because this is
  1916.    only called if we are not currently connected we do NOT need to call
  1917.    BreakConnect. This also makes it easier to derive classes from us as
  1918.    BreakConnect is only called when we actually have to break a connection
  1919.    (or a partly made connection) and not when we are checking a connection */
  1920. /* Overriden from CBasePin */
  1921. HRESULT
  1922. CBaseOutputPin::CheckConnect(IPin * pPin)
  1923. {
  1924.     HRESULT hr = CBasePin::CheckConnect(pPin);
  1925.     if (FAILED(hr)) {
  1926.     return hr;
  1927.     }
  1928.     // get an input pin and an allocator interface
  1929.     hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin);
  1930.     if (FAILED(hr)) {
  1931.         return hr;
  1932.     }
  1933.     return NOERROR;
  1934. }
  1935. /* Overriden from CBasePin */
  1936. HRESULT
  1937. CBaseOutputPin::BreakConnect()
  1938. {
  1939.     /* Release any allocator we hold */
  1940.     if (m_pAllocator) {
  1941.         // Always decommit the allocator because a downstream filter may or
  1942.         // may not decommit the connection's allocator.  A memory leak could
  1943.         // occur if the allocator is not decommited when a connection is broken.
  1944.         HRESULT hr = m_pAllocator->Decommit();
  1945.         if( FAILED( hr ) ) {
  1946.             return hr;
  1947.         }
  1948.         m_pAllocator->Release();
  1949.         m_pAllocator = NULL;
  1950.     }
  1951.     /* Release any input pin interface we hold */
  1952.     if (m_pInputPin) {
  1953.         m_pInputPin->Release();
  1954.         m_pInputPin = NULL;
  1955.     }
  1956.     return NOERROR;
  1957. }
  1958. /* This is called when the input pin didn't give us a valid allocator */
  1959. HRESULT
  1960. CBaseOutputPin::InitAllocator(IMemAllocator **ppAlloc)
  1961. {
  1962.     return CreateMemoryAllocator(ppAlloc);
  1963. }
  1964. /* Decide on an allocator, override this if you want to use your own allocator
  1965.    Override DecideBufferSize to call SetProperties. If the input pin fails
  1966.    the GetAllocator call then this will construct a CMemAllocator and call
  1967.    DecideBufferSize on that, and if that fails then we are completely hosed.
  1968.    If the you succeed the DecideBufferSize call, we will notify the input
  1969.    pin of the selected allocator. NOTE this is called during Connect() which
  1970.    therefore looks after grabbing and locking the object's critical section */
  1971. // We query the input pin for its requested properties and pass this to
  1972. // DecideBufferSize to allow it to fulfill requests that it is happy
  1973. // with (eg most people don't care about alignment and are thus happy to
  1974. // use the downstream pin's alignment request).
  1975. HRESULT
  1976. CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
  1977. {
  1978.     HRESULT hr = NOERROR;
  1979.     *ppAlloc = NULL;
  1980.     // get downstream prop request
  1981.     // the derived class may modify this in DecideBufferSize, but
  1982.     // we assume that he will consistently modify it the same way,
  1983.     // so we only get it once
  1984.     ALLOCATOR_PROPERTIES prop;
  1985.     ZeroMemory(&prop, sizeof(prop));
  1986.     // whatever he returns, we assume prop is either all zeros
  1987.     // or he has filled it out.
  1988.     pPin->GetAllocatorRequirements(&prop);
  1989.     // if he doesn't care about alignment, then set it to 1
  1990.     if (prop.cbAlign == 0) {
  1991.         prop.cbAlign = 1;
  1992.     }
  1993.     /* Try the allocator provided by the input pin */
  1994.     hr = pPin->GetAllocator(ppAlloc);
  1995.     if (SUCCEEDED(hr)) {
  1996.         hr = DecideBufferSize(*ppAlloc, &prop);
  1997.         if (SUCCEEDED(hr)) {
  1998.             hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
  1999.             if (SUCCEEDED(hr)) {
  2000.                 return NOERROR;
  2001.             }
  2002.         }
  2003.     }
  2004.     /* If the GetAllocator failed we may not have an interface */
  2005.     if (*ppAlloc) {
  2006.         (*ppAlloc)->Release();
  2007.         *ppAlloc = NULL;
  2008.     }
  2009.     /* Try the output pin's allocator by the same method */
  2010.     hr = InitAllocator(ppAlloc);
  2011.     if (SUCCEEDED(hr)) {
  2012.         // note - the properties passed here are in the same
  2013.         // structure as above and may have been modified by
  2014.         // the previous call to DecideBufferSize
  2015.         hr = DecideBufferSize(*ppAlloc, &prop);
  2016.         if (SUCCEEDED(hr)) {
  2017.             hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
  2018.             if (SUCCEEDED(hr)) {
  2019.                 return NOERROR;
  2020.             }
  2021.         }
  2022.     }
  2023.     /* Likewise we may not have an interface to release */
  2024.     if (*ppAlloc) {
  2025.         (*ppAlloc)->Release();
  2026.         *ppAlloc = NULL;
  2027.     }
  2028.     return hr;
  2029. }
  2030. /* This returns an empty sample buffer from the allocator WARNING the same
  2031.    dangers and restrictions apply here as described below for Deliver() */
  2032. HRESULT
  2033. CBaseOutputPin::GetDeliveryBuffer(IMediaSample ** ppSample,
  2034.                                   REFERENCE_TIME * pStartTime,
  2035.                                   REFERENCE_TIME * pEndTime,
  2036.                                   DWORD dwFlags)
  2037. {
  2038.     if (m_pAllocator != NULL) {
  2039.         return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags);
  2040.     } else {
  2041.         return E_NOINTERFACE;
  2042.     }
  2043. }
  2044. /* Deliver a filled-in sample to the connected input pin. NOTE the object must
  2045.    have locked itself before calling us otherwise we may get halfway through
  2046.    executing this method only to find the filter graph has got in and
  2047.    disconnected us from the input pin. If the filter has no worker threads
  2048.    then the lock is best applied on Receive(), otherwise it should be done
  2049.    when the worker thread is ready to deliver. There is a wee snag to worker
  2050.    threads that this shows up. The worker thread must lock the object when
  2051.    it is ready to deliver a sample, but it may have to wait until a state
  2052.    change has completed, but that may never complete because the state change
  2053.    is waiting for the worker thread to complete. The way to handle this is for
  2054.    the state change code to grab the critical section, then set an abort event
  2055.    for the worker thread, then release the critical section and wait for the
  2056.    worker thread to see the event we set and then signal that it has finished
  2057.    (with another event). At which point the state change code can complete */
  2058. // note (if you've still got any breath left after reading that) that you
  2059. // need to release the sample yourself after this call. if the connected
  2060. // input pin needs to hold onto the sample beyond the call, it will addref
  2061. // the sample itself.
  2062. // of course you must release this one and call GetDeliveryBuffer for the
  2063. // next. You cannot reuse it directly.