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

P2P编程

开发平台:

Visual C++

  1. HRESULT
  2. CBaseOutputPin::Deliver(IMediaSample * pSample)
  3. {
  4.     if (m_pInputPin == NULL) {
  5.         return VFW_E_NOT_CONNECTED;
  6.     }
  7.     return m_pInputPin->Receive(pSample);
  8. }
  9. // called from elsewhere in our filter to pass EOS downstream to
  10. // our connected input pin
  11. HRESULT
  12. CBaseOutputPin::DeliverEndOfStream(void)
  13. {
  14.     // remember this is on IPin not IMemInputPin
  15.     if (m_Connected == NULL) {
  16.         return VFW_E_NOT_CONNECTED;
  17.     }
  18.     return m_Connected->EndOfStream();
  19. }
  20. /* Commit the allocator's memory, this is called through IMediaFilter
  21.    which is responsible for locking the object before calling us */
  22. HRESULT
  23. CBaseOutputPin::Active(void)
  24. {
  25.     if (m_pAllocator == NULL) {
  26.         return VFW_E_NO_ALLOCATOR;
  27.     }
  28.     return m_pAllocator->Commit();
  29. }
  30. /* Free up or unprepare allocator's memory, this is called through
  31.    IMediaFilter which is responsible for locking the object first */
  32. HRESULT
  33. CBaseOutputPin::Inactive(void)
  34. {
  35.     m_bRunTimeError = FALSE;
  36.     if (m_pAllocator == NULL) {
  37.         return VFW_E_NO_ALLOCATOR;
  38.     }
  39.     return m_pAllocator->Decommit();
  40. }
  41. // we have a default handling of EndOfStream which is to return
  42. // an error, since this should be called on input pins only
  43. STDMETHODIMP
  44. CBaseOutputPin::EndOfStream(void)
  45. {
  46.     return E_UNEXPECTED;
  47. }
  48. // BeginFlush should be called on input pins only
  49. STDMETHODIMP
  50. CBaseOutputPin::BeginFlush(void)
  51. {
  52.     return E_UNEXPECTED;
  53. }
  54. // EndFlush should be called on input pins only
  55. STDMETHODIMP
  56. CBaseOutputPin::EndFlush(void)
  57. {
  58.     return E_UNEXPECTED;
  59. }
  60. // call BeginFlush on the connected input pin
  61. HRESULT
  62. CBaseOutputPin::DeliverBeginFlush(void)
  63. {
  64.     // remember this is on IPin not IMemInputPin
  65.     if (m_Connected == NULL) {
  66.         return VFW_E_NOT_CONNECTED;
  67.     }
  68.     return m_Connected->BeginFlush();
  69. }
  70. // call EndFlush on the connected input pin
  71. HRESULT
  72. CBaseOutputPin::DeliverEndFlush(void)
  73. {
  74.     // remember this is on IPin not IMemInputPin
  75.     if (m_Connected == NULL) {
  76.         return VFW_E_NOT_CONNECTED;
  77.     }
  78.     return m_Connected->EndFlush();
  79. }
  80. // deliver NewSegment to connected pin
  81. HRESULT
  82. CBaseOutputPin::DeliverNewSegment(
  83.     REFERENCE_TIME tStart,
  84.     REFERENCE_TIME tStop,
  85.     double dRate)
  86. {
  87.     if (m_Connected == NULL) {
  88.         return VFW_E_NOT_CONNECTED;
  89.     }
  90.     return m_Connected->NewSegment(tStart, tStop, dRate);
  91. }
  92. //=====================================================================
  93. //=====================================================================
  94. // Implements CBaseInputPin
  95. //=====================================================================
  96. //=====================================================================
  97. /* Constructor creates a default allocator object */
  98. CBaseInputPin::CBaseInputPin(TCHAR *pObjectName,
  99.                  CBaseFilter *pFilter,
  100.                  CCritSec *pLock,
  101.                  HRESULT *phr,
  102.                  LPCWSTR pPinName) :
  103.     CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
  104.     m_pAllocator(NULL),
  105.     m_bReadOnly(FALSE),
  106.     m_bFlushing(FALSE)
  107. {
  108.     ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
  109. }
  110. #ifdef UNICODE
  111. CBaseInputPin::CBaseInputPin(CHAR *pObjectName,
  112.                  CBaseFilter *pFilter,
  113.                  CCritSec *pLock,
  114.                  HRESULT *phr,
  115.                  LPCWSTR pPinName) :
  116.     CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
  117.     m_pAllocator(NULL),
  118.     m_bReadOnly(FALSE),
  119.     m_bFlushing(FALSE)
  120. {
  121.     ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
  122. }
  123. #endif
  124. /* Destructor releases it's reference count on the default allocator */
  125. CBaseInputPin::~CBaseInputPin()
  126. {
  127.     if (m_pAllocator != NULL) {
  128.     m_pAllocator->Release();
  129.     m_pAllocator = NULL;
  130.     }
  131. }
  132. // override this to publicise our interfaces
  133. STDMETHODIMP
  134. CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  135. {
  136.     /* Do we know about this interface */
  137.     if (riid == IID_IMemInputPin) {
  138.         return GetInterface((IMemInputPin *) this, ppv);
  139.     } else {
  140.         return CBasePin::NonDelegatingQueryInterface(riid, ppv);
  141.     }
  142. }
  143. /* Return the allocator interface that this input pin would like the output
  144.    pin to use. NOTE subsequent calls to GetAllocator should all return an
  145.    interface onto the SAME object so we create one object at the start
  146.    Note:
  147.        The allocator is Release()'d on disconnect and replaced on
  148.        NotifyAllocator().
  149.    Override this to provide your own allocator.
  150. */
  151. STDMETHODIMP
  152. CBaseInputPin::GetAllocator(
  153.     IMemAllocator **ppAllocator)
  154. {
  155.     CheckPointer(ppAllocator,E_POINTER);
  156.     ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
  157.     CAutoLock cObjectLock(m_pLock);
  158.     if (m_pAllocator == NULL) {
  159.         HRESULT hr = CreateMemoryAllocator(&m_pAllocator);
  160.         if (FAILED(hr)) {
  161.             return hr;
  162.         }
  163.     }
  164.     ASSERT(m_pAllocator != NULL);
  165.     *ppAllocator = m_pAllocator;
  166.     m_pAllocator->AddRef();
  167.     return NOERROR;
  168. }
  169. /* Tell the input pin which allocator the output pin is actually going to use
  170.    Override this if you care - NOTE the locking we do both here and also in
  171.    GetAllocator is unnecessary but derived classes that do something useful
  172.    will undoubtedly have to lock the object so this might help remind people */
  173. STDMETHODIMP
  174. CBaseInputPin::NotifyAllocator(
  175.     IMemAllocator * pAllocator,
  176.     BOOL bReadOnly)
  177. {
  178.     CheckPointer(pAllocator,E_POINTER);
  179.     ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
  180.     CAutoLock cObjectLock(m_pLock);
  181.     IMemAllocator *pOldAllocator = m_pAllocator;
  182.     pAllocator->AddRef();
  183.     m_pAllocator = pAllocator;
  184.     if (pOldAllocator != NULL) {
  185.         pOldAllocator->Release();
  186.     }
  187.     // the readonly flag indicates whether samples from this allocator should
  188.     // be regarded as readonly - if true, then inplace transforms will not be
  189.     // allowed.
  190.     m_bReadOnly = (BYTE)bReadOnly;
  191.     return NOERROR;
  192. }
  193. HRESULT
  194. CBaseInputPin::BreakConnect()
  195. {
  196.     /* We don't need our allocator any more */
  197.     if (m_pAllocator) {
  198.         // Always decommit the allocator because a downstream filter may or
  199.         // may not decommit the connection's allocator.  A memory leak could
  200.         // occur if the allocator is not decommited when a pin is disconnected.
  201.         HRESULT hr = m_pAllocator->Decommit();
  202.         if( FAILED( hr ) ) {
  203.             return hr;
  204.         }
  205.         m_pAllocator->Release();
  206.         m_pAllocator = NULL;
  207.     }
  208.     return S_OK;
  209. }
  210. /* Do something with this media sample - this base class checks to see if the
  211.    format has changed with this media sample and if so checks that the filter
  212.    will accept it, generating a run time error if not. Once we have raised a
  213.    run time error we set a flag so that no more samples will be accepted
  214.    It is important that any filter should override this method and implement
  215.    synchronization so that samples are not processed when the pin is
  216.    disconnected etc
  217. */
  218. STDMETHODIMP
  219. CBaseInputPin::Receive(IMediaSample *pSample)
  220. {
  221.     CheckPointer(pSample,E_POINTER);
  222.     ValidateReadPtr(pSample,sizeof(IMediaSample));
  223.     ASSERT(pSample);
  224.     HRESULT hr = CheckStreaming();
  225.     if (S_OK != hr) {
  226.         return hr;
  227.     }
  228.     /* Check for IMediaSample2 */
  229.     IMediaSample2 *pSample2;
  230.     if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
  231.         hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps);
  232.         pSample2->Release();
  233.         if (FAILED(hr)) {
  234.             return hr;
  235.         }
  236.     } else {
  237.         /*  Get the properties the hard way */
  238.         m_SampleProps.cbData = sizeof(m_SampleProps);
  239.         m_SampleProps.dwTypeSpecificFlags = 0;
  240.         m_SampleProps.dwStreamId = AM_STREAM_MEDIA;
  241.         m_SampleProps.dwSampleFlags = 0;
  242.         if (S_OK == pSample->IsDiscontinuity()) {
  243.             m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
  244.         }
  245.         if (S_OK == pSample->IsPreroll()) {
  246.             m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL;
  247.         }
  248.         if (S_OK == pSample->IsSyncPoint()) {
  249.             m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
  250.         }
  251.         if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart,
  252.                                        &m_SampleProps.tStop))) {
  253.             m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID |
  254.                                            AM_SAMPLE_STOPVALID;
  255.         }
  256.         if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) {
  257.             m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
  258.         }
  259.         pSample->GetPointer(&m_SampleProps.pbBuffer);
  260.         m_SampleProps.lActual = pSample->GetActualDataLength();
  261.         m_SampleProps.cbBuffer = pSample->GetSize();
  262.     }
  263.     /* Has the format changed in this sample */
  264.     if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) {
  265.         return NOERROR;
  266.     }
  267.     /* Check the derived class accepts this format */
  268.     /* This shouldn't fail as the source must call QueryAccept first */
  269.     hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType);
  270.     if (hr == NOERROR) {
  271.         return NOERROR;
  272.     }
  273.     /* Raise a runtime error if we fail the media type */
  274.     m_bRunTimeError = TRUE;
  275.     EndOfStream();
  276.     m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
  277.     return VFW_E_INVALIDMEDIATYPE;
  278. }
  279. /*  Receive multiple samples */
  280. STDMETHODIMP
  281. CBaseInputPin::ReceiveMultiple (
  282.     IMediaSample **pSamples,
  283.     long nSamples,
  284.     long *nSamplesProcessed)
  285. {
  286.     CheckPointer(pSamples,E_POINTER);
  287.     ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *));
  288.     HRESULT hr = S_OK;
  289.     *nSamplesProcessed = 0;
  290.     while (nSamples-- > 0) {
  291.          hr = Receive(pSamples[*nSamplesProcessed]);
  292.          /*  S_FALSE means don't send any more */
  293.          if (hr != S_OK) {
  294.              break;
  295.          }
  296.          (*nSamplesProcessed)++;
  297.     }
  298.     return hr;
  299. }
  300. /*  See if Receive() might block */
  301. STDMETHODIMP
  302. CBaseInputPin::ReceiveCanBlock()
  303. {
  304.     /*  Ask all the output pins if they block
  305.         If there are no output pin assume we do block
  306.     */
  307.     int cPins = m_pFilter->GetPinCount();
  308.     int cOutputPins = 0;
  309.     for (int c = 0; c < cPins; c++) {
  310.         CBasePin *pPin = m_pFilter->GetPin(c);
  311.         PIN_DIRECTION pd;
  312.         HRESULT hr = pPin->QueryDirection(&pd);
  313.         if (FAILED(hr)) {
  314.             return hr;
  315.         }
  316.         if (pd == PINDIR_OUTPUT) {
  317.             IPin *pConnected;
  318.             hr = pPin->ConnectedTo(&pConnected);
  319.             if (SUCCEEDED(hr)) {
  320.                 ASSERT(pConnected != NULL);
  321.                 cOutputPins++;
  322.                 IMemInputPin *pInputPin;
  323.                 hr = pConnected->QueryInterface(
  324.                                               IID_IMemInputPin,
  325.                                               (void **)&pInputPin);
  326.                 pConnected->Release();
  327.                 if (SUCCEEDED(hr)) {
  328.                     hr = pInputPin->ReceiveCanBlock();
  329.                     pInputPin->Release();
  330.                     if (hr != S_FALSE) {
  331.                         return S_OK;
  332.                     }
  333.                 } else {
  334.                     /*  There's a transport we don't understand here */
  335.                     return S_OK;
  336.                 }
  337.             }
  338.         }
  339.     }
  340.     return cOutputPins == 0 ? S_OK : S_FALSE;
  341. }
  342. // Default handling for BeginFlush - call at the beginning
  343. // of your implementation (makes sure that all Receive calls
  344. // fail). After calling this, you need to free any queued data
  345. // and then call downstream.
  346. STDMETHODIMP
  347. CBaseInputPin::BeginFlush(void)
  348. {
  349.     //  BeginFlush is NOT synchronized with streaming but is part of
  350.     //  a control action - hence we synchronize with the filter
  351.     CAutoLock lck(m_pLock);
  352.     // if we are already in mid-flush, this is probably a mistake
  353.     // though not harmful - try to pick it up for now so I can think about it
  354.     ASSERT(!m_bFlushing);
  355.     // first thing to do is ensure that no further Receive calls succeed
  356.     m_bFlushing = TRUE;
  357.     // now discard any data and call downstream - must do that
  358.     // in derived classes
  359.     return S_OK;
  360. }
  361. // default handling for EndFlush - call at end of your implementation
  362. // - before calling this, ensure that there is no queued data and no thread
  363. // pushing any more without a further receive, then call downstream,
  364. // then call this method to clear the m_bFlushing flag and re-enable
  365. // receives
  366. STDMETHODIMP
  367. CBaseInputPin::EndFlush(void)
  368. {
  369.     //  Endlush is NOT synchronized with streaming but is part of
  370.     //  a control action - hence we synchronize with the filter
  371.     CAutoLock lck(m_pLock);
  372.     // almost certainly a mistake if we are not in mid-flush
  373.     ASSERT(m_bFlushing);
  374.     // before calling, sync with pushing thread and ensure
  375.     // no more data is going downstream, then call EndFlush on
  376.     // downstream pins.
  377.     // now re-enable Receives
  378.     m_bFlushing = FALSE;
  379.     // No more errors
  380.     m_bRunTimeError = FALSE;
  381.     return S_OK;
  382. }
  383. STDMETHODIMP
  384. CBaseInputPin::Notify(IBaseFilter * pSender, Quality q)
  385. {
  386.     UNREFERENCED_PARAMETER(q);
  387.     CheckPointer(pSender,E_POINTER);
  388.     ValidateReadPtr(pSender,sizeof(IBaseFilter));
  389.     DbgBreak("IQuality::Notify called on an input pin");
  390.     return NOERROR;
  391. } // Notify
  392. /* Free up or unprepare allocator's memory, this is called through
  393.    IMediaFilter which is responsible for locking the object first */
  394. HRESULT
  395. CBaseInputPin::Inactive(void)
  396. {
  397.     m_bRunTimeError = FALSE;
  398.     if (m_pAllocator == NULL) {
  399.         return VFW_E_NO_ALLOCATOR;
  400.     }
  401.     m_bFlushing = FALSE;
  402.     return m_pAllocator->Decommit();
  403. }
  404. // what requirements do we have of the allocator - override if you want
  405. // to support other people's allocators but need a specific alignment
  406. // or prefix.
  407. STDMETHODIMP
  408. CBaseInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps)
  409. {
  410.     UNREFERENCED_PARAMETER(pProps);
  411.     return E_NOTIMPL;
  412. }
  413. //  Check if it's OK to process data
  414. //
  415. HRESULT
  416. CBaseInputPin::CheckStreaming()
  417. {
  418.     //  Shouldn't be able to get any data if we're not connected!
  419.     ASSERT(IsConnected());
  420.     //  Don't process stuff in Stopped state
  421.     if (IsStopped()) {
  422.         return VFW_E_WRONG_STATE;
  423.     }
  424.     if (m_bFlushing) {
  425.         return S_FALSE;
  426.     }
  427.     if (m_bRunTimeError) {
  428.         return VFW_E_RUNTIME_ERROR;
  429.     }
  430.     return S_OK;
  431. }
  432. // Pass on the Quality notification q to
  433. // a. Our QualityControl sink (if we have one) or else
  434. // b. to our upstream filter
  435. // and if that doesn't work, throw it away with a bad return code
  436. HRESULT
  437. CBaseInputPin::PassNotify(Quality& q)
  438. {
  439.     // We pass the message on, which means that we find the quality sink
  440.     // for our input pin and send it there
  441.     DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform")));
  442.     if (m_pQSink!=NULL) {
  443.         return m_pQSink->Notify(m_pFilter, q);
  444.     } else {
  445.         // no sink set, so pass it upstream
  446.         HRESULT hr;
  447.         IQualityControl * pIQC;
  448.         hr = VFW_E_NOT_FOUND;                   // default
  449.         if (m_Connected) {
  450.             m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
  451.             if (pIQC!=NULL) {
  452.                 hr = pIQC->Notify(m_pFilter, q);
  453.                 pIQC->Release();
  454.             }
  455.         }
  456.         return hr;
  457.     }
  458. } // PassNotify
  459. //=====================================================================
  460. //=====================================================================
  461. // Memory allocation class, implements CMediaSample
  462. //=====================================================================
  463. //=====================================================================
  464. /* NOTE The implementation of this class calls the CUnknown constructor with
  465.    a NULL outer unknown pointer. This has the effect of making us a self
  466.    contained class, ie any QueryInterface, AddRef or Release calls will be
  467.    routed to the class's NonDelegatingUnknown methods. You will typically
  468.    find that the classes that do this then override one or more of these
  469.    virtual functions to provide more specialised behaviour. A good example
  470.    of this is where a class wants to keep the QueryInterface internal but
  471.    still wants it's lifetime controlled by the external object */
  472. /* The last two parameters have default values of NULL and zero */
  473. CMediaSample::CMediaSample(TCHAR *pName,
  474.                CBaseAllocator *pAllocator,
  475.                HRESULT *phr,
  476.                LPBYTE pBuffer,
  477.                LONG length) :
  478.     m_pBuffer(pBuffer),             // Initialise the buffer
  479.     m_cbBuffer(length),             // And it's length
  480.     m_lActual(length),              // By default, actual = length
  481.     m_pMediaType(NULL),             // No media type change
  482.     m_dwFlags(0),                   // Nothing set
  483.     m_cRef(0),                      // 0 ref count
  484.     m_dwTypeSpecificFlags(0),       // Type specific flags
  485.     m_dwStreamId(AM_STREAM_MEDIA),  // Stream id
  486.     m_pAllocator(pAllocator)        // Allocator
  487. {
  488.     /* We must have an owner and it must also be derived from class
  489.        CBaseAllocator BUT we do not hold a reference count on it */
  490.     ASSERT(pAllocator);
  491. }
  492. #ifdef UNICODE
  493. CMediaSample::CMediaSample(CHAR *pName,
  494.                CBaseAllocator *pAllocator,
  495.                HRESULT *phr,
  496.                LPBYTE pBuffer,
  497.                LONG length) :
  498.     m_pBuffer(pBuffer),             // Initialise the buffer
  499.     m_cbBuffer(length),             // And it's length
  500.     m_lActual(length),              // By default, actual = length
  501.     m_pMediaType(NULL),             // No media type change
  502.     m_dwFlags(0),                   // Nothing set
  503.     m_cRef(0),                      // 0 ref count
  504.     m_dwTypeSpecificFlags(0),       // Type specific flags
  505.     m_dwStreamId(AM_STREAM_MEDIA),  // Stream id
  506.     m_pAllocator(pAllocator)        // Allocator
  507. {
  508.     /* We must have an owner and it must also be derived from class
  509.        CBaseAllocator BUT we do not hold a reference count on it */
  510.     ASSERT(pAllocator);
  511. }
  512. #endif
  513. /* Destructor deletes the media type memory */
  514. CMediaSample::~CMediaSample()
  515. {
  516.     if (m_pMediaType) {
  517.     DeleteMediaType(m_pMediaType);
  518.     }
  519. }
  520. /* Override this to publicise our interfaces */
  521. STDMETHODIMP
  522. CMediaSample::QueryInterface(REFIID riid, void **ppv)
  523. {
  524.     if (riid == IID_IMediaSample ||
  525.         riid == IID_IMediaSample2 ||
  526.         riid == IID_IUnknown) {
  527.         return GetInterface((IMediaSample *) this, ppv);
  528.     } else {
  529.         return E_NOINTERFACE;
  530.     }
  531. }
  532. STDMETHODIMP_(ULONG)
  533. CMediaSample::AddRef()
  534. {
  535.     return InterlockedIncrement(&m_cRef);
  536. }
  537. // --  CMediaSample lifetimes --
  538. //
  539. // On final release of this sample buffer it is not deleted but
  540. // returned to the freelist of the owning memory allocator
  541. //
  542. // The allocator may be waiting for the last buffer to be placed on the free
  543. // list in order to decommit all the memory, so the ReleaseBuffer() call may
  544. // result in this sample being deleted. We also need to hold a refcount on
  545. // the allocator to stop that going away until we have finished with this.
  546. // However, we cannot release the allocator before the ReleaseBuffer, as the
  547. // release may cause us to be deleted. Similarly we can't do it afterwards.
  548. //
  549. // Thus we must leave it to the allocator to hold an addref on our behalf.
  550. // When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer
  551. // is called, he releases himself, possibly causing us and him to be deleted.
  552. STDMETHODIMP_(ULONG)
  553. CMediaSample::Release()
  554. {
  555.     /* Decrement our own private reference count */
  556.     LONG lRef;
  557.     if (m_cRef == 1) {
  558.         lRef = 0;
  559.         m_cRef = 0;
  560.     } else {
  561.         lRef = InterlockedDecrement(&m_cRef);
  562.     }
  563.     ASSERT(lRef >= 0);
  564.     DbgLog((LOG_MEMORY,3,TEXT("    Unknown %X ref-- = %d"),
  565.         this, m_cRef));
  566.     /* Did we release our final reference count */
  567.     if (lRef == 0) {
  568.         /* Free all resources */
  569.         if (m_dwFlags & Sample_TypeChanged) {
  570.             SetMediaType(NULL);
  571.         }
  572.         ASSERT(m_pMediaType == NULL);
  573.         m_dwFlags = 0;
  574.         m_dwTypeSpecificFlags = 0;
  575.         m_dwStreamId = AM_STREAM_MEDIA;
  576.         /* This may cause us to be deleted */
  577.         // Our refcount is reliably 0 thus no-one will mess with us
  578.         m_pAllocator->ReleaseBuffer(this);
  579.     }
  580.     return (ULONG)lRef;
  581. }
  582. // set the buffer pointer and length. Used by allocators that
  583. // want variable sized pointers or pointers into already-read data.
  584. // This is only available through a CMediaSample* not an IMediaSample*
  585. // and so cannot be changed by clients.
  586. HRESULT
  587. CMediaSample::SetPointer(BYTE * ptr, LONG cBytes)
  588. {
  589.     m_pBuffer = ptr;            // new buffer area (could be null)
  590.     m_cbBuffer = cBytes;        // length of buffer
  591.     m_lActual = cBytes;         // length of data in buffer (assume full)
  592.     return S_OK;
  593. }
  594. // get me a read/write pointer to this buffer's memory. I will actually
  595. // want to use sizeUsed bytes.
  596. STDMETHODIMP
  597. CMediaSample::GetPointer(BYTE ** ppBuffer)
  598. {
  599.     ValidateReadWritePtr(ppBuffer,sizeof(BYTE *));
  600.     // creator must have set pointer either during
  601.     // constructor or by SetPointer
  602.     ASSERT(m_pBuffer);
  603.     *ppBuffer = m_pBuffer;
  604.     return NOERROR;
  605. }
  606. // return the size in bytes of this buffer
  607. STDMETHODIMP_(LONG)
  608. CMediaSample::GetSize(void)
  609. {
  610.     return m_cbBuffer;
  611. }
  612. // get the stream time at which this sample should start and finish.
  613. STDMETHODIMP
  614. CMediaSample::GetTime(
  615.     REFERENCE_TIME * pTimeStart,     // put time here
  616.     REFERENCE_TIME * pTimeEnd
  617. )
  618. {
  619.     ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME));
  620.     ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME));
  621.     if (!(m_dwFlags & Sample_StopValid)) {
  622.         if (!(m_dwFlags & Sample_TimeValid)) {
  623.             return VFW_E_SAMPLE_TIME_NOT_SET;
  624.         } else {
  625.             *pTimeStart = m_Start;
  626.             //  Make sure old stuff works
  627.             *pTimeEnd = m_Start + 1;
  628.             return VFW_S_NO_STOP_TIME;
  629.         }
  630.     }
  631.     *pTimeStart = m_Start;
  632.     *pTimeEnd = m_End;
  633.     return NOERROR;
  634. }
  635. // Set the stream time at which this sample should start and finish.
  636. // NULL pointers means the time is reset
  637. STDMETHODIMP
  638. CMediaSample::SetTime(
  639.     REFERENCE_TIME * pTimeStart,
  640.     REFERENCE_TIME * pTimeEnd
  641. )
  642. {
  643.     if (pTimeStart == NULL) {
  644.         ASSERT(pTimeEnd == NULL);
  645.         m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid);
  646.     } else {
  647.         if (pTimeEnd == NULL) {
  648.             m_Start = *pTimeStart;
  649.             m_dwFlags |= Sample_TimeValid;
  650.             m_dwFlags &= ~Sample_StopValid;
  651.         } else {
  652.             ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME));
  653.             ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME));
  654.             ASSERT(*pTimeEnd >= *pTimeStart);
  655.             m_Start = *pTimeStart;
  656.             m_End = *pTimeEnd;
  657.             m_dwFlags |= Sample_TimeValid | Sample_StopValid;
  658.         }
  659.     }
  660.     return NOERROR;
  661. }
  662. // get the media times (eg bytes) for this sample
  663. STDMETHODIMP
  664. CMediaSample::GetMediaTime(
  665.     LONGLONG * pTimeStart,
  666.     LONGLONG * pTimeEnd
  667. )
  668. {
  669.     ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG));
  670.     ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG));
  671.     if (!(m_dwFlags & Sample_MediaTimeValid)) {
  672.         return VFW_E_MEDIA_TIME_NOT_SET;
  673.     }
  674.     *pTimeStart = m_MediaStart;
  675.     *pTimeEnd = (m_MediaStart + m_MediaEnd);
  676.     return NOERROR;
  677. }
  678. // Set the media times for this sample
  679. STDMETHODIMP
  680. CMediaSample::SetMediaTime(
  681.     LONGLONG * pTimeStart,
  682.     LONGLONG * pTimeEnd
  683. )
  684. {
  685.     if (pTimeStart == NULL) {
  686.         ASSERT(pTimeEnd == NULL);
  687.         m_dwFlags &= ~Sample_MediaTimeValid;
  688.     } else {
  689.         ValidateReadPtr(pTimeStart,sizeof(LONGLONG));
  690.         ValidateReadPtr(pTimeEnd,sizeof(LONGLONG));
  691.         ASSERT(*pTimeEnd >= *pTimeStart);
  692.         m_MediaStart = *pTimeStart;
  693.         m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart);
  694.         m_dwFlags |= Sample_MediaTimeValid;
  695.     }
  696.     return NOERROR;
  697. }
  698. STDMETHODIMP
  699. CMediaSample::IsSyncPoint(void)
  700. {
  701.     if (m_dwFlags & Sample_SyncPoint) {
  702.         return S_OK;
  703.     } else {
  704.         return S_FALSE;
  705.     }
  706. }
  707. STDMETHODIMP
  708. CMediaSample::SetSyncPoint(BOOL bIsSyncPoint)
  709. {
  710.     if (bIsSyncPoint) {
  711.         m_dwFlags |= Sample_SyncPoint;
  712.     } else {
  713.         m_dwFlags &= ~Sample_SyncPoint;
  714.     }
  715.     return NOERROR;
  716. }
  717. // returns S_OK if there is a discontinuity in the data (this same is
  718. // not a continuation of the previous stream of data
  719. // - there has been a seek).
  720. STDMETHODIMP
  721. CMediaSample::IsDiscontinuity(void)
  722. {
  723.     if (m_dwFlags & Sample_Discontinuity) {
  724.         return S_OK;
  725.     } else {
  726.         return S_FALSE;
  727.     }
  728. }
  729. // set the discontinuity property - TRUE if this sample is not a
  730. // continuation, but a new sample after a seek.
  731. STDMETHODIMP
  732. CMediaSample::SetDiscontinuity(BOOL bDiscont)
  733. {
  734.     // should be TRUE or FALSE
  735.     if (bDiscont) {
  736.         m_dwFlags |= Sample_Discontinuity;
  737.     } else {
  738.         m_dwFlags &= ~Sample_Discontinuity;
  739.     }
  740.     return S_OK;
  741. }
  742. STDMETHODIMP
  743. CMediaSample::IsPreroll(void)
  744. {
  745.     if (m_dwFlags & Sample_Preroll) {
  746.         return S_OK;
  747.     } else {
  748.         return S_FALSE;
  749.     }
  750. }
  751. STDMETHODIMP
  752. CMediaSample::SetPreroll(BOOL bIsPreroll)
  753. {
  754.     if (bIsPreroll) {
  755.         m_dwFlags |= Sample_Preroll;
  756.     } else {
  757.         m_dwFlags &= ~Sample_Preroll;
  758.     }
  759.     return NOERROR;
  760. }
  761. STDMETHODIMP_(LONG)
  762. CMediaSample::GetActualDataLength(void)
  763. {
  764.     return m_lActual;
  765. }
  766. STDMETHODIMP
  767. CMediaSample::SetActualDataLength(LONG lActual)
  768. {
  769.     if (lActual > m_cbBuffer) {
  770.         ASSERT(lActual <= GetSize());
  771.         return VFW_E_BUFFER_OVERFLOW;
  772.     }
  773.     m_lActual = lActual;
  774.     return NOERROR;
  775. }
  776. /* These allow for limited format changes in band */
  777. STDMETHODIMP
  778. CMediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType)
  779. {
  780.     ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *));
  781.     ASSERT(ppMediaType);
  782.     /* Do we have a new media type for them */
  783.     if (!(m_dwFlags & Sample_TypeChanged)) {
  784.         ASSERT(m_pMediaType == NULL);
  785.         *ppMediaType = NULL;
  786.         return S_FALSE;
  787.     }
  788.     ASSERT(m_pMediaType);
  789.     /* Create a copy of our media type */
  790.     *ppMediaType = CreateMediaType(m_pMediaType);
  791.     if (*ppMediaType == NULL) {
  792.         return E_OUTOFMEMORY;
  793.     }
  794.     return NOERROR;
  795. }
  796. /* Mark this sample as having a different format type */
  797. STDMETHODIMP
  798. CMediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType)
  799. {
  800.     /* Delete the current media type */
  801.     if (m_pMediaType) {
  802.         DeleteMediaType(m_pMediaType);
  803.         m_pMediaType = NULL;
  804.     }
  805.     /* Mechanism for resetting the format type */
  806.     if (pMediaType == NULL) {
  807.         m_dwFlags &= ~Sample_TypeChanged;
  808.         return NOERROR;
  809.     }
  810.     ASSERT(pMediaType);
  811.     ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE));
  812.     /* Take a copy of the media type */
  813.     m_pMediaType = CreateMediaType(pMediaType);
  814.     if (m_pMediaType == NULL) {
  815.         m_dwFlags &= ~Sample_TypeChanged;
  816.         return E_OUTOFMEMORY;
  817.     }
  818.     m_dwFlags |= Sample_TypeChanged;
  819.     return NOERROR;
  820. }
  821. // Set and get properties (IMediaSample2)
  822. STDMETHODIMP CMediaSample::GetProperties(
  823.     DWORD cbProperties,
  824.     BYTE * pbProperties
  825. )
  826. {
  827.     if (0 != cbProperties) {
  828.         CheckPointer(pbProperties, E_POINTER);
  829.         //  Return generic stuff up to the length
  830.         AM_SAMPLE2_PROPERTIES Props;
  831.         Props.cbData     = (DWORD) (min(cbProperties, sizeof(Props)));
  832.         Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid;
  833.         Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags;
  834.         Props.pbBuffer   = m_pBuffer;
  835.         Props.cbBuffer   = m_cbBuffer;
  836.         Props.lActual    = m_lActual;
  837.         Props.tStart     = m_Start;
  838.         Props.tStop      = m_End;
  839.         Props.dwStreamId = m_dwStreamId;
  840.         if (m_dwFlags & AM_SAMPLE_TYPECHANGED) {
  841.             Props.pMediaType = m_pMediaType;
  842.         } else {
  843.             Props.pMediaType = NULL;
  844.         }
  845.         CopyMemory(pbProperties, &Props, Props.cbData);
  846.     }
  847.     return S_OK;
  848. }
  849. #define CONTAINS_FIELD(type, field, offset) 
  850.     ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset)
  851. HRESULT CMediaSample::SetProperties(
  852.     DWORD cbProperties,
  853.     const BYTE * pbProperties
  854. )
  855. {
  856.     /*  Generic properties */
  857.     AM_MEDIA_TYPE *pMediaType = NULL;
  858.     if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) {
  859.         CheckPointer(pbProperties, E_POINTER);
  860.         AM_SAMPLE2_PROPERTIES *pProps =
  861.             (AM_SAMPLE2_PROPERTIES *)pbProperties;
  862.         /*  Don't use more data than is actually there */
  863.         if (pProps->cbData < cbProperties) {
  864.             cbProperties = pProps->cbData;
  865.         }
  866.         /*  We only handle IMediaSample2 */
  867.         if (cbProperties > sizeof(*pProps) ||
  868.             pProps->cbData > sizeof(*pProps)) {
  869.             return E_INVALIDARG;
  870.         }
  871.         /*  Do checks first, the assignments (for backout) */
  872.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
  873.             /*  Check the flags */
  874.             if (pProps->dwSampleFlags &
  875.                     (~Sample_ValidFlags | Sample_MediaTimeValid)) {
  876.                 return E_INVALIDARG;
  877.             }
  878.             /*  Check a flag isn't being set for a property
  879.                 not being provided
  880.             */
  881.             if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) &&
  882.                  !(m_dwFlags & AM_SAMPLE_TIMEVALID) &&
  883.                  !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
  884.                  return E_INVALIDARG;
  885.             }
  886.         }
  887.         /*  NB - can't SET the pointer or size */
  888.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) {
  889.             /*  Check pbBuffer */
  890.             if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) {
  891.                 return E_INVALIDARG;
  892.             }
  893.         }
  894.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) {
  895.             /*  Check cbBuffer */
  896.             if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) {
  897.                 return E_INVALIDARG;
  898.             }
  899.         }
  900.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) &&
  901.             CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
  902.             /*  Check lActual */
  903.             if (pProps->cbBuffer < pProps->lActual) {
  904.                 return E_INVALIDARG;
  905.             }
  906.         }
  907.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
  908.             /*  Check pMediaType */
  909.             if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
  910.                 CheckPointer(pProps->pMediaType, E_POINTER);
  911.                 pMediaType = CreateMediaType(pProps->pMediaType);
  912.                 if (pMediaType == NULL) {
  913.                     return E_OUTOFMEMORY;
  914.                 }
  915.             }
  916.         }
  917.         /*  Now do the assignments */
  918.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) {
  919.             m_dwStreamId = pProps->dwStreamId;
  920.         }
  921.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
  922.             /*  Set the flags */
  923.             m_dwFlags = pProps->dwSampleFlags |
  924.                                 (m_dwFlags & Sample_MediaTimeValid);
  925.             m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
  926.         } else {
  927.             if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) {
  928.                 m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
  929.             }
  930.         }
  931.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
  932.             /*  Set lActual */
  933.             m_lActual = pProps->lActual;
  934.         }
  935.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
  936.             /*  Set the times */
  937.             m_End   = pProps->tStop;
  938.         }
  939.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) {
  940.             /*  Set the times */
  941.             m_Start = pProps->tStart;
  942.         }
  943.         if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
  944.             /*  Set pMediaType */
  945.             if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
  946.                 if (m_pMediaType != NULL) {
  947.                     DeleteMediaType(m_pMediaType);
  948.                 }
  949.                 m_pMediaType = pMediaType;
  950.             }
  951.         }
  952.         /*  Fix up the type changed flag to correctly reflect the current state
  953.             If, for instance the input contained no type change but the
  954.             output does then if we don't do this we'd lose the
  955.             output media type.
  956.         */
  957.         if (m_pMediaType) {
  958.             m_dwFlags |= Sample_TypeChanged;
  959.         } else {
  960.             m_dwFlags &= ~Sample_TypeChanged;
  961.         }
  962.     }
  963.     return S_OK;
  964. }
  965. //
  966. // The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(),
  967. // IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the
  968. // connected input pin.  The application thread calls Block().  The
  969. // following class members can only be called by the streaming thread.
  970. //
  971. //    Deliver()
  972. //    DeliverNewSegment()
  973. //    StartUsingOutputPin()
  974. //    StopUsingOutputPin()
  975. //    ChangeOutputFormat()
  976. //    ChangeMediaType()
  977. //    DynamicReconnect()
  978. //
  979. // The following class members can only be called by the application thread.
  980. //
  981. //    Block()
  982. //    SynchronousBlockOutputPin()
  983. //    AsynchronousBlockOutputPin()
  984. //
  985. CDynamicOutputPin::CDynamicOutputPin(
  986.     TCHAR *pObjectName,
  987.     CBaseFilter *pFilter,
  988.     CCritSec *pLock,
  989.     HRESULT *phr,
  990.     LPCWSTR pName) :
  991.         CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
  992.         m_hStopEvent(NULL),
  993.         m_pGraphConfig(NULL),
  994.         m_bPinUsesReadOnlyAllocator(FALSE),
  995.         m_BlockState(NOT_BLOCKED),
  996.         m_hUnblockOutputPinEvent(NULL),
  997.         m_hNotifyCallerPinBlockedEvent(NULL),
  998.         m_dwBlockCallerThreadID(0),
  999.         m_dwNumOutstandingOutputPinUsers(0)
  1000. {
  1001.     HRESULT hr = Initialize();
  1002.     if( FAILED( hr ) ) {
  1003.         *phr = hr;
  1004.         return;
  1005.     }
  1006. }
  1007. #ifdef UNICODE
  1008. CDynamicOutputPin::CDynamicOutputPin(
  1009.     CHAR *pObjectName,
  1010.     CBaseFilter *pFilter,
  1011.     CCritSec *pLock,
  1012.     HRESULT *phr,
  1013.     LPCWSTR pName) :
  1014.         CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
  1015.         m_hStopEvent(NULL),
  1016.         m_pGraphConfig(NULL),
  1017.         m_bPinUsesReadOnlyAllocator(FALSE),
  1018.         m_BlockState(NOT_BLOCKED),
  1019.         m_hUnblockOutputPinEvent(NULL),
  1020.         m_hNotifyCallerPinBlockedEvent(NULL),
  1021.         m_dwBlockCallerThreadID(0),
  1022.         m_dwNumOutstandingOutputPinUsers(0)
  1023. {
  1024.     HRESULT hr = Initialize();
  1025.     if( FAILED( hr ) ) {
  1026.         *phr = hr;
  1027.         return;
  1028.     }
  1029. }
  1030. #endif
  1031. CDynamicOutputPin::~CDynamicOutputPin()
  1032. {
  1033.     if(NULL != m_hUnblockOutputPinEvent) {
  1034.         // This call should not fail because we have access to m_hUnblockOutputPinEvent
  1035.         // and m_hUnblockOutputPinEvent is a valid event.
  1036.         EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent));
  1037.     }
  1038.     if(NULL != m_hNotifyCallerPinBlockedEvent) {
  1039.         // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent
  1040.         // and m_hNotifyCallerPinBlockedEvent is a valid event.
  1041.         EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
  1042.     }
  1043. }
  1044. HRESULT CDynamicOutputPin::Initialize(void)
  1045. {
  1046.     m_hUnblockOutputPinEvent = ::CreateEvent( NULL,   // The event will have the default security descriptor.
  1047.                                               TRUE,   // This is a manual reset event.
  1048.                                               TRUE,   // The event is initially signaled.
  1049.                                               NULL ); // The event is not named.
  1050.     // CreateEvent() returns NULL if an error occurs.
  1051.     if(NULL == m_hUnblockOutputPinEvent) {
  1052.         return AmGetLastErrorToHResult();
  1053.     }
  1054.     //  Set flag to say we can reconnect while streaming.
  1055.     SetReconnectWhenActive(true);
  1056.     return S_OK;
  1057. }
  1058. STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  1059. {
  1060.     if(riid == IID_IPinFlowControl) {
  1061.         return GetInterface(static_cast<IPinFlowControl*>(this), ppv);
  1062.     } else {
  1063.         return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
  1064.     }
  1065. }
  1066. STDMETHODIMP CDynamicOutputPin::Disconnect(void)
  1067. {
  1068.     CAutoLock cObjectLock(m_pLock);
  1069.     return DisconnectInternal();
  1070. }
  1071. STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent)
  1072. {
  1073.     const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK;
  1074.     // Check for illegal flags.
  1075.     if(dwBlockFlags & ~VALID_FLAGS) {
  1076.         return E_INVALIDARG;
  1077.     }
  1078.     // Make sure the event is unsignaled.
  1079.     if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) {
  1080.         if( !::ResetEvent( hEvent ) ) {
  1081.             return AmGetLastErrorToHResult();
  1082.         }
  1083.     }
  1084.     // No flags are set if we are unblocking the output pin.
  1085.     if(0 == dwBlockFlags) {
  1086.         // This parameter should be NULL because unblock operations are always synchronous.
  1087.         // There is no need to notify the caller when the event is done.
  1088.         if(NULL != hEvent) {
  1089.             return E_INVALIDARG;
  1090.         }
  1091.     }
  1092.     #ifdef DEBUG
  1093.     AssertValid();
  1094.     #endif // DEBUG
  1095.     HRESULT hr;
  1096.     if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) {
  1097.         // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous.
  1098.         // If hEvent is not NULL, the block is asynchronous.
  1099.         if(NULL == hEvent) {
  1100.             hr = SynchronousBlockOutputPin();
  1101.         } else {
  1102.             hr = AsynchronousBlockOutputPin(hEvent);
  1103.         }
  1104.     } else {
  1105.         hr = UnblockOutputPin();
  1106.     }
  1107.     #ifdef DEBUG
  1108.     AssertValid();
  1109.     #endif // DEBUG
  1110.     if(FAILED(hr)) {
  1111.         return hr;
  1112.     }
  1113.     return S_OK;
  1114. }
  1115. HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void)
  1116. {
  1117.     HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL,   // The event will have the default security attributes.
  1118.                                                           FALSE,  // This is an automatic reset event.
  1119.                                                           FALSE,  // The event is initially unsignaled.
  1120.                                                           NULL ); // The event is not named.
  1121.     // CreateEvent() returns NULL if an error occurs.
  1122.     if(NULL == hNotifyCallerPinBlockedEvent) {
  1123.         return AmGetLastErrorToHResult();
  1124.     }
  1125.     HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent);
  1126.     if(FAILED(hr)) {
  1127.         // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
  1128.         // and hNotifyCallerPinBlockedEvent is a valid event.
  1129.         EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
  1130.         return hr;
  1131.     }
  1132.     hr = WaitEvent(hNotifyCallerPinBlockedEvent);
  1133.     // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
  1134.     // and hNotifyCallerPinBlockedEvent is a valid event.
  1135.     EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
  1136.     if(FAILED(hr)) {
  1137.         return hr;
  1138.     }
  1139.     return S_OK;
  1140. }
  1141. HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent)
  1142. {
  1143.     // This function holds the m_BlockStateLock because it uses
  1144.     // m_dwBlockCallerThreadID, m_BlockState and
  1145.     // m_hNotifyCallerPinBlockedEvent.
  1146.     CAutoLock alBlockStateLock(&m_BlockStateLock);
  1147.     if(NOT_BLOCKED != m_BlockState) {
  1148.         if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) {
  1149.             return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD;
  1150.         } else {
  1151.             return VFW_E_PIN_ALREADY_BLOCKED;
  1152.         }
  1153.     }
  1154.     BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(),
  1155.                                        hNotifyCallerPinBlockedEvent,
  1156.                                        ::GetCurrentProcess(),
  1157.                                        &m_hNotifyCallerPinBlockedEvent,
  1158.                                        EVENT_MODIFY_STATE,
  1159.                                        FALSE,
  1160.                                        0 );
  1161.     if( !fSuccess ) {
  1162.         return AmGetLastErrorToHResult();
  1163.     }
  1164.     m_BlockState = PENDING;
  1165.     m_dwBlockCallerThreadID = ::GetCurrentThreadId();
  1166.     // The output pin cannot be blocked if the streaming thread is
  1167.     // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive()
  1168.     // or IMemInputPin::ReceiveMultiple() on the connected input pin.  Also, it
  1169.     // cannot be blocked if the streaming thread is calling DynamicReconnect(),
  1170.     // ChangeMediaType() or ChangeOutputFormat().
  1171.     if(!StreamingThreadUsingOutputPin()) {
  1172.         // The output pin can be immediately blocked.
  1173.         BlockOutputPin();
  1174.     }
  1175.     return S_OK;
  1176. }
  1177. void CDynamicOutputPin::BlockOutputPin(void)
  1178. {
  1179.     // The caller should always hold the m_BlockStateLock because this function
  1180.     // uses m_BlockState and m_hNotifyCallerPinBlockedEvent.
  1181.     ASSERT(CritCheckIn(&m_BlockStateLock));
  1182.     // This function should not be called if the streaming thread is modifying
  1183.     // the connection state or it's passing data downstream.
  1184.     ASSERT(!StreamingThreadUsingOutputPin());
  1185.     // This should not fail because we successfully created the event
  1186.     // and we have the security permissions to change it's state.
  1187.     EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent));
  1188.     // This event should not fail because AsynchronousBlockOutputPin() successfully
  1189.     // duplicated this handle and we have the appropriate security permissions.
  1190.     EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent));
  1191.     EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
  1192.     m_BlockState = BLOCKED;
  1193.     m_hNotifyCallerPinBlockedEvent = NULL;
  1194. }
  1195. HRESULT CDynamicOutputPin::UnblockOutputPin(void)
  1196. {
  1197.     // UnblockOutputPin() holds the m_BlockStateLock because it
  1198.     // uses m_BlockState, m_dwBlockCallerThreadID and
  1199.     // m_hNotifyCallerPinBlockedEvent.
  1200.     CAutoLock alBlockStateLock(&m_BlockStateLock);
  1201.     if(NOT_BLOCKED == m_BlockState) {
  1202.         return S_FALSE;
  1203.     }
  1204.     // This should not fail because we successfully created the event
  1205.     // and we have the security permissions to change it's state.
  1206.     EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent));
  1207.     // Cancel the block operation if it's still pending.
  1208.     if(NULL != m_hNotifyCallerPinBlockedEvent) {
  1209.         // This event should not fail because AsynchronousBlockOutputPin() successfully
  1210.         // duplicated this handle and we have the appropriate security permissions.
  1211.         EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent));
  1212.         EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
  1213.     }
  1214.     m_BlockState = NOT_BLOCKED;
  1215.     m_dwBlockCallerThreadID = 0;
  1216.     m_hNotifyCallerPinBlockedEvent = NULL;
  1217.     return S_OK;
  1218. }
  1219. HRESULT CDynamicOutputPin::StartUsingOutputPin(void)
  1220. {
  1221.     // The caller should not hold m_BlockStateLock.  If the caller does,
  1222.     // a deadlock could occur.
  1223.     ASSERT(CritCheckOut(&m_BlockStateLock));
  1224.     CAutoLock alBlockStateLock(&m_BlockStateLock);
  1225.     #ifdef DEBUG
  1226.     AssertValid();
  1227.     #endif // DEBUG
  1228.     // Are we in the middle of a block operation?
  1229.     while(BLOCKED == m_BlockState) {
  1230.         m_BlockStateLock.Unlock();
  1231.         // If this ASSERT fires, a deadlock could occur.  The caller should make sure
  1232.         // that this thread never acquires the Block State lock more than once.
  1233.         ASSERT(CritCheckOut( &m_BlockStateLock ));
  1234.         // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event
  1235.         // is fired.  It returns WAIT_OBJECT_0 + 1 if the stop event if fired.
  1236.         // See the Windows SDK documentation for more information on
  1237.         // WaitForMultipleObjects().
  1238.         const DWORD UNBLOCK = WAIT_OBJECT_0;
  1239.         const DWORD STOP = WAIT_OBJECT_0 + 1;
  1240.         HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent };
  1241.         DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE);
  1242.         DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE );
  1243.         m_BlockStateLock.Lock();
  1244.         #ifdef DEBUG
  1245.         AssertValid();
  1246.         #endif // DEBUG
  1247.         switch( dwReturnValue ) {
  1248.         case UNBLOCK:
  1249.             break;
  1250.         case STOP:
  1251.             return VFW_E_STATE_CHANGED;
  1252.         case WAIT_FAILED:
  1253.             return AmGetLastErrorToHResult();
  1254.         default:
  1255.             DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." );
  1256.             return E_UNEXPECTED;
  1257.         }
  1258.     }
  1259.     m_dwNumOutstandingOutputPinUsers++;
  1260.     #ifdef DEBUG
  1261.     AssertValid();
  1262.     #endif // DEBUG
  1263.     return S_OK;
  1264. }
  1265. void CDynamicOutputPin::StopUsingOutputPin(void)
  1266. {
  1267.     CAutoLock alBlockStateLock(&m_BlockStateLock);
  1268.     #ifdef DEBUG
  1269.     AssertValid();
  1270.     #endif // DEBUG
  1271.     m_dwNumOutstandingOutputPinUsers--;
  1272.     if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) {
  1273.         BlockOutputPin();
  1274.     }
  1275.     #ifdef DEBUG
  1276.     AssertValid();
  1277.     #endif // DEBUG
  1278. }
  1279. bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void)
  1280. {
  1281.     CAutoLock alBlockStateLock(&m_BlockStateLock);
  1282.     return (m_dwNumOutstandingOutputPinUsers > 0);
  1283. }
  1284. void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent)
  1285. {
  1286.     // This pointer is not addrefed because filters are not allowed to
  1287.     // hold references to the filter graph manager.  See the documentation for
  1288.     // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information.
  1289.     m_pGraphConfig = pGraphConfig;
  1290.     m_hStopEvent = hStopEvent;
  1291. }
  1292. HRESULT CDynamicOutputPin::Active(void)
  1293. {
  1294.     // Make sure the user initialized the object by calling SetConfigInfo().
  1295.     if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) {
  1296.         DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized.  Call SetConfigInfo() to initialize them. );
  1297.         return E_FAIL;
  1298.     }
  1299.     // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  1300.     // The ASSERT can also fire if the event if destroyed and then Active() is called.  An event
  1301.     // handle is invalid if 1) the event does not exist or the user does not have the security
  1302.     // permissions to use the event.
  1303.     EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
  1304.     return CBaseOutputPin::Active();
  1305. }
  1306. HRESULT CDynamicOutputPin::Inactive(void)
  1307. {
  1308.     // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  1309.     // The ASSERT can also fire if the event if destroyed and then Active() is called.  An event
  1310.     // handle is invalid if 1) the event does not exist or the user does not have the security
  1311.     // permissions to use the event.
  1312.     EXECUTE_ASSERT(SetEvent(m_hStopEvent));
  1313.     return CBaseOutputPin::Inactive();
  1314. }
  1315. HRESULT CDynamicOutputPin::DeliverBeginFlush(void)
  1316. {
  1317.     // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  1318.     // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
  1319.     // An event handle is invalid if 1) the event does not exist or the user does not have the security
  1320.     // permissions to use the event.
  1321.     EXECUTE_ASSERT(SetEvent(m_hStopEvent));
  1322.     return CBaseOutputPin::DeliverBeginFlush();
  1323. }
  1324. HRESULT CDynamicOutputPin::DeliverEndFlush(void)
  1325. {
  1326.     // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  1327.     // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
  1328.     // An event handle is invalid if 1) the event does not exist or the user does not have the security
  1329.     // permissions to use the event.
  1330.     EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
  1331.     return CBaseOutputPin::DeliverEndFlush();
  1332. }
  1333. // ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly
  1334. // reconnects the output pin.
  1335. HRESULT CDynamicOutputPin::ChangeOutputFormat
  1336.     (
  1337.     const AM_MEDIA_TYPE *pmt,
  1338.     REFERENCE_TIME tSegmentStart,
  1339.     REFERENCE_TIME tSegmentStop,
  1340.     double dSegmentRate
  1341.     )
  1342. {
  1343.     // The caller should call StartUsingOutputPin() before calling this
  1344.     // method.
  1345.     ASSERT(StreamingThreadUsingOutputPin());
  1346.     // Callers should always pass a valid media type to ChangeOutputFormat() .
  1347.     ASSERT(NULL != pmt);
  1348.     CMediaType cmt(*pmt);
  1349.     HRESULT hr = ChangeMediaType(&cmt);
  1350.     if (FAILED(hr)) {
  1351.         return hr;
  1352.     }
  1353.     hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate);
  1354.     if( FAILED( hr ) ) {
  1355.         return hr;
  1356.     }
  1357.     return S_OK;
  1358. }
  1359. HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt)
  1360. {
  1361.     // The caller should call StartUsingOutputPin() before calling this
  1362.     // method.
  1363.     ASSERT(StreamingThreadUsingOutputPin());
  1364.     // This function assumes the filter graph is running.
  1365.     ASSERT(!IsStopped());
  1366.     if(!IsConnected()) {
  1367.         return VFW_E_NOT_CONNECTED;
  1368.     }
  1369.     /*  First check if the downstream pin will accept a dynamic
  1370.         format change
  1371.     */
  1372.     QzCComPtr<IPinConnection> pConnection;
  1373.     m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection);
  1374.     if(pConnection != NULL) {
  1375.         if(S_OK == pConnection->DynamicQueryAccept(pmt)) {
  1376.             HRESULT hr = ChangeMediaTypeHelper(pmt);
  1377.             if(FAILED(hr)) {
  1378.                 return hr;
  1379.             }
  1380.             return S_OK;
  1381.         }
  1382.     }
  1383.     /*  Can't do the dynamic connection */
  1384.     return DynamicReconnect(pmt);
  1385. }
  1386. HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt)
  1387. {
  1388.     // The caller should call StartUsingOutputPin() before calling this
  1389.     // method.
  1390.     ASSERT(StreamingThreadUsingOutputPin());
  1391.     HRESULT hr = m_Connected->ReceiveConnection(this, pmt);
  1392.     if(FAILED(hr)) {
  1393.         return hr;
  1394.     }
  1395.     hr = SetMediaType(pmt);
  1396.     if(FAILED(hr)) {
  1397.         return hr;
  1398.     }
  1399.     // Does this pin use the local memory transport?
  1400.     if(NULL != m_pInputPin) {
  1401.         // This function assumes that m_pInputPin and m_Connected are
  1402.         // two different interfaces to the same object.
  1403.         ASSERT(::IsEqualObject(m_Connected, m_pInputPin));
  1404.         ALLOCATOR_PROPERTIES apInputPinRequirements;
  1405.         apInputPinRequirements.cbAlign = 0;
  1406.         apInputPinRequirements.cbBuffer = 0;
  1407.         apInputPinRequirements.cbPrefix = 0;
  1408.         apInputPinRequirements.cBuffers = 0;
  1409.         m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements);
  1410.         // A zero allignment does not make any sense.
  1411.         if(0 == apInputPinRequirements.cbAlign) {
  1412.             apInputPinRequirements.cbAlign = 1;
  1413.         }
  1414.         hr = m_pAllocator->Decommit();
  1415.         if(FAILED(hr)) {
  1416.             return hr;
  1417.         }
  1418.         hr = DecideBufferSize(m_pAllocator,  &apInputPinRequirements);
  1419.         if(FAILED(hr)) {
  1420.             return hr;
  1421.         }
  1422.         hr = m_pAllocator->Commit();
  1423.         if(FAILED(hr)) {
  1424.             return hr;
  1425.         }
  1426.         hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator);
  1427.         if(FAILED(hr)) {
  1428.             return hr;
  1429.         }
  1430.     }
  1431.     return S_OK;
  1432. }
  1433. // this method has to be called from the thread that is pushing data,
  1434. // and it's the caller's responsibility to make sure that the thread
  1435. // has no outstand samples because they cannot be delivered after a
  1436. // reconnect
  1437. //
  1438. HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt )
  1439. {
  1440.     // The caller should call StartUsingOutputPin() before calling this
  1441.     // method.
  1442.     ASSERT(StreamingThreadUsingOutputPin());
  1443.     if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) {
  1444.         return E_FAIL;
  1445.     }
  1446.     HRESULT hr = m_pGraphConfig->Reconnect(
  1447.         this,
  1448.         NULL,
  1449.         pmt,
  1450.         NULL,
  1451.         m_hStopEvent,
  1452.         AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS );
  1453.     return hr;
  1454. }
  1455. HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin)
  1456. {
  1457.     HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
  1458.     if(SUCCEEDED(hr)) {
  1459.         if(!IsStopped() && m_pAllocator) {
  1460.             hr = m_pAllocator->Commit();
  1461.             ASSERT(hr != VFW_E_ALREADY_COMMITTED);
  1462.         }
  1463.     }
  1464.     return hr;
  1465. }
  1466. #ifdef DEBUG
  1467. void CDynamicOutputPin::AssertValid(void)
  1468. {
  1469.     // Make sure the object was correctly initialized.
  1470.     // This ASSERT only fires if the object failed to initialize
  1471.     // and the user ignored the constructor's return code (phr).
  1472.     ASSERT(NULL != m_hUnblockOutputPinEvent);
  1473.     // If either of these ASSERTs fire, the user did not correctly call
  1474.     // SetConfigInfo().
  1475.     ASSERT(NULL != m_hStopEvent);
  1476.     ASSERT(NULL != m_pGraphConfig);
  1477.     // Make sure the block state is consistent.
  1478.     CAutoLock alBlockStateLock(&m_BlockStateLock);
  1479.     // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED.
  1480.     ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState));
  1481.     // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete
  1482.     // immediately.
  1483.     ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) ||
  1484.            ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) );
  1485.     // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and
  1486.     // the user is not trying to block the pin.
  1487.     ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState));
  1488.     // If this ASSERT fires, the streaming thread is using the output pin and the
  1489.     // output pin is blocked.
  1490.     ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) ||
  1491.            ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) ||
  1492.            ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) );
  1493. }
  1494. #endif // DEBUG
  1495. HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent)
  1496. {
  1497.     const DWORD EVENT_SIGNALED = WAIT_OBJECT_0;
  1498.     DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE);
  1499.     switch( dwReturnValue ) {
  1500.     case EVENT_SIGNALED:
  1501.         return S_OK;
  1502.     case WAIT_FAILED:
  1503.         return AmGetLastErrorToHResult();
  1504.     default:
  1505.         DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." );
  1506.         return E_UNEXPECTED;
  1507.     }
  1508. }
  1509. //=====================================================================
  1510. //=====================================================================
  1511. // Implements CBaseAllocator
  1512. //=====================================================================
  1513. //=====================================================================
  1514. /* Constructor overrides the default settings for the free list to request
  1515.    that it be alertable (ie the list can be cast to a handle which can be
  1516.    passed to WaitForSingleObject). Both of the allocator lists also ask for
  1517.    object locking, the all list matches the object default settings but I
  1518.    have included them here just so it is obvious what kind of list it is */
  1519. CBaseAllocator::CBaseAllocator(TCHAR *pName,
  1520.                                LPUNKNOWN pUnk,
  1521.                                HRESULT *phr,
  1522.                                BOOL bEvent,
  1523.                                BOOL fEnableReleaseCallback
  1524.                                ) :
  1525.     CUnknown(pName, pUnk),
  1526.     m_lAllocated(0),
  1527.     m_bChanged(FALSE),
  1528.     m_bCommitted(FALSE),
  1529.     m_bDecommitInProgress(FALSE),
  1530.     m_lSize(0),
  1531.     m_lCount(0),
  1532.     m_lAlignment(0),
  1533.     m_lPrefix(0),
  1534.     m_hSem(NULL),
  1535.     m_lWaiting(0),
  1536.     m_fEnableReleaseCallback(fEnableReleaseCallback),
  1537.     m_pNotify(NULL)
  1538. {
  1539.     if (bEvent) {
  1540.         m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
  1541.         if (m_hSem == NULL) {
  1542.             *phr = E_OUTOFMEMORY;
  1543.             return;
  1544.         }
  1545.     }
  1546. }
  1547. #ifdef UNICODE
  1548. CBaseAllocator::CBaseAllocator(CHAR *pName,
  1549.                                LPUNKNOWN pUnk,
  1550.                                HRESULT *phr,
  1551.                                BOOL bEvent,
  1552.                                BOOL fEnableReleaseCallback) :
  1553.     CUnknown(pName, pUnk),
  1554.     m_lAllocated(0),
  1555.     m_bChanged(FALSE),
  1556.     m_bCommitted(FALSE),
  1557.     m_bDecommitInProgress(FALSE),
  1558.     m_lSize(0),
  1559.     m_lCount(0),
  1560.     m_lAlignment(0),
  1561.     m_lPrefix(0),
  1562.     m_hSem(NULL),
  1563.     m_lWaiting(0),
  1564.     m_fEnableReleaseCallback(fEnableReleaseCallback),
  1565.     m_pNotify(NULL)
  1566. {
  1567.     if (bEvent) {
  1568.         m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
  1569.         if (m_hSem == NULL) {
  1570.             *phr = E_OUTOFMEMORY;
  1571.             return;
  1572.         }
  1573.     }
  1574. }
  1575. #endif
  1576. /* Destructor */
  1577. CBaseAllocator::~CBaseAllocator()
  1578. {
  1579.     // we can't call Decommit here since that would mean a call to a
  1580.     // pure virtual in destructor.
  1581.     // We must assume that the derived class has gone into decommit state in
  1582.     // its destructor.
  1583.     ASSERT(!m_bCommitted);
  1584.     if (m_hSem != NULL) {
  1585.         EXECUTE_ASSERT(CloseHandle(m_hSem));
  1586.     }
  1587.     if (m_pNotify) {
  1588.         m_pNotify->Release();
  1589.     }
  1590. }
  1591. /* Override this to publicise our interfaces */
  1592. STDMETHODIMP
  1593. CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  1594. {
  1595.     /* Do we know about this interface */
  1596.     if (riid == IID_IMemAllocator ||
  1597.         riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) {
  1598.         return GetInterface((IMemAllocatorCallbackTemp *) this, ppv);
  1599.     } else {
  1600.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  1601.     }
  1602. }
  1603. /* This sets the size and count of the required samples. The memory isn't
  1604.    actually allocated until Commit() is called, if memory has already been
  1605.    allocated then assuming no samples are outstanding the user may call us
  1606.    to change the buffering, the memory will be released in Commit() */
  1607. STDMETHODIMP
  1608. CBaseAllocator::SetProperties(
  1609.                 ALLOCATOR_PROPERTIES* pRequest,
  1610.                 ALLOCATOR_PROPERTIES* pActual)
  1611. {
  1612.     CheckPointer(pRequest, E_POINTER);
  1613.     CheckPointer(pActual, E_POINTER);
  1614.     ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
  1615.     CAutoLock cObjectLock(this);
  1616.     ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
  1617.     ASSERT(pRequest->cbBuffer > 0);
  1618.     /*  Check the alignment requested */
  1619.     if (pRequest->cbAlign != 1) {
  1620.         DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"),
  1621.                pRequest->cbAlign));
  1622.         return VFW_E_BADALIGN;
  1623.     }
  1624.     /* Can't do this if already committed, there is an argument that says we
  1625.        should not reject the SetProperties call if there are buffers still
  1626.        active. However this is called by the source filter, which is the same
  1627.        person who is holding the samples. Therefore it is not unreasonable
  1628.        for them to free all their samples before changing the requirements */
  1629.     if (m_bCommitted) {
  1630.         return VFW_E_ALREADY_COMMITTED;
  1631.     }
  1632.     /* Must be no outstanding buffers */
  1633.     if (m_lAllocated != m_lFree.GetCount()) {
  1634.         return VFW_E_BUFFERS_OUTSTANDING;
  1635.     }
  1636.     /* There isn't any real need to check the parameters as they
  1637.        will just be rejected when the user finally calls Commit */
  1638.     pActual->cbBuffer = m_lSize = pRequest->cbBuffer;
  1639.     pActual->cBuffers = m_lCount = pRequest->cBuffers;
  1640.     pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
  1641.     pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
  1642.     m_bChanged = TRUE;
  1643.     return NOERROR;
  1644. }
  1645. STDMETHODIMP
  1646. CBaseAllocator::GetProperties(
  1647.     ALLOCATOR_PROPERTIES * pActual)
  1648. {
  1649.     CheckPointer(pActual,E_POINTER);
  1650.     ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
  1651.     CAutoLock cObjectLock(this);
  1652.     pActual->cbBuffer = m_lSize;
  1653.     pActual->cBuffers = m_lCount;
  1654.     pActual->cbAlign = m_lAlignment;
  1655.     pActual->cbPrefix = m_lPrefix;
  1656.     return NOERROR;
  1657. }
  1658. // get container for a sample. Blocking, synchronous call to get the
  1659. // next free buffer (as represented by an IMediaSample interface).
  1660. // on return, the time etc properties will be invalid, but the buffer
  1661. // pointer and size will be correct.
  1662. HRESULT CBaseAllocator::GetBuffer(IMediaSample **ppBuffer,
  1663.                                   REFERENCE_TIME *pStartTime,
  1664.                                   REFERENCE_TIME *pEndTime,
  1665.                                   DWORD dwFlags
  1666.                                   )
  1667. {
  1668.     UNREFERENCED_PARAMETER(pStartTime);
  1669.     UNREFERENCED_PARAMETER(pEndTime);
  1670.     UNREFERENCED_PARAMETER(dwFlags);
  1671.     CMediaSample *pSample;
  1672.     *ppBuffer = NULL;
  1673.     for (;;)
  1674.     {
  1675.         {  // scope for lock
  1676.             CAutoLock cObjectLock(this);
  1677.             /* Check we are committed */
  1678.             if (!m_bCommitted) {
  1679.                 return VFW_E_NOT_COMMITTED;
  1680.             }
  1681.             pSample = (CMediaSample *) m_lFree.RemoveHead();
  1682.             if (pSample == NULL) {
  1683.                 SetWaiting();
  1684.             }
  1685.         }
  1686.         /* If we didn't get a sample then wait for the list to signal */
  1687.         if (pSample) {
  1688.             break;
  1689.         }
  1690.         if (dwFlags & AM_GBF_NOWAIT) {
  1691.             return VFW_E_TIMEOUT;
  1692.         }
  1693.         ASSERT(m_hSem != NULL);
  1694.         WaitForSingleObject(m_hSem, INFINITE);
  1695.     }
  1696.     /* Addref the buffer up to one. On release
  1697.        back to zero instead of being deleted, it will requeue itself by
  1698.        calling the ReleaseBuffer member function. NOTE the owner of a
  1699.        media sample must always be derived from CBaseAllocator */
  1700.     ASSERT(pSample->m_cRef == 0);
  1701.     pSample->m_cRef = 1;
  1702.     *ppBuffer = pSample;
  1703.     return NOERROR;
  1704. }
  1705. /* Final release of a CMediaSample will call this */
  1706. STDMETHODIMP
  1707. CBaseAllocator::ReleaseBuffer(IMediaSample * pSample)
  1708. {
  1709.     CheckPointer(pSample,E_POINTER);
  1710.     ValidateReadPtr(pSample,sizeof(IMediaSample));
  1711.     BOOL bRelease = FALSE;
  1712.     {
  1713.         CAutoLock cal(this);
  1714.         /* Put back on the free list */
  1715.         m_lFree.Add((CMediaSample *)pSample);
  1716.         if (m_lWaiting != 0) {
  1717.             NotifySample();
  1718.         }
  1719.         // if there is a pending Decommit, then we need to complete it by
  1720.         // calling Free() when the last buffer is placed on the free list
  1721.         LONG l1 = m_lFree.GetCount();
  1722.         if (m_bDecommitInProgress && (l1 == m_lAllocated)) {
  1723.             Free();
  1724.             m_bDecommitInProgress = FALSE;
  1725.             bRelease = TRUE;
  1726.         }
  1727.     }
  1728.     if (m_pNotify) {
  1729.         ASSERT(m_fEnableReleaseCallback);
  1730.         //
  1731.         // Note that this is not synchronized with setting up a notification
  1732.         // method.
  1733.         //
  1734.         m_pNotify->NotifyRelease();
  1735.     }
  1736.     /* For each buffer there is one AddRef, made in GetBuffer and released
  1737.        here. This may cause the allocator and all samples to be deleted */
  1738.     if (bRelease) {
  1739.         Release();
  1740.     }
  1741.     return NOERROR;
  1742. }
  1743. STDMETHODIMP
  1744. CBaseAllocator::SetNotify(
  1745.     IMemAllocatorNotifyCallbackTemp* pNotify
  1746.     )
  1747. {
  1748.     ASSERT(m_fEnableReleaseCallback);
  1749.     CAutoLock lck(this);
  1750.     if (pNotify) {
  1751.         pNotify->AddRef();
  1752.     }
  1753.     if (m_pNotify) {
  1754.         m_pNotify->Release();
  1755.     }
  1756.     m_pNotify = pNotify;
  1757.     return S_OK;
  1758. }
  1759. STDMETHODIMP
  1760. CBaseAllocator::GetFreeCount(
  1761.     LONG* plBuffersFree
  1762.     )
  1763. {
  1764.     ASSERT(m_fEnableReleaseCallback);
  1765.     CAutoLock cObjectLock(this);
  1766.     *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount();
  1767.     return NOERROR;
  1768. }
  1769. void
  1770. CBaseAllocator::NotifySample()
  1771. {
  1772.     if (m_lWaiting != 0) {
  1773.         ASSERT(m_hSem != NULL);
  1774.         ReleaseSemaphore(m_hSem, m_lWaiting, 0);
  1775.         m_lWaiting = 0;
  1776.     }
  1777. }
  1778. STDMETHODIMP
  1779. CBaseAllocator::Commit()
  1780. {
  1781.     /* Check we are not decommitted */
  1782.     CAutoLock cObjectLock(this);
  1783.     // cannot need to alloc or re-alloc if we are committed
  1784.     if (m_bCommitted) {
  1785.         return NOERROR;
  1786.     }
  1787.     /* Allow GetBuffer calls */
  1788.     m_bCommitted = TRUE;
  1789.     // is there a pending decommit ? if so, just cancel it
  1790.     if (m_bDecommitInProgress) {
  1791.         m_bDecommitInProgress = FALSE;
  1792.         // don't call Alloc at this point. He cannot allow SetProperties
  1793.         // between Decommit and the last free, so the buffer size cannot have
  1794.         // changed. And because some of the buffers are not free yet, he
  1795.         // cannot re-alloc anyway.
  1796.         return NOERROR;
  1797.     }
  1798.     DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize));
  1799.     // actually need to allocate the samples
  1800.     HRESULT hr = Alloc();
  1801.     if (FAILED(hr)) {
  1802.         m_bCommitted = FALSE;
  1803.         return hr;
  1804.     }
  1805.     AddRef();
  1806.     return NOERROR;
  1807. }
  1808. STDMETHODIMP
  1809. CBaseAllocator::Decommit()
  1810. {
  1811.     BOOL bRelease = FALSE;
  1812.     {
  1813.         /* Check we are not already decommitted */
  1814.         CAutoLock cObjectLock(this);
  1815.         if (m_bCommitted == FALSE) {
  1816.             if (m_bDecommitInProgress == FALSE) {
  1817.                 return NOERROR;
  1818.             }
  1819.         }
  1820.         /* No more GetBuffer calls will succeed */
  1821.         m_bCommitted = FALSE;
  1822.         // are any buffers outstanding?
  1823.         if (m_lFree.GetCount() < m_lAllocated) {
  1824.             // please complete the decommit when last buffer is freed
  1825.             m_bDecommitInProgress = TRUE;
  1826.         } else {
  1827.             m_bDecommitInProgress = FALSE;
  1828.             // need to complete the decommit here as there are no
  1829.             // outstanding buffers
  1830.             Free();
  1831.             bRelease = TRUE;
  1832.         }
  1833.         // Tell anyone waiting that they can go now so we can
  1834.         // reject their call
  1835.         NotifySample();
  1836.     }
  1837.     if (bRelease) {
  1838.         Release();
  1839.     }
  1840.     return NOERROR;
  1841. }
  1842. /* Base definition of allocation which checks we are ok to go ahead and do
  1843.    the full allocation. We return S_FALSE if the requirements are the same */
  1844. HRESULT
  1845. CBaseAllocator::Alloc(void)
  1846. {
  1847.     /* Error if he hasn't set the size yet */
  1848.     if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) {
  1849.         return VFW_E_SIZENOTSET;
  1850.     }
  1851.     /* should never get here while buffers outstanding */
  1852.     ASSERT(m_lFree.GetCount() == m_lAllocated);
  1853.     /* If the requirements haven't changed then don't reallocate */
  1854.     if (m_bChanged == FALSE) {
  1855.         return S_FALSE;
  1856.     }
  1857.     return NOERROR;
  1858. }
  1859. /*  Implement CBaseAllocator::CSampleList::Remove(pSample)
  1860.     Removes pSample from the list
  1861. */
  1862. void
  1863. CBaseAllocator::CSampleList::Remove(CMediaSample * pSample)
  1864. {
  1865.     CMediaSample **pSearch;
  1866.     for (pSearch = &m_List;
  1867.          *pSearch != NULL;
  1868.          pSearch = &(CBaseAllocator::NextSample(*pSearch))) {
  1869.        if (*pSearch == pSample) {
  1870.            *pSearch = CBaseAllocator::NextSample(pSample);
  1871.            CBaseAllocator::NextSample(pSample) = NULL;
  1872.            m_nOnList--;
  1873.            return;
  1874.        }
  1875.     }
  1876.     DbgBreak("Couldn't find sample in list");
  1877. }
  1878. //=====================================================================
  1879. //=====================================================================
  1880. // Implements CMemAllocator
  1881. //=====================================================================
  1882. //=====================================================================
  1883. /* This goes in the factory template table to create new instances */
  1884. CUnknown *CMemAllocator::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
  1885. {
  1886.     CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr);
  1887.     return pUnkRet;
  1888. }
  1889. CMemAllocator::CMemAllocator(
  1890.     TCHAR *pName,
  1891.     LPUNKNOWN pUnk,
  1892.     HRESULT *phr)
  1893.     : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
  1894.     m_pBuffer(NULL)
  1895. {
  1896. }
  1897. #ifdef UNICODE
  1898. CMemAllocator::CMemAllocator(
  1899.     CHAR *pName,
  1900.     LPUNKNOWN pUnk,
  1901.     HRESULT *phr)
  1902.     : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
  1903.     m_pBuffer(NULL)
  1904. {
  1905. }
  1906. #endif
  1907. /* This sets the size and count of the required samples. The memory isn't
  1908.    actually allocated until Commit() is called, if memory has already been
  1909.    allocated then assuming no samples are outstanding the user may call us
  1910.    to change the buffering, the memory will be released in Commit() */
  1911. STDMETHODIMP
  1912. CMemAllocator::SetProperties(
  1913.                 ALLOCATOR_PROPERTIES* pRequest,
  1914.                 ALLOCATOR_PROPERTIES* pActual)
  1915. {
  1916.     CheckPointer(pActual,E_POINTER);
  1917.     ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
  1918.     CAutoLock cObjectLock(this);
  1919.     ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
  1920.     ASSERT(pRequest->cbBuffer > 0);
  1921.     SYSTEM_INFO SysInfo;
  1922.     GetSystemInfo(&SysInfo);
  1923.     /*  Check the alignment request is a power of 2 */
  1924.     if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) {
  1925.         DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"),
  1926.                pRequest->cbAlign));
  1927.     }
  1928.     /*  Check the alignment requested */
  1929.     if (pRequest->cbAlign == 0 ||
  1930.     (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) {
  1931.         DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"),
  1932.                pRequest->cbAlign, SysInfo.dwAllocationGranularity));
  1933.         return VFW_E_BADALIGN;
  1934.     }
  1935.     /* Can't do this if already committed, there is an argument that says we
  1936.        should not reject the SetProperties call if there are buffers still
  1937.        active. However this is called by the source filter, which is the same
  1938.        person who is holding the samples. Therefore it is not unreasonable
  1939.        for them to free all their samples before changing the requirements */
  1940.     if (m_bCommitted == TRUE) {
  1941.         return VFW_E_ALREADY_COMMITTED;
  1942.     }
  1943.     /* Must be no outstanding buffers */
  1944.     if (m_lFree.GetCount() < m_lAllocated) {
  1945.         return VFW_E_BUFFERS_OUTSTANDING;
  1946.     }
  1947.     /* There isn't any real need to check the parameters as they
  1948.        will just be rejected when the user finally calls Commit */
  1949.     // round length up to alignment - remember that prefix is included in
  1950.     // the alignment
  1951.     LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix;
  1952.     LONG lRemainder = lSize % pRequest->cbAlign;
  1953.     if (lRemainder != 0) {
  1954.         lSize = lSize - lRemainder + pRequest->cbAlign;
  1955.     }
  1956.     pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix);
  1957.     pActual->cBuffers = m_lCount = pRequest->cBuffers;
  1958.     pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
  1959.     pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
  1960.     m_bChanged = TRUE;
  1961.     return NOERROR;
  1962. }
  1963. // override this to allocate our resources when Commit is called.
  1964. //
  1965. // note that our resources may be already allocated when this is called,
  1966. // since we don't free them on Decommit. We will only be called when in
  1967. // decommit state with all buffers free.
  1968. //
  1969. // object locked by caller
  1970. HRESULT
  1971. CMemAllocator::Alloc(void)
  1972. {
  1973.     CAutoLock lck(this);
  1974.     /* Check he has called SetProperties */
  1975.     HRESULT hr = CBaseAllocator::Alloc();
  1976.     if (FAILED(hr)) {
  1977.         return hr;
  1978.     }
  1979.     /* If the requirements haven't changed then don't reallocate */
  1980.     if (hr == S_FALSE) {
  1981.         ASSERT(m_pBuffer);
  1982.         return NOERROR;
  1983.     }
  1984.     ASSERT(hr == S_OK); // we use this fact in the loop below
  1985.     /* Free the old resources */
  1986.     if (m_pBuffer) {
  1987.         ReallyFree();
  1988.     }
  1989.     /* Compute the aligned size */
  1990.     LONG lAlignedSize = m_lSize + m_lPrefix;
  1991.     if (m_lAlignment > 1) {
  1992.         LONG lRemainder = lAlignedSize % m_lAlignment;
  1993.         if (lRemainder != 0) {
  1994.             lAlignedSize += (m_lAlignment - lRemainder);
  1995.         }
  1996.     }
  1997.     /* Create the contiguous memory block for the samples
  1998.        making sure it's properly aligned (64K should be enough!)
  1999.     */
  2000.     ASSERT(lAlignedSize % m_lAlignment == 0);
  2001.     m_pBuffer = (PBYTE)VirtualAlloc(NULL,
  2002.                     m_lCount * lAlignedSize,
  2003.                     MEM_COMMIT,
  2004.                     PAGE_READWRITE);
  2005.     if (m_pBuffer == NULL) {
  2006.         return E_OUTOFMEMORY;
  2007.     }
  2008.     LPBYTE pNext = m_pBuffer;
  2009.     CMediaSample *pSample;
  2010.     ASSERT(m_lAllocated == 0);
  2011.     // Create the new samples - we have allocated m_lSize bytes for each sample
  2012.     // plus m_lPrefix bytes per sample as a prefix. We set the pointer to
  2013.     // the memory after the prefix - so that GetPointer() will return a pointer
  2014.     // to m_lSize bytes.
  2015.     for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) {
  2016.         pSample = new CMediaSample(
  2017.                             NAME("Default memory media sample"),
  2018.                 this,
  2019.                             &hr,
  2020.                             pNext + m_lPrefix,      // GetPointer() value
  2021.                             m_lSize);               // not including prefix
  2022.             ASSERT(SUCCEEDED(hr));
  2023.         if (pSample == NULL) {
  2024.             return E_OUTOFMEMORY;
  2025.         }
  2026.         // This CANNOT fail
  2027.         m_lFree.Add(pSample);
  2028.     }
  2029.     m_bChanged = FALSE;
  2030.     return NOERROR;
  2031. }
  2032. // override this to free up any resources we have allocated.
  2033. // called from the base class on Decommit when all buffers have been
  2034. // returned to the free list.
  2035. //
  2036. // caller has already locked the object.
  2037. // in our case, we keep the memory until we are deleted, so
  2038. // we do nothing here. The memory is deleted in the destructor by
  2039. // calling ReallyFree()
  2040. void
  2041. CMemAllocator::Free(void)
  2042. {
  2043.     return;
  2044. }
  2045. // called from the destructor (and from Alloc if changing size/count) to
  2046. // actually free up the memory
  2047. void
  2048. CMemAllocator::ReallyFree(void)
  2049. {
  2050.     /* Should never be deleting this unless all buffers are freed */
  2051.     ASSERT(m_lAllocated == m_lFree.GetCount());
  2052.     /* Free up all the CMediaSamples */
  2053.     CMediaSample *pSample;
  2054.     for (;;) {
  2055.         pSample = m_lFree.RemoveHead();
  2056.         if (pSample != NULL) {
  2057.             delete pSample;
  2058.         } else {
  2059.             break;
  2060.         }
  2061.     }
  2062.     m_lAllocated = 0;
  2063.     // free the block of buffer memory
  2064.     if (m_pBuffer) {
  2065.         EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE));
  2066.         m_pBuffer = NULL;
  2067.     }
  2068. }
  2069. /* Destructor frees our memory resources */
  2070. CMemAllocator::~CMemAllocator()
  2071. {
  2072.     Decommit();
  2073.     ReallyFree();
  2074. }
  2075. // ------------------------------------------------------------------------
  2076. // filter registration through IFilterMapper. used if IFilterMapper is
  2077. // not found (Quartz 1.0 install)
  2078. STDAPI
  2079. AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata
  2080.                          , IFilterMapper *                  pIFM
  2081.                          , BOOL                             bRegister  )
  2082. {
  2083.   DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter")));
  2084.   // check we've got data
  2085.   //
  2086.   if( NULL == psetupdata ) return S_FALSE;
  2087.   // unregister filter
  2088.   // (as pins are subkeys of filter's CLSID key
  2089.   // they do not need to be removed separately).
  2090.   //
  2091.   DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter")));
  2092.   HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) );
  2093.   if( bRegister )
  2094.   {
  2095.     // register filter
  2096.     //
  2097.     DbgLog((LOG_TRACE, 3, TEXT("= = register filter")));
  2098.     hr = pIFM->RegisterFilter( *(psetupdata->clsID)
  2099.                              , psetupdata->strName
  2100.                              , psetupdata->dwMerit    );
  2101.     if( SUCCEEDED(hr) )
  2102.     {
  2103.       // all its pins
  2104.       //
  2105.       DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins")));
  2106.       for( UINT m1=0; m1 < psetupdata->nPins; m1++ )
  2107.       {
  2108.         hr = pIFM->RegisterPin( *(psetupdata->clsID)
  2109.                               , psetupdata->lpPin[m1].strName
  2110.                               , psetupdata->lpPin[m1].bRendered
  2111.                               , psetupdata->lpPin[m1].bOutput
  2112.                               , psetupdata->lpPin[m1].bZero
  2113.                               , psetupdata->lpPin[m1].bMany
  2114.                               , *(psetupdata->lpPin[m1].clsConnectsToFilter)
  2115.                               , psetupdata->lpPin[m1].strConnectsToPin );
  2116.         if( SUCCEEDED(hr) )
  2117.         {
  2118.           // and each pin's media types
  2119.           //
  2120.           DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types")));
  2121.           for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ )
  2122.           {
  2123.             hr = pIFM->RegisterPinType( *(psetupdata->clsID)
  2124.                                       , psetupdata->lpPin[m1].strName
  2125.                                       , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType)
  2126.                                       , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) );
  2127.             if( FAILED(hr) ) break;
  2128.           }
  2129.           if( FAILED(hr) ) break;
  2130.         }
  2131.         if( FAILED(hr) ) break;
  2132.       }
  2133.     }
  2134.   }
  2135.   // handle one acceptable "error" - that
  2136.   // of filter not being registered!
  2137.   // (couldn't find a suitable #define'd
  2138.   // name for the error!)
  2139.   //
  2140.   if( 0x80070002 == hr)
  2141.     return NOERROR;
  2142.   else
  2143.     return hr;
  2144. }
  2145. //  Remove warnings about unreferenced inline functions
  2146. #pragma warning(disable:4514)