home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / directshow / baseclasses / transfrm.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-02  |  27.7 KB  |  1,015 lines

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