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

P2P编程

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // File: Transfrm.cpp
  3. //
  4. // Desc: DirectShow base classes - implements class for simple transform
  5. //       filters such as video decompressors.
  6. //
  7. // Copyright (c) Microsoft Corporation.  All rights reserved.
  8. //------------------------------------------------------------------------------
  9. #include <streams.h>
  10. #include <measure.h>
  11. // =================================================================
  12. // Implements the CTransformFilter class
  13. // =================================================================
  14. CTransformFilter::CTransformFilter(TCHAR     *pName,
  15.                                    LPUNKNOWN pUnk,
  16.                                    REFCLSID  clsid) :
  17.     CBaseFilter(pName,pUnk,&m_csFilter, clsid),
  18.     m_pInput(NULL),
  19.     m_pOutput(NULL),
  20.     m_bEOSDelivered(FALSE),
  21.     m_bQualityChanged(FALSE),
  22.     m_bSampleSkipped(FALSE)
  23. {
  24. #ifdef PERF
  25.     RegisterPerfId();
  26. #endif //  PERF
  27. }
  28. #ifdef UNICODE
  29. CTransformFilter::CTransformFilter(char     *pName,
  30.                                    LPUNKNOWN pUnk,
  31.                                    REFCLSID  clsid) :
  32.     CBaseFilter(pName,pUnk,&m_csFilter, clsid),
  33.     m_pInput(NULL),
  34.     m_pOutput(NULL),
  35.     m_bEOSDelivered(FALSE),
  36.     m_bQualityChanged(FALSE),
  37.     m_bSampleSkipped(FALSE)
  38. {
  39. #ifdef PERF
  40.     RegisterPerfId();
  41. #endif //  PERF
  42. }
  43. #endif
  44. // destructor
  45. CTransformFilter::~CTransformFilter()
  46. {
  47.     // Delete the pins
  48.     delete m_pInput;
  49.     delete m_pOutput;
  50. }
  51. // Transform place holder - should never be called
  52. HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut)
  53. {
  54.     UNREFERENCED_PARAMETER(pIn);
  55.     UNREFERENCED_PARAMETER(pOut);
  56.     DbgBreak("CTransformFilter::Transform() should never be called");
  57.     return E_UNEXPECTED;
  58. }
  59. // return the number of pins we provide
  60. int CTransformFilter::GetPinCount()
  61. {
  62.     return 2;
  63. }
  64. // return a non-addrefed CBasePin * for the user to addref if he holds onto it
  65. // for longer than his pointer to us. We create the pins dynamically when they
  66. // are asked for rather than in the constructor. This is because we want to
  67. // give the derived class an oppportunity to return different pin objects
  68. // We return the objects as and when they are needed. If either of these fails
  69. // then we return NULL, the assumption being that the caller will realise the
  70. // whole deal is off and destroy us - which in turn will delete everything.
  71. CBasePin *
  72. CTransformFilter::GetPin(int n)
  73. {
  74.     HRESULT hr = S_OK;
  75.     // Create an input pin if necessary
  76.     if (m_pInput == NULL) {
  77.         m_pInput = new CTransformInputPin(NAME("Transform input pin"),
  78.                                           this,              // Owner filter
  79.                                           &hr,               // Result code
  80.                                           L"XForm In");      // Pin name
  81.         //  Can't fail
  82.         ASSERT(SUCCEEDED(hr));
  83.         if (m_pInput == NULL) {
  84.             return NULL;
  85.         }
  86.         m_pOutput = (CTransformOutputPin *)
  87.    new CTransformOutputPin(NAME("Transform output pin"),
  88.                                             this,            // Owner filter
  89.                                             &hr,             // Result code
  90.                                             L"XForm Out");   // Pin name
  91.         // Can't fail
  92.         ASSERT(SUCCEEDED(hr));
  93.         if (m_pOutput == NULL) {
  94.             delete m_pInput;
  95.             m_pInput = NULL;
  96.         }
  97.     }
  98.     // Return the appropriate pin
  99.     if (n == 0) {
  100.         return m_pInput;
  101.     } else
  102.     if (n == 1) {
  103.         return m_pOutput;
  104.     } else {
  105.         return NULL;
  106.     }
  107. }
  108. //
  109. // FindPin
  110. //
  111. // If Id is In or Out then return the IPin* for that pin
  112. // creating the pin if need be.  Otherwise return NULL with an error.
  113. STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin)
  114. {
  115.     CheckPointer(ppPin,E_POINTER);
  116.     ValidateReadWritePtr(ppPin,sizeof(IPin *));
  117.     if (0==lstrcmpW(Id,L"In")) {
  118.         *ppPin = GetPin(0);
  119.     } else if (0==lstrcmpW(Id,L"Out")) {
  120.         *ppPin = GetPin(1);
  121.     } else {
  122.         *ppPin = NULL;
  123.         return VFW_E_NOT_FOUND;
  124.     }
  125.     HRESULT hr = NOERROR;
  126.     //  AddRef() returned pointer - but GetPin could fail if memory is low.
  127.     if (*ppPin) {
  128.         (*ppPin)->AddRef();
  129.     } else {
  130.         hr = E_OUTOFMEMORY;  // probably.  There's no pin anyway.
  131.     }
  132.     return hr;
  133. }
  134. // override these two functions if you want to inform something
  135. // about entry to or exit from streaming state.
  136. HRESULT
  137. CTransformFilter::StartStreaming()
  138. {
  139.     return NOERROR;
  140. }
  141. HRESULT
  142. CTransformFilter::StopStreaming()
  143. {
  144.     return NOERROR;
  145. }
  146. // override this to grab extra interfaces on connection
  147. HRESULT
  148. CTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin)
  149. {
  150.     UNREFERENCED_PARAMETER(dir);
  151.     UNREFERENCED_PARAMETER(pPin);
  152.     return NOERROR;
  153. }
  154. // place holder to allow derived classes to release any extra interfaces
  155. HRESULT
  156. CTransformFilter::BreakConnect(PIN_DIRECTION dir)
  157. {
  158.     UNREFERENCED_PARAMETER(dir);
  159.     return NOERROR;
  160. }
  161. // Let derived classes know about connection completion
  162. HRESULT
  163. CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin)
  164. {
  165.     UNREFERENCED_PARAMETER(direction);
  166.     UNREFERENCED_PARAMETER(pReceivePin);
  167.     return NOERROR;
  168. }
  169. // override this to know when the media type is really set
  170. HRESULT
  171. CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
  172. {
  173.     UNREFERENCED_PARAMETER(direction);
  174.     UNREFERENCED_PARAMETER(pmt);
  175.     return NOERROR;
  176. }
  177. // Set up our output sample
  178. HRESULT
  179. CTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample)
  180. {
  181.     IMediaSample *pOutSample;
  182.     // default - times are the same
  183.     AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
  184.     DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0;
  185.     // This will prevent the image renderer from switching us to DirectDraw
  186.     // when we can't do it without skipping frames because we're not on a
  187.     // keyframe.  If it really has to switch us, it still will, but then we
  188.     // will have to wait for the next keyframe
  189.     if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) {
  190. dwFlags |= AM_GBF_NOTASYNCPOINT;
  191.     }
  192.     ASSERT(m_pOutput->m_pAllocator != NULL);
  193.     HRESULT hr = m_pOutput->m_pAllocator->GetBuffer(
  194.              &pOutSample
  195.              , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ?
  196.                    &pProps->tStart : NULL
  197.              , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ?
  198.                    &pProps->tStop : NULL
  199.              , dwFlags
  200.          );
  201.     *ppOutSample = pOutSample;
  202.     if (FAILED(hr)) {
  203.         return hr;
  204.     }
  205.     ASSERT(pOutSample);
  206.     IMediaSample2 *pOutSample2;
  207.     if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2,
  208.                                              (void **)&pOutSample2))) {
  209.         /*  Modify it */
  210.         AM_SAMPLE2_PROPERTIES OutProps;
  211.         EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(
  212.             FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps)
  213.         ));
  214.         OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
  215.         OutProps.dwSampleFlags =
  216.             (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) |
  217.             (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED);
  218.         OutProps.tStart = pProps->tStart;
  219.         OutProps.tStop  = pProps->tStop;
  220.         OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId);
  221.         hr = pOutSample2->SetProperties(
  222.             FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId),
  223.             (PBYTE)&OutProps
  224.         );
  225.         if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) {
  226.             m_bSampleSkipped = FALSE;
  227.         }
  228.         pOutSample2->Release();
  229.     } else {
  230.         if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) {
  231.             pOutSample->SetTime(&pProps->tStart,
  232.                                 &pProps->tStop);
  233.         }
  234.         if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) {
  235.             pOutSample->SetSyncPoint(TRUE);
  236.         }
  237.         if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) {
  238.             pOutSample->SetDiscontinuity(TRUE);
  239.             m_bSampleSkipped = FALSE;
  240.         }
  241.         // Copy the media times
  242.         LONGLONG MediaStart, MediaEnd;
  243.         if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
  244.             pOutSample->SetMediaTime(&MediaStart,&MediaEnd);
  245.         }
  246.     }
  247.     return S_OK;
  248. }
  249. // override this to customize the transform process
  250. HRESULT
  251. CTransformFilter::Receive(IMediaSample *pSample)
  252. {
  253.     /*  Check for other streams and pass them on */
  254.     AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
  255.     if (pProps->dwStreamId != AM_STREAM_MEDIA) {
  256.         return m_pOutput->m_pInputPin->Receive(pSample);
  257.     }
  258.     HRESULT hr;
  259.     ASSERT(pSample);
  260.     IMediaSample * pOutSample;
  261.     // If no output to deliver to then no point sending us data
  262.     ASSERT (m_pOutput != NULL) ;
  263.     // Set up the output sample
  264.     hr = InitializeOutputSample(pSample, &pOutSample);
  265.     if (FAILED(hr)) {
  266.         return hr;
  267.     }
  268.     // Start timing the transform (if PERF is defined)
  269.     MSR_START(m_idTransform);
  270.     // have the derived class transform the data
  271.     hr = Transform(pSample, pOutSample);
  272.     // Stop the clock and log it (if PERF is defined)
  273.     MSR_STOP(m_idTransform);
  274.     if (FAILED(hr)) {
  275. DbgLog((LOG_TRACE,1,TEXT("Error from transform")));
  276.     } else {
  277.         // the Transform() function can return S_FALSE to indicate that the
  278.         // sample should not be delivered; we only deliver the sample if it's
  279.         // really S_OK (same as NOERROR, of course.)
  280.         if (hr == NOERROR) {
  281.          hr = m_pOutput->m_pInputPin->Receive(pOutSample);
  282.             m_bSampleSkipped = FALSE; // last thing no longer dropped
  283.         } else {
  284.             // S_FALSE returned from Transform is a PRIVATE agreement
  285.             // We should return NOERROR from Receive() in this cause because returning S_FALSE
  286.             // from Receive() means that this is the end of the stream and no more data should
  287.             // be sent.
  288.             if (S_FALSE == hr) {
  289.                 //  Release the sample before calling notify to avoid
  290.                 //  deadlocks if the sample holds a lock on the system
  291.                 //  such as DirectDraw buffers do
  292.                 pOutSample->Release();
  293.                 m_bSampleSkipped = TRUE;
  294.                 if (!m_bQualityChanged) {
  295.                     NotifyEvent(EC_QUALITY_CHANGE,0,0);
  296.                     m_bQualityChanged = TRUE;
  297.                 }
  298.                 return NOERROR;
  299.             }
  300.         }
  301.     }
  302.     // release the output buffer. If the connected pin still needs it,
  303.     // it will have addrefed it itself.
  304.     pOutSample->Release();
  305.     return hr;
  306. }
  307. // Return S_FALSE to mean "pass the note on upstream"
  308. // Return NOERROR (Same as S_OK)
  309. // to mean "I've done something about it, don't pass it on"
  310. HRESULT CTransformFilter::AlterQuality(Quality q)
  311. {
  312.     UNREFERENCED_PARAMETER(q);
  313.     return S_FALSE;
  314. }
  315. // EndOfStream received. Default behaviour is to deliver straight
  316. // downstream, since we have no queued data. If you overrode Receive
  317. // and have queue data, then you need to handle this and deliver EOS after
  318. // all queued data is sent
  319. HRESULT
  320. CTransformFilter::EndOfStream(void)
  321. {
  322.     HRESULT hr = NOERROR;
  323.     if (m_pOutput != NULL) {
  324.         hr = m_pOutput->DeliverEndOfStream();
  325.     }
  326.     return hr;
  327. }
  328. // enter flush state. Receives already blocked
  329. // must override this if you have queued data or a worker thread
  330. HRESULT
  331. CTransformFilter::BeginFlush(void)
  332. {
  333.     HRESULT hr = NOERROR;
  334.     if (m_pOutput != NULL) {
  335. // block receives -- done by caller (CBaseInputPin::BeginFlush)
  336. // discard queued data -- we have no queued data
  337. // free anyone blocked on receive - not possible in this filter
  338. // call downstream
  339. hr = m_pOutput->DeliverBeginFlush();
  340.     }
  341.     return hr;
  342. }
  343. // leave flush state. must override this if you have queued data
  344. // or a worker thread
  345. HRESULT
  346. CTransformFilter::EndFlush(void)
  347. {
  348.     // sync with pushing thread -- we have no worker thread
  349.     // ensure no more data to go downstream -- we have no queued data
  350.     // call EndFlush on downstream pins
  351.     ASSERT (m_pOutput != NULL);
  352.     return m_pOutput->DeliverEndFlush();
  353.     // caller (the input pin's method) will unblock Receives
  354. }
  355. // override these so that the derived filter can catch them
  356. STDMETHODIMP
  357. CTransformFilter::Stop()
  358. {
  359.     CAutoLock lck1(&m_csFilter);
  360.     if (m_State == State_Stopped) {
  361.         return NOERROR;
  362.     }
  363.     // Succeed the Stop if we are not completely connected
  364.     ASSERT(m_pInput == NULL || m_pOutput != NULL);
  365.     if (m_pInput == NULL || m_pInput->IsConnected() == FALSE ||
  366.         m_pOutput->IsConnected() == FALSE) {
  367.                 m_State = State_Stopped;
  368.                 m_bEOSDelivered = FALSE;
  369.                 return NOERROR;
  370.     }
  371.     ASSERT(m_pInput);
  372.     ASSERT(m_pOutput);
  373.     // decommit the input pin before locking or we can deadlock
  374.     m_pInput->Inactive();
  375.     // synchronize with Receive calls
  376.     CAutoLock lck2(&m_csReceive);
  377.     m_pOutput->Inactive();
  378.     // allow a class derived from CTransformFilter
  379.     // to know about starting and stopping streaming
  380.     HRESULT hr = StopStreaming();
  381.     if (SUCCEEDED(hr)) {
  382. // complete the state transition
  383. m_State = State_Stopped;
  384. m_bEOSDelivered = FALSE;
  385.     }
  386.     return hr;
  387. }
  388. STDMETHODIMP
  389. CTransformFilter::Pause()
  390. {
  391.     CAutoLock lck(&m_csFilter);
  392.     HRESULT hr = NOERROR;
  393.     if (m_State == State_Paused) {
  394.         // (This space left deliberately blank)
  395.     }
  396.     // If we have no input pin or it isn't yet connected then when we are
  397.     // asked to pause we deliver an end of stream to the downstream filter.
  398.     // This makes sure that it doesn't sit there forever waiting for
  399.     // samples which we cannot ever deliver without an input connection.
  400.     else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) {
  401.         if (m_pOutput && m_bEOSDelivered == FALSE) {
  402.             m_pOutput->DeliverEndOfStream();
  403.             m_bEOSDelivered = TRUE;
  404.         }
  405.         m_State = State_Paused;
  406.     }
  407.     // We may have an input connection but no output connection
  408.     // However, if we have an input pin we do have an output pin
  409.     else if (m_pOutput->IsConnected() == FALSE) {
  410.         m_State = State_Paused;
  411.     }
  412.     else {
  413. if (m_State == State_Stopped) {
  414.     // allow a class derived from CTransformFilter
  415.     // to know about starting and stopping streaming
  416.             CAutoLock lck2(&m_csReceive);
  417.     hr = StartStreaming();
  418. }
  419. if (SUCCEEDED(hr)) {
  420.     hr = CBaseFilter::Pause();
  421. }
  422.     }
  423.     m_bSampleSkipped = FALSE;
  424.     m_bQualityChanged = FALSE;
  425.     return hr;
  426. }
  427. HRESULT
  428. CTransformFilter::NewSegment(
  429.     REFERENCE_TIME tStart,
  430.     REFERENCE_TIME tStop,
  431.     double dRate)
  432. {
  433.     if (m_pOutput != NULL) {
  434.         return m_pOutput->DeliverNewSegment(tStart, tStop, dRate);
  435.     }
  436.     return S_OK;
  437. }
  438. // Check streaming status
  439. HRESULT
  440. CTransformInputPin::CheckStreaming()
  441. {
  442.     ASSERT(m_pTransformFilter->m_pOutput != NULL);
  443.     if (!m_pTransformFilter->m_pOutput->IsConnected()) {
  444.         return VFW_E_NOT_CONNECTED;
  445.     } else {
  446.         //  Shouldn't be able to get any data if we're not connected!
  447.         ASSERT(IsConnected());
  448.         //  we're flushing
  449.         if (m_bFlushing) {
  450.             return S_FALSE;
  451.         }
  452.         //  Don't process stuff in Stopped state
  453.         if (IsStopped()) {
  454.             return VFW_E_WRONG_STATE;
  455.         }
  456.         if (m_bRunTimeError) {
  457.          return VFW_E_RUNTIME_ERROR;
  458.         }
  459.         return S_OK;
  460.     }
  461. }
  462. // =================================================================
  463. // Implements the CTransformInputPin class
  464. // =================================================================
  465. // constructor
  466. CTransformInputPin::CTransformInputPin(
  467.     TCHAR *pObjectName,
  468.     CTransformFilter *pTransformFilter,
  469.     HRESULT * phr,
  470.     LPCWSTR pName)
  471.     : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
  472. {
  473.     DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
  474.     m_pTransformFilter = pTransformFilter;
  475. }
  476. #ifdef UNICODE
  477. CTransformInputPin::CTransformInputPin(
  478.     CHAR *pObjectName,
  479.     CTransformFilter *pTransformFilter,
  480.     HRESULT * phr,
  481.     LPCWSTR pName)
  482.     : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
  483. {
  484.     DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
  485.     m_pTransformFilter = pTransformFilter;
  486. }
  487. #endif
  488. // provides derived filter a chance to grab extra interfaces
  489. HRESULT
  490. CTransformInputPin::CheckConnect(IPin *pPin)
  491. {
  492.     HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin);
  493.     if (FAILED(hr)) {
  494.      return hr;
  495.     }
  496.     return CBaseInputPin::CheckConnect(pPin);
  497. }
  498. // provides derived filter a chance to release it's extra interfaces
  499. HRESULT
  500. CTransformInputPin::BreakConnect()
  501. {
  502.     //  Can't disconnect unless stopped
  503.     ASSERT(IsStopped());
  504.     m_pTransformFilter->BreakConnect(PINDIR_INPUT);
  505.     return CBaseInputPin::BreakConnect();
  506. }
  507. // Let derived class know when the input pin is connected
  508. HRESULT
  509. CTransformInputPin::CompleteConnect(IPin *pReceivePin)
  510. {
  511.     HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
  512.     if (FAILED(hr)) {
  513.         return hr;
  514.     }
  515.     return CBaseInputPin::CompleteConnect(pReceivePin);
  516. }
  517. // check that we can support a given media type
  518. HRESULT
  519. CTransformInputPin::CheckMediaType(const CMediaType* pmt)
  520. {
  521.     // Check the input type
  522.     HRESULT hr = m_pTransformFilter->CheckInputType(pmt);
  523.     if (S_OK != hr) {
  524.         return hr;
  525.     }
  526.     // if the output pin is still connected, then we have
  527.     // to check the transform not just the input format
  528.     if ((m_pTransformFilter->m_pOutput != NULL) &&
  529.         (m_pTransformFilter->m_pOutput->IsConnected())) {
  530.             return m_pTransformFilter->CheckTransform(
  531.                       pmt,
  532.       &m_pTransformFilter->m_pOutput->CurrentMediaType());
  533.     } else {
  534.         return hr;
  535.     }
  536. }
  537. // set the media type for this connection
  538. HRESULT
  539. CTransformInputPin::SetMediaType(const CMediaType* mtIn)
  540. {
  541.     // Set the base class media type (should always succeed)
  542.     HRESULT hr = CBasePin::SetMediaType(mtIn);
  543.     if (FAILED(hr)) {
  544.         return hr;
  545.     }
  546.     // check the transform can be done (should always succeed)
  547.     ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn)));
  548.     return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn);
  549. }
  550. // =================================================================
  551. // Implements IMemInputPin interface
  552. // =================================================================
  553. // provide EndOfStream that passes straight downstream
  554. // (there is no queued data)
  555. STDMETHODIMP
  556. CTransformInputPin::EndOfStream(void)
  557. {
  558.     CAutoLock lck(&m_pTransformFilter->m_csReceive);
  559.     HRESULT hr = CheckStreaming();
  560.     if (S_OK == hr) {
  561.        hr = m_pTransformFilter->EndOfStream();
  562.     }
  563.     return hr;
  564. }
  565. // enter flushing state. Call default handler to block Receives, then
  566. // pass to overridable method in filter
  567. STDMETHODIMP
  568. CTransformInputPin::BeginFlush(void)
  569. {
  570.     CAutoLock lck(&m_pTransformFilter->m_csFilter);
  571.     //  Are we actually doing anything?
  572.     ASSERT(m_pTransformFilter->m_pOutput != NULL);
  573.     if (!IsConnected() ||
  574.         !m_pTransformFilter->m_pOutput->IsConnected()) {
  575.         return VFW_E_NOT_CONNECTED;
  576.     }
  577.     HRESULT hr = CBaseInputPin::BeginFlush();
  578.     if (FAILED(hr)) {
  579.      return hr;
  580.     }
  581.     return m_pTransformFilter->BeginFlush();
  582. }
  583. // leave flushing state.
  584. // Pass to overridable method in filter, then call base class
  585. // to unblock receives (finally)
  586. STDMETHODIMP
  587. CTransformInputPin::EndFlush(void)
  588. {
  589.     CAutoLock lck(&m_pTransformFilter->m_csFilter);
  590.     //  Are we actually doing anything?
  591.     ASSERT(m_pTransformFilter->m_pOutput != NULL);
  592.     if (!IsConnected() ||
  593.         !m_pTransformFilter->m_pOutput->IsConnected()) {
  594.         return VFW_E_NOT_CONNECTED;
  595.     }
  596.     HRESULT hr = m_pTransformFilter->EndFlush();
  597.     if (FAILED(hr)) {
  598.         return hr;
  599.     }
  600.     return CBaseInputPin::EndFlush();
  601. }
  602. // here's the next block of data from the stream.
  603. // AddRef it yourself if you need to hold it beyond the end
  604. // of this call.
  605. HRESULT
  606. CTransformInputPin::Receive(IMediaSample * pSample)
  607. {
  608.     HRESULT hr;
  609.     CAutoLock lck(&m_pTransformFilter->m_csReceive);
  610.     ASSERT(pSample);
  611.     // check all is well with the base class
  612.     hr = CBaseInputPin::Receive(pSample);
  613.     if (S_OK == hr) {
  614.         hr = m_pTransformFilter->Receive(pSample);
  615.     }
  616.     return hr;
  617. }
  618. // override to pass downstream
  619. STDMETHODIMP
  620. CTransformInputPin::NewSegment(
  621.     REFERENCE_TIME tStart,
  622.     REFERENCE_TIME tStop,
  623.     double dRate)
  624. {
  625.     //  Save the values in the pin
  626.     CBasePin::NewSegment(tStart, tStop, dRate);
  627.     return m_pTransformFilter->NewSegment(tStart, tStop, dRate);
  628. }
  629. // =================================================================
  630. // Implements the CTransformOutputPin class
  631. // =================================================================
  632. // constructor
  633. CTransformOutputPin::CTransformOutputPin(
  634.     TCHAR *pObjectName,
  635.     CTransformFilter *pTransformFilter,
  636.     HRESULT * phr,
  637.     LPCWSTR pPinName)
  638.     : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
  639.       m_pPosition(NULL)
  640. {
  641.     DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
  642.     m_pTransformFilter = pTransformFilter;
  643. }
  644. #ifdef UNICODE
  645. CTransformOutputPin::CTransformOutputPin(
  646.     CHAR *pObjectName,
  647.     CTransformFilter *pTransformFilter,
  648.     HRESULT * phr,
  649.     LPCWSTR pPinName)
  650.     : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
  651.       m_pPosition(NULL)
  652. {
  653.     DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
  654.     m_pTransformFilter = pTransformFilter;
  655. }
  656. #endif
  657. // destructor
  658. CTransformOutputPin::~CTransformOutputPin()
  659. {
  660.     DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin")));
  661.     if (m_pPosition) m_pPosition->Release();
  662. }
  663. // overriden to expose IMediaPosition and IMediaSeeking control interfaces
  664. STDMETHODIMP
  665. CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  666. {
  667.     CheckPointer(ppv,E_POINTER);
  668.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  669.     *ppv = NULL;
  670.     if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
  671.         // we should have an input pin by now
  672.         ASSERT(m_pTransformFilter->m_pInput != NULL);
  673.         if (m_pPosition == NULL) {
  674.             HRESULT hr = CreatePosPassThru(
  675.                              GetOwner(),
  676.                              FALSE,
  677.                              (IPin *)m_pTransformFilter->m_pInput,
  678.                              &m_pPosition);
  679.             if (FAILED(hr)) {
  680.                 return hr;
  681.             }
  682.         }
  683.         return m_pPosition->QueryInterface(riid, ppv);
  684.     } else {
  685.         return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
  686.     }
  687. }
  688. // provides derived filter a chance to grab extra interfaces
  689. HRESULT
  690. CTransformOutputPin::CheckConnect(IPin *pPin)
  691. {
  692.     // we should have an input connection first
  693.     ASSERT(m_pTransformFilter->m_pInput != NULL);
  694.     if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
  695.     return E_UNEXPECTED;
  696.     }
  697.     HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin);
  698.     if (FAILED(hr)) {
  699.     return hr;
  700.     }
  701.     return CBaseOutputPin::CheckConnect(pPin);
  702. }
  703. // provides derived filter a chance to release it's extra interfaces
  704. HRESULT
  705. CTransformOutputPin::BreakConnect()
  706. {
  707.     //  Can't disconnect unless stopped
  708.     ASSERT(IsStopped());
  709.     m_pTransformFilter->BreakConnect(PINDIR_OUTPUT);
  710.     return CBaseOutputPin::BreakConnect();
  711. }
  712. // Let derived class know when the output pin is connected
  713. HRESULT
  714. CTransformOutputPin::CompleteConnect(IPin *pReceivePin)
  715. {
  716.     HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
  717.     if (FAILED(hr)) {
  718.         return hr;
  719.     }
  720.     return CBaseOutputPin::CompleteConnect(pReceivePin);
  721. }
  722. // check a given transform - must have selected input type first
  723. HRESULT
  724. CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut)
  725. {
  726.     // must have selected input first
  727.     ASSERT(m_pTransformFilter->m_pInput != NULL);
  728.     if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
  729.         return E_INVALIDARG;
  730.     }
  731.     return m_pTransformFilter->CheckTransform(
  732.     &m_pTransformFilter->m_pInput->CurrentMediaType(),
  733.     pmtOut);
  734. }
  735. // called after we have agreed a media type to actually set it in which case
  736. // we run the CheckTransform function to get the output format type again
  737. HRESULT
  738. CTransformOutputPin::SetMediaType(const CMediaType* pmtOut)
  739. {
  740.     HRESULT hr = NOERROR;
  741.     ASSERT(m_pTransformFilter->m_pInput != NULL);
  742.     ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid());
  743.     // Set the base class media type (should always succeed)
  744.     hr = CBasePin::SetMediaType(pmtOut);
  745.     if (FAILED(hr)) {
  746.         return hr;
  747.     }
  748. #ifdef DEBUG
  749.     if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter->
  750. m_pInput->CurrentMediaType(),pmtOut))) {
  751. DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type")));
  752. DbgLog((LOG_ERROR,0,TEXT("    that it can't currently transform to.  I hope")));
  753. DbgLog((LOG_ERROR,0,TEXT("    it's smart enough to reconnect its input.")));
  754.     }
  755. #endif
  756.     return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut);
  757. }
  758. // pass the buffer size decision through to the main transform class
  759. HRESULT
  760. CTransformOutputPin::DecideBufferSize(
  761.     IMemAllocator * pAllocator,
  762.     ALLOCATOR_PROPERTIES* pProp)
  763. {
  764.     return m_pTransformFilter->DecideBufferSize(pAllocator, pProp);
  765. }
  766. // return a specific media type indexed by iPosition
  767. HRESULT
  768. CTransformOutputPin::GetMediaType(
  769.     int iPosition,
  770.     CMediaType *pMediaType)
  771. {
  772.     ASSERT(m_pTransformFilter->m_pInput != NULL);
  773.     //  We don't have any media types if our input is not connected
  774.     if (m_pTransformFilter->m_pInput->IsConnected()) {
  775.         return m_pTransformFilter->GetMediaType(iPosition,pMediaType);
  776.     } else {
  777.         return VFW_S_NO_MORE_ITEMS;
  778.     }
  779. }
  780. // Override this if you can do something constructive to act on the
  781. // quality message.  Consider passing it upstream as well
  782. // Pass the quality mesage on upstream.
  783. STDMETHODIMP
  784. CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q)
  785. {
  786.     UNREFERENCED_PARAMETER(pSender);
  787.     ValidateReadPtr(pSender,sizeof(IBaseFilter));
  788.     // First see if we want to handle this ourselves
  789.     HRESULT hr = m_pTransformFilter->AlterQuality(q);
  790.     if (hr!=S_FALSE) {
  791.         return hr;        // either S_OK or a failure
  792.     }
  793.     // S_FALSE means we pass the message on.
  794.     // Find the quality sink for our input pin and send it there
  795.     ASSERT(m_pTransformFilter->m_pInput != NULL);
  796.     return m_pTransformFilter->m_pInput->PassNotify(q);
  797. } // Notify
  798. // the following removes a very large number of level 4 warnings from the microsoft
  799. // compiler output, which are not useful at all in this case.
  800. #pragma warning(disable:4514)