home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / transfrm.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-22  |  25.2 KB  |  954 lines

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