home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / inftee.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  40.6 KB  |  1,229 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. #include <streams.h>
  13. #include <initguid.h>
  14. #include <inftee.h>
  15. #include <tchar.h>
  16. #include <stdio.h>
  17.  
  18.  
  19. //----------------------------------------------------------------------------
  20. // setup data
  21. //----------------------------------------------------------------------------
  22.  
  23. AMOVIESETUP_MEDIATYPE sudPinTypes =   { &MEDIATYPE_NULL                    // clsMajorType
  24.                                            , &MEDIASUBTYPE_NULL }  ;       // clsMinorType
  25.  
  26. AMOVIESETUP_PIN psudPins[] = { { L"Input"            // strName
  27.                                , FALSE               // bRendered
  28.                                , FALSE               // bOutput
  29.                                , FALSE               // bZero
  30.                                , FALSE               // bMany
  31.                                , &CLSID_NULL         // clsConnectsToFilter
  32.                                , L"Output"           // strConnectsToPin
  33.                                , 1                   // nTypes
  34.                                , &sudPinTypes }      // lpTypes
  35.                              , { L"Output"           // strName
  36.                                , FALSE               // bRendered
  37.                                , TRUE                // bOutput
  38.                                , FALSE               // bZero
  39.                                , FALSE               // bMany
  40.                                , &CLSID_NULL         // clsConnectsToFilter
  41.                                , L"Input"            // strConnectsToPin
  42.                                , 1                   // nTypes
  43.                                , &sudPinTypes } };   // lpTypes
  44.  
  45.  
  46. AMOVIESETUP_FILTER sudInfTee = { &CLSID_Tee                         // clsID
  47.                                   , L"Infinite Pin Tee"             // strName
  48.                                   , MERIT_DO_NOT_USE                // dwMerit
  49.                                   , 2                               // nPins
  50.                                   , psudPins };                     // lpPin
  51.  
  52. //----------------------------------------------------------------------------
  53. // Creator function for the class ID
  54. //----------------------------------------------------------------------------
  55. CFactoryTemplate g_Templates [1] = { {L"Infinite Pin Tee", &CLSID_Tee, CTee::CreateInstance}} ;
  56.  
  57. int g_cTemplates = sizeof (g_Templates) / sizeof (g_Templates[0]) ;
  58.  
  59.  
  60. CUnknown *CTee::CreateInstance (LPUNKNOWN pUnk, HRESULT *phr)
  61. {
  62.     return new CTee (NAME("Infinite Tee Filter"), pUnk, phr) ;
  63. }
  64. //----------------------------------------------------------------------------
  65. // CTee constructor
  66. //----------------------------------------------------------------------------
  67. #pragma warning(disable:4355) // using THIS pointer in constructor for base objects
  68. CTee::CTee (TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr)
  69.  : m_lCanSeek (TRUE),
  70.    m_pAllocator (NULL),
  71.    m_OutputPinsList (NAME("Tee Output Pins list"), DEFAULTCACHE),
  72.    m_NumOutputPins (0),
  73.    m_NextOutputPinNumber (0),
  74.    m_Input (NAME("Input Pin"), this, phr, L"Input"),
  75.    CBaseFilter (NAME("Infinite Pin Tee Filter"), pUnk, this, CLSID_Tee, phr)
  76. {
  77.     DbgLog((LOG_TRACE,2,TEXT("CTee constructor")));
  78.  
  79.     ASSERT (phr) ;
  80.  
  81.     // create a single output pin at this time.
  82.     InitOutputPinsList () ;
  83.  
  84.     CTeeOutputPin *pOutputPin = CreateNextOutputPin (this) ;
  85.  
  86.     if (pOutputPin != NULL )
  87.     {
  88.         m_NumOutputPins++ ;
  89.         m_OutputPinsList.AddTail (pOutputPin) ;
  90.     }
  91.  
  92. }
  93. #pragma warning(default:4355)
  94.  
  95. //----------------------------------------------------------------------------
  96. // CTee destructor
  97. //----------------------------------------------------------------------------
  98. CTee::~CTee()
  99. {
  100.     DbgLog((LOG_TRACE,2,TEXT("CTee destructor")));
  101.     InitOutputPinsList () ;
  102. }
  103.  
  104. //----------------------------------------------------------------------------
  105. // GetSetupData
  106. //----------------------------------------------------------------------------
  107. LPAMOVIESETUP_FILTER CTee::GetSetupData()
  108. {
  109.   return &sudInfTee;
  110. }
  111.  
  112. //----------------------------------------------------------------------------
  113. // CTee::GetPinCount
  114. //----------------------------------------------------------------------------
  115. int CTee::GetPinCount ()
  116. {
  117.     DbgLog((LOG_TRACE,2,TEXT("CTee::GetPinCount")));
  118.     return 1+m_NumOutputPins ;
  119. }
  120.  
  121. //----------------------------------------------------------------------------
  122. // CTee::GetPin
  123. //----------------------------------------------------------------------------
  124. CBasePin *CTee::GetPin (int n)
  125. {
  126.     DbgLog((LOG_TRACE,2,TEXT("CTee::GetPin: PinNumber = %d"), n));
  127.  
  128.     //n == 0 is for input pin. The others are for the output pins
  129.     if (n == 0)
  130.         return &m_Input ;
  131.  
  132.     //output pins
  133.  
  134.     // return the output pin at position (n-1) [zero based]
  135.     return GetPinNFromList (n-1) ;
  136. }
  137. //----------------------------------------------------------------------------
  138. // CTee::InitOutputPinsList () (HELPER FUNCTION)
  139. //----------------------------------------------------------------------------
  140. void CTee::InitOutputPinsList ()
  141. {
  142.     POSITION pos = m_OutputPinsList.GetHeadPosition () ;
  143.     while (pos)
  144.     {
  145.         CTeeOutputPin *pOutputPin = m_OutputPinsList.GetNext (pos) ;
  146.         ASSERT (pOutputPin->m_pOutputQueue == NULL) ;
  147.         pOutputPin->Release() ;
  148.     }
  149.     m_NumOutputPins = 0 ;
  150.     m_OutputPinsList.RemoveAll () ;
  151. }
  152. //----------------------------------------------------------------------------
  153. // CTee::CreateNextOutputPin (HELPER FUNCTION)
  154. //----------------------------------------------------------------------------
  155. CTeeOutputPin *CTee::CreateNextOutputPin (CTee *pTee)
  156. {
  157.     WCHAR szbuf[20] ;                          // scratch buffer
  158.     m_NextOutputPinNumber++ ;                  // next number to use for pin
  159.  
  160.     swprintf (szbuf, L"Output%d", m_NextOutputPinNumber) ;
  161.  
  162.     HRESULT hr = NOERROR ;
  163.     CTeeOutputPin *pPin = new CTeeOutputPin (NAME("Tee Output"), pTee,
  164.                          &hr, szbuf,
  165.                          m_NextOutputPinNumber) ;
  166.     if (pPin)
  167.         pPin->AddRef () ;
  168.  
  169.     if (FAILED (hr) && pPin != NULL)
  170.     {
  171.         pPin->Release () ;
  172.         pPin = NULL ;
  173.     }
  174.     return pPin ;
  175. }
  176. //----------------------------------------------------------------------------
  177. // CTee::DeleteOutputPin -- HELPER FUNCTION
  178. //----------------------------------------------------------------------------
  179. void CTee::DeleteOutputPin (CTeeOutputPin *pPin)
  180. {
  181.     POSITION pos = m_OutputPinsList.GetHeadPosition () ;
  182.     while (pos)
  183.     {
  184.         POSITION posold = pos ;         // remember this position
  185.         CTeeOutputPin *pOutputPin = m_OutputPinsList.GetNext (pos) ;
  186.         if (pOutputPin == pPin)
  187.         {
  188.  
  189.             // if this pin holds the seek interface release it.
  190.             if (pPin->m_bHoldsSeek)
  191.             {
  192.                 InterlockedExchange (&m_lCanSeek, FALSE) ;
  193.                 pPin->m_bHoldsSeek = FALSE ;
  194.                 delete pPin->m_pPosition ;
  195.             }
  196.  
  197.             m_OutputPinsList.Remove (posold) ;
  198.             ASSERT (pOutputPin->m_pOutputQueue == NULL) ;
  199.             delete pPin ;
  200.             m_NumOutputPins-- ;
  201.             IncrementPinVersion();
  202.             break ;
  203.         }
  204.     }
  205. }
  206. //----------------------------------------------------------------------------
  207. // CTee::GetNumFreePins -- HELPER FUNCTION
  208. //----------------------------------------------------------------------------
  209. int CTee::GetNumFreePins ()
  210. {
  211.     int n = 0 ;
  212.     POSITION pos = m_OutputPinsList.GetHeadPosition () ;
  213.     while (pos)
  214.     {
  215.         CTeeOutputPin *pOutputPin = m_OutputPinsList.GetNext (pos) ;
  216.         if (pOutputPin->m_Connected == NULL)
  217.             n++ ;
  218.     }
  219.     return n ;
  220. }
  221. //----------------------------------------------------------------------------
  222. // CTee::GetPinNFromList (HELPER FUNCTION)
  223. //----------------------------------------------------------------------------
  224. CTeeOutputPin *CTee::GetPinNFromList (int n)
  225. {
  226.     //validate the position being asked for
  227.     if (n >= m_NumOutputPins)
  228.         return NULL ;
  229.  
  230.     // get the head of the list
  231.     POSITION pos = m_OutputPinsList.GetHeadPosition () ;
  232.  
  233.  
  234.     n++ ;       //make the number 1 based
  235.  
  236.     CTeeOutputPin *pOutputPin ;
  237.     while (n)
  238.     {
  239.         pOutputPin = m_OutputPinsList.GetNext (pos) ;
  240.         n-- ;
  241.     }
  242.     return pOutputPin ;
  243. }
  244. //----------------------------------------------------------------------------
  245. // CTee::FindPin (Persistent pinid support)
  246. //----------------------------------------------------------------------------
  247. STDMETHODIMP CTee::FindPin(LPCWSTR pwszPinId, IPin **ppPin)
  248. {
  249.     // There is a plan for pin 1 to pass on quality messages where other pins don't
  250.     // so being the first pin matters.
  251.     *ppPin = GetPin(WstrToInt(pwszPinId));
  252.     if (*ppPin==NULL){
  253.         return VFW_E_NOT_FOUND;
  254.     }
  255.     (*ppPin)->AddRef();
  256.     return NOERROR;
  257.  
  258. }
  259. //----------------------------------------------------------------------------
  260. // CTeeOutputPin::QueryId (Persistent pinid support)
  261. //----------------------------------------------------------------------------
  262. STDMETHODIMP CTeeOutputPin::QueryId(LPWSTR * Id)
  263. {
  264.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition () ;
  265.     int nPin = 1;   // the first output pin is number 1
  266.  
  267.     // ?? UNUSED -- CTeeOutputPin *pOutputPin ;
  268.     while (pos!=NULL)
  269.     {
  270.         IPin* pip = (IPin*)m_pTee->m_OutputPinsList.GetNext(pos);
  271.     // if this is ME then I have found myself
  272.         if (pip==(IPin*)this) {
  273.             *Id = (LPWSTR)CoTaskMemAlloc(8);
  274.             if (*Id==NULL) {
  275.                return E_OUTOFMEMORY;
  276.             }
  277.             IntToWstr(nPin, *Id);
  278.             return NOERROR;
  279.         }
  280.         ++nPin;
  281.     }
  282.     return VFW_E_NOT_FOUND;
  283. }
  284.  
  285. //----------------------------------------------------------------------------
  286. // CTeeInputPin constructor
  287. //----------------------------------------------------------------------------
  288.  
  289. CTeeInputPin::CTeeInputPin (TCHAR *pName, CTee *pTee, HRESULT *phr,
  290.                            LPCWSTR pPinName)
  291.  :  CBaseInputPin (pName, pTee, pTee, phr, pPinName),
  292.     m_pTee (pTee),
  293.     m_bInsideCheckMediaType (FALSE)
  294. {
  295.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin constructor")));
  296.     ASSERT (pTee) ;
  297. }
  298.  
  299. //----------------------------------------------------------------------------
  300. // CTeeInputPin destructor
  301. //----------------------------------------------------------------------------
  302.  
  303. CTeeInputPin::~CTeeInputPin ()
  304. {
  305.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin destructor")));
  306.     ASSERT (m_pTee->m_pAllocator == NULL) ;
  307. }
  308.  
  309. //----------------------------------------------------------------------------
  310. // DisplayMediaType -- DEBUG ONLY HELPER FUNCTION
  311. //----------------------------------------------------------------------------
  312.  
  313. void DisplayMediaType(TCHAR *pDescription,const CMediaType *pmt)
  314. {
  315. #ifdef DEBUG
  316.  
  317.     // Dump the GUID types and a short description
  318.  
  319.     DbgLog((LOG_TRACE,2,TEXT("")));
  320.     DbgLog((LOG_TRACE,2,TEXT("%s"),pDescription));
  321.     DbgLog((LOG_TRACE,2,TEXT("")));
  322.     DbgLog((LOG_TRACE,2,TEXT("Media Type Description")));
  323.     DbgLog((LOG_TRACE,2,TEXT("Major type %s"),GuidNames[*pmt->Type()]));
  324.     DbgLog((LOG_TRACE,2,TEXT("Subtype %s"),GuidNames[*pmt->Subtype()]));
  325.     DbgLog((LOG_TRACE,2,TEXT("Subtype description %s"),GetSubtypeName(pmt->Subtype())));
  326.     DbgLog((LOG_TRACE,2,TEXT("Format size %d"),pmt->cbFormat));
  327.  
  328.     // Dump the generic media types */
  329.  
  330.     DbgLog((LOG_TRACE,2,TEXT("Fixed size sample %d"),pmt->IsFixedSize()));
  331.     DbgLog((LOG_TRACE,2,TEXT("Temporal compression %d"),pmt->IsTemporalCompressed()));
  332.     DbgLog((LOG_TRACE,2,TEXT("Sample size %d"),pmt->GetSampleSize()));
  333.  
  334. #endif
  335. }
  336.  
  337. //----------------------------------------------------------------------------
  338. // CTeeInputPin::CheckMediaType
  339. //----------------------------------------------------------------------------
  340. HRESULT CTeeInputPin::CheckMediaType (const CMediaType *pmt)
  341. {
  342.  
  343.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::CheckMediaType pmt = %lx"), pmt));
  344.  
  345.     CAutoLock lock_it (m_pLock) ;
  346.  
  347.     // If we are already inside checkmedia type for this pin, return NOERROR
  348.     // It is possble to hookup two of the tee filters and some other filter
  349.     // like the video effects sample to get into this situation. If we
  350.     // do not detect this, we will loop till we blow the stack
  351.     if (m_bInsideCheckMediaType == TRUE)
  352.         return NOERROR ;
  353.     m_bInsideCheckMediaType = TRUE ;
  354.  
  355.     HRESULT hr = NOERROR ;
  356.  
  357.     // display the type of the media for debugging perposes.
  358.     DisplayMediaType (TEXT("Input Pin Checking"), pmt) ;
  359.  
  360.  
  361.     // The media types that we can support are entirely dependent on the
  362.     // downstream connections. If we have downstream connections, we should
  363.     // check with them.
  364.  
  365.     // walk through the list calling each output pin.
  366.  
  367.     int n = m_pTee->m_NumOutputPins ;        // number of output pins connected
  368.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  369.  
  370.     while (n)
  371.     {
  372.  
  373.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  374.         if (pOutputPin != NULL)
  375.         {
  376.             if (pOutputPin->m_Connected != NULL)
  377.             {
  378.                 // The pin is connected, check its peer
  379.                 hr = pOutputPin->m_Connected->QueryAccept (pmt) ;
  380.                 if (hr != NOERROR)
  381.                 {
  382.                     m_bInsideCheckMediaType = FALSE ;
  383.                     return VFW_E_TYPE_NOT_ACCEPTED ;
  384.                 }
  385.             }
  386.         }
  387.         else
  388.         {
  389.             // This should never happen. We should have as many pins as the
  390.             // count says we have
  391.             ASSERT (FALSE) ;
  392.         }
  393.         n-- ;
  394.     }
  395.  
  396.     // either all the downstream pins have accepted or there are none.
  397.     m_bInsideCheckMediaType = FALSE ;
  398.     return NOERROR ;
  399. }
  400.  
  401. //----------------------------------------------------------------------------
  402. // CTeeInputPin::SetMediaType
  403. //----------------------------------------------------------------------------
  404. HRESULT CTeeInputPin::SetMediaType (const CMediaType *pmt)
  405. {
  406.  
  407.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::SetMediaType pmt = %lx"), pmt));
  408.  
  409.     CAutoLock lock_it (m_pLock) ;
  410.  
  411.     HRESULT hr = NOERROR ;
  412.  
  413.     // make sure that the base class likes it
  414.     hr = CBaseInputPin::SetMediaType (pmt) ;
  415.     if (FAILED (hr))
  416.         return hr ;
  417.  
  418.     ASSERT (m_Connected != NULL) ;
  419.  
  420.     return NOERROR ;
  421. }
  422.  
  423. //----------------------------------------------------------------------------
  424. // CTeeInputPin::BreakConnect
  425. //----------------------------------------------------------------------------
  426. HRESULT CTeeInputPin::BreakConnect ()
  427. {
  428.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::BreakConnect")));
  429.  
  430.     // release any allocator that we are holding.
  431.     if (m_pTee->m_pAllocator)
  432.     {
  433.         m_pTee->m_pAllocator->Release () ;
  434.         m_pTee->m_pAllocator = NULL ;
  435.     }
  436.  
  437.     return NOERROR ;                // this function always succeedes.
  438. }
  439.  
  440. //----------------------------------------------------------------------------
  441. // CTeeInputPin::NotifyAllocator
  442. //----------------------------------------------------------------------------
  443. STDMETHODIMP
  444. CTeeInputPin::NotifyAllocator (IMemAllocator *pAllocator, BOOL bReadOnly)
  445. {
  446.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::NotifyAllocator ptr = %lx"), pAllocator));
  447.  
  448.     CAutoLock lock_it (m_pLock) ;
  449.  
  450.     if (pAllocator == NULL)
  451.         return E_FAIL ;             
  452.  
  453.     // free the old allocator if any.
  454.     if (m_pTee->m_pAllocator)
  455.         m_pTee->m_pAllocator->Release () ;
  456.  
  457.     // store away the new allocator
  458.     pAllocator->AddRef () ;             // since we are stashing away the ptr
  459.     m_pTee->m_pAllocator = pAllocator ; // save the new allocator
  460.  
  461.     // notify the base class about the allocator.
  462.     return CBaseInputPin::NotifyAllocator (pAllocator,bReadOnly) ;
  463. }
  464.  
  465. //----------------------------------------------------------------------------
  466. // CTeeInputPin::EndOfStream
  467. //----------------------------------------------------------------------------
  468. HRESULT CTeeInputPin::EndOfStream ()
  469. {
  470.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::EndOfStream")));
  471.  
  472.     CAutoLock lock_it (m_pLock) ;
  473.  
  474.     ASSERT (m_pTee->m_NumOutputPins) ;
  475.  
  476.     HRESULT hr = NOERROR ;
  477.  
  478.     // walk through the output pins list, sending the message downstream.
  479.  
  480.     int n = m_pTee->m_NumOutputPins ;
  481.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  482.     while (n)
  483.     {
  484.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  485.         if (pOutputPin != NULL)
  486.         {
  487.             // pass call to it.
  488.             hr = pOutputPin->DeliverEndOfStream () ;
  489.             if (FAILED (hr))
  490.                 return hr ;
  491.         }
  492.         else
  493.         {
  494.             // This should never happen. We should have as many pins as the
  495.             // count says we have
  496.             ASSERT (FALSE) ;
  497.         }
  498.         n-- ;
  499.     }
  500.     // !!! Why are we NOT passing this on to the base pin when we do it for
  501.     // BeginFlush and EndFlush
  502.     return (NOERROR) ;
  503. }
  504.  
  505. //----------------------------------------------------------------------------
  506. // CTeeInputPin::BeginFlush
  507. //----------------------------------------------------------------------------
  508. HRESULT CTeeInputPin::BeginFlush ()
  509. {
  510.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::BeginFlush")));
  511.  
  512.     CAutoLock lock_it (m_pLock) ;
  513.  
  514.     ASSERT (m_pTee->m_NumOutputPins) ;
  515.  
  516.     HRESULT hr = NOERROR ;
  517.  
  518.     // walk through the output pins list, sending the message downstream.
  519.  
  520.     int n = m_pTee->m_NumOutputPins ;
  521.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  522.     while (n)
  523.     {
  524.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  525.         if (pOutputPin != NULL)
  526.         {
  527.             // pass call to it.
  528.             hr = pOutputPin->DeliverBeginFlush () ;
  529.             if (FAILED (hr))
  530.                 return hr ;
  531.         }
  532.         else
  533.         {
  534.             // This should never happen. We should have as many pins as the
  535.             // count says we have
  536.             ASSERT (FALSE) ;
  537.         }
  538.         n-- ;
  539.     }
  540.     return CBaseInputPin::BeginFlush () ;
  541. }
  542.  
  543. //----------------------------------------------------------------------------
  544. // CTeeInputPin::EndFlush
  545. //----------------------------------------------------------------------------
  546. HRESULT CTeeInputPin::EndFlush ()
  547. {
  548.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::EndFlush")));
  549.  
  550.     CAutoLock lock_it (m_pLock) ;
  551.  
  552.     ASSERT (m_pTee->m_NumOutputPins) ;
  553.  
  554.     HRESULT hr = NOERROR ;
  555.  
  556.     // walk through the output pins list, sending the message downstream.
  557.  
  558.     int n = m_pTee->m_NumOutputPins ;
  559.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  560.     while (n)
  561.     {
  562.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  563.         if (pOutputPin != NULL)
  564.         {
  565.             // pass call to it.
  566.             hr = pOutputPin->DeliverEndFlush () ;
  567.             if (FAILED (hr))
  568.                 return hr ;
  569.         }
  570.         else
  571.         {
  572.             // This should never happen. We should have as many pins as the
  573.             // count says we have
  574.             ASSERT (FALSE) ;
  575.         }
  576.         n-- ;
  577.     }
  578.     return CBaseInputPin::EndFlush () ;
  579. }
  580. //----------------------------------------------------------------------------
  581. // CTeeInputPin::Receive
  582. //----------------------------------------------------------------------------
  583. HRESULT CTeeInputPin::Receive (IMediaSample *pSample)
  584. {
  585.     DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::pSample ptr = %lx"), pSample));
  586.  
  587.     CAutoLock lock_it (m_pLock) ;
  588.  
  589.     // check that all is well with the base class
  590.     HRESULT hr = NOERROR ;
  591.     hr = CBaseInputPin::Receive (pSample) ;
  592.     if (hr != NOERROR)
  593.         return hr ;
  594.  
  595.     // walk through the output pins list, delivering the buffer to the out pins
  596.  
  597.     int n = m_pTee->m_NumOutputPins ;
  598.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  599.     while (n)
  600.     {
  601.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  602.         if (pOutputPin != NULL)
  603.         {
  604.             // pass call to it.
  605.             hr = pOutputPin->Deliver (pSample) ;
  606.             if (hr != NOERROR)
  607.                 return hr ;
  608.         }
  609.         else
  610.         {
  611.             // This should never happen. We should have as many pins as the
  612.             // count says we have
  613.             ASSERT (FALSE) ;
  614.         }
  615.         n-- ;
  616.     }
  617.     return NOERROR ;
  618. }
  619.  
  620. //
  621. // End of connection negotiation. A good time to force all the
  622. // output pins of differing types to be reconnected.
  623. HRESULT
  624. CTeeInputPin::CompleteConnect(IPin *pReceivePin)
  625. {
  626.  
  627.     HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
  628.     if (FAILED(hr)) {
  629.         return hr;
  630.     }
  631.  
  632.     // now we are definitely connected. Force any output pins to use our
  633.     // type.
  634.  
  635.     int n = m_pTee->m_NumOutputPins ;        // number of output pins connected
  636.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  637.  
  638.     while (n)
  639.     {
  640.  
  641.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  642.         if (pOutputPin != NULL)
  643.         {
  644.             // check with downstream pin
  645.             if (pOutputPin->m_Connected != NULL)
  646.             {
  647.                 if (m_mt != pOutputPin->m_mt)
  648.                     m_pTee->m_pGraph->Reconnect (pOutputPin) ;
  649.             }
  650.         }
  651.         else
  652.         {
  653.             // This should never happen. We should have as many pins as the
  654.             // count says we have
  655.  
  656.             //!!! then why don't we just use List.GetCount() ?
  657.             ASSERT (FALSE) ;
  658.         }
  659.         n-- ;
  660.     }
  661.     return S_OK;
  662. }
  663.  
  664. //----------------------------------------------------------------------------
  665. // CTeeOutputPin constructor
  666. //----------------------------------------------------------------------------
  667. CTeeOutputPin::CTeeOutputPin (TCHAR *pName, CTee *pTee, HRESULT *phr,
  668.                             LPCWSTR pPinName, int PinNumber)
  669.  : CBaseOutputPin (pName, pTee, pTee, phr, pPinName) ,
  670.  m_pOutputQueue (NULL),
  671.  m_bHoldsSeek (FALSE),
  672.  m_pPosition (NULL),
  673.  m_pTee (pTee),
  674.  m_cOurRef (0),
  675.  m_bInsideCheckMediaType (FALSE)
  676. {
  677.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin constructor")));
  678.     ASSERT (pTee) ;
  679. }
  680.  
  681. //----------------------------------------------------------------------------
  682. // CTeeOutputPin destructor
  683. //----------------------------------------------------------------------------
  684. CTeeOutputPin::~CTeeOutputPin ()
  685. {
  686.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin destructor")));
  687.     ASSERT (m_pOutputQueue == NULL) ;
  688. }
  689.  
  690. //----------------------------------------------------------------------------
  691. // CTeeOutputPin::NonDelegatingQueryInterface
  692. //
  693. // This function is overwritten to expose IMediaPosition and IMediaSelection
  694. // Note that only one output stream can be allowed to expose this to avoid
  695. // conflicts, the other pins will just return E_NOINTERFACE and therefore
  696. // appear as non seekable streams. We have a LONG value that if exchanged to
  697. // produce a TRUE means that we have the honor. If it exchanges to FALSE then
  698. // someone is already in. If we do get it and error occurs then we reset it
  699. // to TRUE so someone else can get it.
  700. //----------------------------------------------------------------------------
  701. STDMETHODIMP CTeeOutputPin::NonDelegatingQueryInterface (REFIID riid, void **ppv)
  702. {
  703.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::NonDelegatingQI" )));
  704.  
  705.     CheckPointer(ppv,E_POINTER);
  706.     ASSERT (ppv) ;
  707.     *ppv = NULL ;
  708.     HRESULT hr = NOERROR ;
  709.  
  710.     // see what interface the caller is interested in.
  711.     if (riid == IID_IMediaPosition || riid == IID_IMediaSelection)
  712.     {
  713.         if (m_pPosition)
  714.         {
  715.             if (m_bHoldsSeek == FALSE)
  716.                 return E_NOINTERFACE ;
  717.             return m_pPosition->NonDelegatingQueryInterface (riid, ppv) ;
  718.         }
  719.     }
  720.     else
  721.         return CBaseOutputPin::NonDelegatingQueryInterface (riid, ppv) ;
  722.  
  723.     CAutoLock lock_it (m_pLock) ;
  724.     ASSERT (m_pPosition == NULL) ;
  725.     CPosPassThru *pMediaPosition = NULL ;
  726.  
  727.     // try to create a seeking implementation
  728.     if (InterlockedExchange (&m_pTee->m_lCanSeek, FALSE) == FALSE)
  729.         return E_NOINTERFACE ;
  730.  
  731.     // Create implementation of this dynamically as sometimes we may never
  732.     // try and seek. The helper object implements IMediaPosition and also
  733.     // the IMediaSelection control interface and simply takes the calls
  734.     // normally from the downstream filter and passes them upstream
  735.  
  736.     pMediaPosition = new CPosPassThru (NAME("Tee CPosPassThru"), GetOwner(),
  737.                             &hr, (IPin*) &m_pTee->m_Input) ;
  738.     if (pMediaPosition == NULL)
  739.     {
  740.         InterlockedExchange (&m_pTee->m_lCanSeek, TRUE) ;
  741.         return E_OUTOFMEMORY ;
  742.     }
  743.  
  744.     if (FAILED (hr))
  745.     {
  746.         InterlockedExchange (&m_pTee->m_lCanSeek, TRUE) ;
  747.         delete pMediaPosition ;
  748.         return hr ;
  749.     }
  750.  
  751.     m_pPosition = pMediaPosition ;
  752.     m_bHoldsSeek = TRUE ;
  753.     return NonDelegatingQueryInterface (riid, ppv) ;
  754.  
  755. }
  756.  
  757. //----------------------------------------------------------------------------
  758. // CTeeOutputPin::NonDelegatingAddRef
  759. //
  760. // We need override this method so that we can do proper reference counting
  761. // on our output pin. The base class CBasePin does not do any reference
  762. // counting on the pin in RETAIL.
  763. //
  764. // Please refer to the comments for the NonDelegatingRelease method for more
  765. // info on why we need to do this.
  766. //----------------------------------------------------------------------------
  767.  
  768. STDMETHODIMP_(ULONG) CTeeOutputPin::NonDelegatingAddRef()
  769. {
  770.     CAutoLock lock_it (m_pLock) ;
  771.  
  772.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::NonDelegatingAddRef" )));
  773.  
  774. #ifdef DEBUG
  775.     // update the debug only variable maintained by the base class
  776.     m_cRef++ ;
  777.     ASSERT (m_cRef > 0) ;
  778. #endif
  779.  
  780.     // now update our reference count
  781.     m_cOurRef++ ;
  782.     ASSERT (m_cOurRef > 0) ;
  783.     return m_cOurRef ;
  784. }
  785.  
  786. //----------------------------------------------------------------------------
  787. // CTeeOutputPin::NonDelegatingRelease
  788. //
  789. // CTeeOutputPin overrides this class so that we can take the pin out of our
  790. // output pins list and delete it when its reference count drops to 1 and there
  791. // is atleast two free pins.
  792. //
  793. // Note that CreateNextOutputPin holds a reference count on the pin so that
  794. // when the count drops to 1, we know that no one else has the pin.
  795. //
  796. // Moreover, the pin that we are about to delete must be a free pin (or else
  797. // the reference would not have dropped to 1, and we must have atleast one
  798. // other free pin (as the filter always wants to have one more free pin)
  799. //
  800. // Also, since CBasePin::NonDelegatingAddRef passes the call to the owning
  801. // filter, we will have to call Release on the owning filter as well.
  802. //
  803. // Also, note that we maintain our own reference count m_cOurRef as the m_cRef
  804. // variable maintained by CBasePin is debug only.
  805. //
  806. //----------------------------------------------------------------------------
  807. STDMETHODIMP_(ULONG) CTeeOutputPin::NonDelegatingRelease()
  808. {
  809.     CAutoLock lock_it (m_pLock) ;
  810.  
  811.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::NonDelegatingRelease" )));
  812.  
  813. #ifdef DEBUG
  814.     // update the debug only variable in CBasePin
  815.     m_cRef-- ;
  816.     ASSERT(m_cRef >= 0) ;
  817. #endif
  818.  
  819.     // now update our reference count
  820.     m_cOurRef-- ;
  821.     ASSERT(m_cOurRef >= 0) ;
  822.  
  823.  
  824.     // if the reference count on the object has gone to one, remove
  825.     // the pin from our output pins list and physically delete it
  826.     // provided there are atealst two free pins in the list (including
  827.     // this one)
  828.  
  829.     // Also, when the ref count drops to 0, it really means that our
  830.     // filter that is holding one ref count has released it so we
  831.     // should delete the pin as well.
  832.  
  833.     if (m_cOurRef <= 1)
  834.     {
  835.         int n = 2 ;                     // default forces pin deletion
  836.         if (m_cOurRef == 1)
  837.         {
  838.             // walk the list of pins, looking for count of free pins
  839.             n = m_pTee->GetNumFreePins () ;
  840.         }
  841.  
  842.         // if there are two free pins, delete this one.
  843.         // NOTE: normall 
  844.         if (n >= 2 )
  845.         {
  846.             m_cOurRef = 0 ;
  847. #ifdef DEBUG
  848.             m_cRef = 0 ;
  849. #endif
  850.             m_pTee->DeleteOutputPin (this) ;
  851.             return (ULONG) 0 ;
  852.         }
  853.     }
  854.  
  855.  
  856.     return (ULONG) m_cOurRef;
  857. }
  858.  //----------------------------------------------------------------------------
  859. // CTeeOutputPin::DecideBufferSize
  860. //
  861. // This has to be present to override the PURE virtual class base function.
  862. //----------------------------------------------------------------------------
  863. HRESULT CTeeOutputPin::DecideBufferSize (IMemAllocator *pMemAllocator,
  864.                                          ALLOCATOR_PROPERTIES * ppropInputRequest)
  865. {
  866.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DecideBufferSize ptr = %lx"), pMemAllocator));
  867.     return NOERROR ;
  868. }
  869.  
  870. //----------------------------------------------------------------------------
  871. // CTeeOutputPin::DecideAllocator
  872. //----------------------------------------------------------------------------
  873. HRESULT CTeeOutputPin::DecideAllocator (IMemInputPin *pPin, IMemAllocator **ppAlloc)
  874. {
  875.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DecideAllocator ptr = %lx"), pPin));
  876.  
  877.     ASSERT (m_pTee->m_pAllocator != NULL) ;
  878.  
  879.     *ppAlloc = NULL ;
  880.  
  881.     // tell the pin about our allocator, set by the input pin.
  882.     HRESULT hr = NOERROR ;
  883.     hr = pPin->NotifyAllocator (m_pTee->m_pAllocator,TRUE) ;
  884.     if (FAILED (hr))
  885.         return hr ;
  886.  
  887.     // return the allocator
  888.     *ppAlloc = m_pTee->m_pAllocator ;
  889.     m_pTee->m_pAllocator->AddRef () ;
  890.     return NOERROR ;
  891. }
  892.  
  893. //----------------------------------------------------------------------------
  894. // CTeeOutputPin::CheckMediaType
  895. //----------------------------------------------------------------------------
  896. HRESULT CTeeOutputPin::CheckMediaType (const CMediaType *pmt)
  897. {
  898.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::CheckMediaType ptr = %lx"), pmt));
  899.  
  900.     CAutoLock lock_it (m_pLock) ;
  901.  
  902.     // If we are already inside checkmedia type for this pin, return NOERROR
  903.     // It is possble to hookup two of the tee filters and some other filter
  904.     // like the video effects sample to get into this situation. If we
  905.     // do not detect this, we will loop till we blow the stack
  906.     if (m_bInsideCheckMediaType == TRUE)
  907.         return NOERROR ;
  908.     m_bInsideCheckMediaType = TRUE ;
  909.  
  910.     HRESULT hr = NOERROR ;
  911.  
  912.     // display the type of the media for debugging perposes.
  913.     DisplayMediaType (TEXT("Output Pin Checking"), pmt) ;
  914.  
  915.     // The input needs to have been conneced first.
  916.     if (m_pTee->m_Input.m_Connected == NULL)
  917.     {
  918.         m_bInsideCheckMediaType = FALSE ;
  919.         return VFW_E_NOT_CONNECTED ;
  920.     }
  921.  
  922.     // make sure that our input pin peer is happy with this.
  923.     hr = m_pTee->m_Input.m_Connected->QueryAccept (pmt) ;
  924.     if (hr != NOERROR)
  925.     {
  926.         m_bInsideCheckMediaType = FALSE ;
  927.         return VFW_E_TYPE_NOT_ACCEPTED ;
  928.     }
  929.  
  930.     // check the format with the other outpin pins
  931.  
  932.     int n = m_pTee->m_NumOutputPins ;
  933.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  934.  
  935.     while (n)
  936.     {
  937.         CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
  938.         if (pOutputPin != NULL && pOutputPin != this)
  939.         {
  940.             if (pOutputPin->m_Connected != NULL)
  941.             {
  942.                 // The pin is connected, check its peer
  943.                 hr = pOutputPin->m_Connected->QueryAccept (pmt) ;
  944.                 if (hr != NOERROR)
  945.                 {
  946.                     m_bInsideCheckMediaType = FALSE ;
  947.                     return VFW_E_TYPE_NOT_ACCEPTED ;
  948.                 }
  949.             }
  950.         }
  951.         n-- ;
  952.     }
  953.     m_bInsideCheckMediaType = FALSE ;
  954.     return NOERROR ;
  955. }
  956.  
  957. //----------------------------------------------------------------------------
  958. // CTeeOutputPin::EnumMediaTypes
  959. //----------------------------------------------------------------------------
  960. STDMETHODIMP CTeeOutputPin::EnumMediaTypes (IEnumMediaTypes **ppEnum)
  961. {
  962.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::EnumMediaTypes")));
  963.  
  964.     CAutoLock lock_it (m_pLock) ;
  965.     ASSERT (ppEnum) ;
  966.  
  967.     // make sure that we are connected.
  968.     if (m_pTee->m_Input.m_Connected == NULL)
  969.         return VFW_E_NOT_CONNECTED ;
  970.  
  971.     // we will simply return the enumerator of our input pin's peer.
  972.     return m_pTee->m_Input.m_Connected->EnumMediaTypes (ppEnum) ;
  973. }
  974.  
  975. //----------------------------------------------------------------------------
  976. // CTeeOutputPin::SetMediaType
  977. //----------------------------------------------------------------------------
  978. HRESULT CTeeOutputPin::SetMediaType (const CMediaType *pmt)
  979. {
  980.     CAutoLock lock_it (m_pLock) ;
  981.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::SetMediaType ptr = %lx"), pmt));
  982.  
  983.     // display the format of the media for debugging purposes
  984.     DisplayMediaType (TEXT("Output pin type agreed"), pmt) ;
  985.  
  986.     // make sure that we have an input connected.
  987.     if (m_pTee->m_Input.m_Connected == NULL)
  988.         return VFW_E_NOT_CONNECTED ;
  989.  
  990.     // make sure that the base class likes it.
  991.     HRESULT hr = NOERROR ;
  992.     hr = CBaseOutputPin::SetMediaType (pmt) ;
  993.     if (FAILED (hr))
  994.         return hr ;
  995.  
  996.     return NOERROR ;
  997. }
  998.  
  999. //----------------------------------------------------------------------------
  1000. // CTeeOutputPin::CompleteConnect
  1001. //
  1002. //----------------------------------------------------------------------------
  1003. HRESULT CTeeOutputPin::CompleteConnect (IPin *pReceivePin)
  1004. {
  1005.     CAutoLock lock_it (m_pLock) ;
  1006.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::CompleteConnect ptr = %lx"), pReceivePin));
  1007.     ASSERT (m_Connected == pReceivePin) ;
  1008.  
  1009.     HRESULT hr = NOERROR ;
  1010.     hr = CBaseOutputPin::CompleteConnect (pReceivePin) ;
  1011.     if (FAILED (hr))
  1012.         return hr ;
  1013.  
  1014.     // if the type is not the same as that stored for the input pin, force the
  1015.     // input pins peer to be reconnected
  1016.     if (m_mt != m_pTee->m_Input.m_mt)
  1017.         m_pTee->m_pGraph->Reconnect (m_pTee->m_Input.m_Connected) ;
  1018.  
  1019.     // since this pin has been connected up, create another output pin.
  1020.     // However, we will do this only if there is no more unconnected
  1021.     // pins. Often, CompleteConnect will get called for the same pin
  1022.     // during reconnection.
  1023.  
  1024.     int n = m_pTee->GetNumFreePins () ;
  1025.     ASSERT (n <= 1) ;
  1026.     if (n == 1)
  1027.         return NOERROR ;
  1028.  
  1029.     // no unconnected pins left, spawn a new one
  1030.  
  1031.     CTeeOutputPin *pOutputPin = m_pTee->CreateNextOutputPin (m_pTee) ;
  1032.     if (pOutputPin != NULL )
  1033.     {
  1034.         m_pTee->m_NumOutputPins++ ;
  1035.         m_pTee->m_OutputPinsList.AddTail (pOutputPin) ;
  1036.     m_pTee->IncrementPinVersion();
  1037.     }
  1038.  
  1039.     // !!! At this point we should be able to send some notification that we
  1040.     // have sprung a new pin.
  1041.  
  1042.     return NOERROR ;
  1043. }
  1044. //----------------------------------------------------------------------------
  1045. // CTeeOutputPin::Active
  1046. //
  1047. // This is called when we start running or go paused. We create the output queue
  1048. // object to send data to our associated peer pin.
  1049. //----------------------------------------------------------------------------
  1050. HRESULT CTeeOutputPin::Active ()
  1051. {
  1052.     CAutoLock lock_it (m_pLock) ;
  1053.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Active")));
  1054.  
  1055.     HRESULT hr = NOERROR ;
  1056.  
  1057.     // make sure that the pin is connected.
  1058.     if (m_Connected == NULL)
  1059.         return NOERROR ;
  1060.  
  1061.     // create the output queue if we have to
  1062.     if (m_pOutputQueue == NULL)
  1063.     {
  1064.         m_pOutputQueue = new COutputQueue (m_Connected, &hr, TRUE, FALSE) ;
  1065.         if (m_pOutputQueue == NULL)
  1066.             return E_OUTOFMEMORY ;
  1067.  
  1068.         // make sure that the constructor did not return any error.
  1069.         if (FAILED (hr))
  1070.         {
  1071.             delete m_pOutputQueue ;
  1072.             m_pOutputQueue = NULL ;
  1073.             return hr ;
  1074.         }
  1075.     }
  1076.  
  1077.     // pass the call on to the base class
  1078.     CBaseOutputPin::Active () ;
  1079.     return NOERROR ;
  1080. }
  1081.  
  1082. //----------------------------------------------------------------------------
  1083. // CTeeOutputPin::Inactive
  1084. //
  1085. // This is called when we stop streaming. We delete the output queue at this
  1086. // time.
  1087. //----------------------------------------------------------------------------
  1088. HRESULT CTeeOutputPin::Inactive ()
  1089. {
  1090.     CAutoLock lock_it (m_pLock) ;
  1091.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Inactive")));
  1092.  
  1093.     // delete the output queus associated with the pin.
  1094.     if (m_pOutputQueue)
  1095.     {
  1096.         delete m_pOutputQueue ;
  1097.         m_pOutputQueue = NULL ;
  1098.     }
  1099.  
  1100.     CBaseOutputPin::Inactive () ;
  1101.     return NOERROR ;
  1102. }
  1103.  
  1104. //----------------------------------------------------------------------------
  1105. // CTeeOutputPin::Deliver
  1106. //----------------------------------------------------------------------------
  1107. HRESULT CTeeOutputPin::Deliver (IMediaSample *pMediaSample)
  1108. {
  1109.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Deliver ptr = %lx"), pMediaSample));
  1110.  
  1111.     // make sure that we have an output queue
  1112.     if (m_pOutputQueue == NULL)
  1113.         return NOERROR ;
  1114.  
  1115.     pMediaSample->AddRef () ;
  1116.     return m_pOutputQueue->Receive (pMediaSample) ;
  1117. }
  1118.  
  1119. //----------------------------------------------------------------------------
  1120. // CTeeOutputPin::DeliverEndOfStream
  1121. //----------------------------------------------------------------------------
  1122. HRESULT CTeeOutputPin::DeliverEndOfStream ()
  1123. {
  1124.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DeliverEndOfStream")));
  1125.  
  1126.     // make sure that we have an output queue
  1127.     if (m_pOutputQueue == NULL)
  1128.         return NOERROR ;
  1129.  
  1130.     m_pOutputQueue->EOS () ;
  1131.     return NOERROR ;
  1132. }
  1133.  
  1134. //----------------------------------------------------------------------------
  1135. // CTeeOutputPin::DeliverBeginFlush
  1136. //----------------------------------------------------------------------------
  1137. HRESULT CTeeOutputPin::DeliverBeginFlush ()
  1138. {
  1139.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DeliverBeginFlush")));
  1140.  
  1141.     // make sure that we have an output queue
  1142.     if (m_pOutputQueue == NULL)
  1143.         return NOERROR ;
  1144.  
  1145.     m_pOutputQueue->BeginFlush () ;
  1146.     return NOERROR ;
  1147. }
  1148.  
  1149. //----------------------------------------------------------------------------
  1150. // CTeeOutputPin::DeliverEndFlush
  1151. //----------------------------------------------------------------------------
  1152. HRESULT CTeeOutputPin::DeliverEndFlush ()
  1153. {
  1154.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DeliverEndFlush")));
  1155.  
  1156.     // make sure that we have an output queue
  1157.     if (m_pOutputQueue == NULL)
  1158.         return NOERROR ;
  1159.  
  1160.     m_pOutputQueue->EndFlush () ;
  1161.     return NOERROR ;
  1162.  
  1163. }
  1164. //----------------------------------------------------------------------------
  1165. // CTeeOutputPin::Notify
  1166. //----------------------------------------------------------------------------
  1167.  
  1168. STDMETHODIMP CTeeOutputPin::Notify (IFilter *pSender, Quality q)
  1169. {
  1170.     DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Notify")));
  1171.  
  1172.     // We pass the message on, which means that we find the quality sink
  1173.     // for our input pin and send it there
  1174.  
  1175.     POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
  1176.     CTeeOutputPin *pFirstOutput = m_pTee->m_OutputPinsList.GetNext (pos) ;
  1177.  
  1178.     if (this == pFirstOutput) {
  1179.     DbgLog((LOG_TRACE,2,TEXT("Passing Quality notification through transform")));
  1180.     if (m_pTee->m_Input.m_pQSink!=NULL) {
  1181.         return m_pTee->m_Input.m_pQSink->Notify(m_pTee, q);
  1182.     } else {
  1183.  
  1184.         // no sink set, so pass it upstream
  1185.         HRESULT hr;
  1186.         IQualityControl * pIQC;
  1187.  
  1188.         hr = VFW_E_NOT_FOUND;                   // default
  1189.         if (m_pTee->m_Input.m_Connected) {
  1190.         m_pTee->m_Input.m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
  1191.  
  1192.         if (pIQC!=NULL) {
  1193.             hr = pIQC->Notify(m_pTee, q);
  1194.             pIQC->Release();
  1195.         }
  1196.         }
  1197.         return hr;
  1198.     }
  1199.     }
  1200.  
  1201.     // Quality management is too hard to do
  1202.     return NOERROR ;
  1203. }
  1204.  
  1205. //----------------------------------------------------------------------------
  1206. // exported entry points for registration and
  1207. // unregistration (in this case they only call
  1208. // through to default implmentations).
  1209. //
  1210. //----------------------------------------------------------------------------
  1211. HRESULT
  1212. DllRegisterServer()
  1213. {
  1214.   return AMovieDllRegisterServer();
  1215. }
  1216.  
  1217. HRESULT
  1218. DllUnregisterServer()
  1219. {
  1220.   return AMovieDllUnregisterServer();
  1221. }
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.