home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directshow / capture / amcap / crossbar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  17.1 KB  |  591 lines

  1. //------------------------------------------------------------------------------
  2. // File: Crossbar.cpp
  3. //
  4. // Desc: A class for controlling video crossbars. 
  5. //
  6. //       This class creates a single object which encapsulates all connected
  7. //       crossbars, enumerates all unique inputs which can be reached from
  8. //       a given starting pin, and automatically routes audio when a video
  9. //       source is selected.
  10. //
  11. //       The class supports an arbitrarily complex graph of crossbars, 
  12. //       which can be cascaded and disjoint, that is not all inputs need 
  13. //       to traverse the same set of crossbars.
  14. //
  15. //       Given a starting input pin (typically the analog video input to
  16. //       the capture filter), the class recursively traces upstream 
  17. //       searching for all viable inputs.  An input is considered viable if
  18. //       it is a video pin and is either:
  19. //
  20. //           - unconnected 
  21. //           - connects to a filter which does not support IAMCrossbar 
  22. //
  23. //       Methods:
  24. //
  25. //       CCrossbar (IPin *pPin);             
  26. //       ~CCrossbar();
  27. //
  28. //       HRESULT GetInputCount (LONG *pCount);
  29. //       HRESULT GetInputType  (LONG Index, LONG * PhysicalType);
  30. //       HRESULT GetInputName  (LONG Index, TCHAR * pName, LONG NameSize);
  31. //       HRESULT SetInputIndex (LONG Index);
  32. //       HRESULT GetInputIndex (LONG *Index);
  33. //
  34. // Copyright (c) 1993 - 2000, Microsoft Corporation.  All rights reserved.
  35. //------------------------------------------------------------------------------
  36.  
  37. #include <streams.h>
  38. #include "crossbar.h"
  39.  
  40.  
  41.  
  42.  
  43. //------------------------------------------------------------------------------
  44. // Name: CCrossbar::CCrossbar()
  45. // Desc: Constructor for the CCrossbar class
  46. //------------------------------------------------------------------------------
  47. CCrossbar::CCrossbar(
  48.         IPin *pStartingInputPin
  49.     ) 
  50.     : m_pStartingPin (pStartingInputPin)
  51.     , m_CurrentRoutingIndex (0)
  52.     , m_RoutingList (NULL)
  53.  
  54. {
  55.     HRESULT hr;
  56.  
  57.     DbgLog((LOG_TRACE,3,TEXT("CCrossbar Constructor")));
  58.  
  59.     ASSERT (pStartingInputPin != NULL);
  60.  
  61.     // Init everything to zero
  62.     ZeroMemory (&m_RoutingRoot, sizeof (m_RoutingRoot));
  63.  
  64.     if (m_RoutingList = new CRoutingList (TEXT("RoutingList"), 5)) {
  65.  
  66.         hr = BuildRoutingList(
  67.                 pStartingInputPin,
  68.                 &m_RoutingRoot, 
  69.                 0 /* Depth */);
  70.     }
  71. }
  72.  
  73.  
  74.  
  75.  
  76. //------------------------------------------------------------------------------
  77. // Name: CCrossbar::CCrossbar()
  78. // Desc: Destructor for the CCrossbar class
  79. //------------------------------------------------------------------------------
  80. CCrossbar::~CCrossbar()
  81. {
  82.     HRESULT hr;
  83.  
  84.     DbgLog((LOG_TRACE,3,TEXT("CCrossbar Destructor")));
  85.  
  86.     hr = DestroyRoutingList ();
  87.  
  88.     delete m_RoutingList;
  89. }
  90.  
  91.  
  92. //
  93. // This function is called recursively, every time a new crossbar is
  94. // entered as we search upstream.
  95. //
  96. // Return values:
  97. //
  98. //  S_OK -    Returned on final exit after recursive search if at least
  99. //            one routing is possible
  100. //  S_FALSE - Normal return indicating we've reached the end of a 
  101. //            recursive search, so save the current path
  102. //  E_FAIL -  Unable to route anything
  103.  
  104. HRESULT
  105. CCrossbar::BuildRoutingList (
  106.    IPin     *pStartingInputPin,
  107.    CRouting *pRouting,
  108.    int       Depth
  109.    )
  110. {
  111.     HRESULT  hr;
  112.     LONG     InputIndexRelated;
  113.     LONG     InputPhysicalType;
  114.     LONG     OutputIndexRelated;
  115.     LONG     OutputPhysicalType;
  116.     IPin    *pPin;
  117.     IPin    *pStartingOutputPin;
  118.     CRouting RoutingNext;
  119.  
  120.     LONG     Inputs;
  121.     LONG     Outputs;
  122.     LONG     InputIndex;
  123.     LONG     OutputIndex;
  124.     PIN_INFO pinInfo;
  125.     IAMCrossbar *pXbar;
  126.  
  127.     ASSERT (pStartingInputPin != NULL);
  128.     ASSERT (pRouting != NULL);
  129.  
  130.     //
  131.     // If the pin isn't connected, then it's a terminal pin
  132.     //
  133.  
  134.     hr = pStartingInputPin->ConnectedTo (&pStartingOutputPin);
  135.     if (hr != S_OK) {
  136.         return (Depth == 0) ? E_FAIL : S_FALSE;
  137.     }
  138.  
  139.     //
  140.     // It is connected, so now find out if the filter supports 
  141.     // IAMCrossbar
  142.     //
  143.  
  144.     if (S_OK == pStartingOutputPin->QueryPinInfo(&pinInfo)) {
  145.         ASSERT (pinInfo.dir == PINDIR_OUTPUT);
  146.  
  147.         hr = pinInfo.pFilter->QueryInterface(IID_IAMCrossbar, 
  148.                             (void **)&pXbar);
  149.         if (hr == S_OK) {
  150.             EXECUTE_ASSERT (S_OK == pXbar->get_PinCounts(&Outputs, &Inputs));
  151.  
  152.             EXECUTE_ASSERT (S_OK == GetCrossbarIndexFromIPin (
  153.                                     pXbar,
  154.                                     &OutputIndex,
  155.                                     FALSE,   // Input ?
  156.                                     pStartingOutputPin));
  157.  
  158.             EXECUTE_ASSERT (S_OK == pXbar->get_CrossbarPinInfo(
  159.                                     FALSE, // Input ?
  160.                                     OutputIndex,
  161.                                     &OutputIndexRelated,
  162.                                     &OutputPhysicalType));
  163.  
  164.             //
  165.             // for all input pins
  166.             //
  167.  
  168.             for (InputIndex = 0; InputIndex < Inputs; InputIndex++) {
  169.                 EXECUTE_ASSERT (S_OK == pXbar->get_CrossbarPinInfo(
  170.                                         TRUE, // Input?
  171.                                         InputIndex,
  172.                                         &InputIndexRelated,
  173.                                         &InputPhysicalType));
  174.  
  175.                 //
  176.                 // Is the pin a video pin?
  177.                 //
  178.                 if (InputPhysicalType < PhysConn_Audio_Tuner) {
  179.                     //
  180.                     // Can we route it?
  181.                     //
  182.                     if (S_OK == pXbar->CanRoute(OutputIndex, InputIndex)) {
  183.  
  184.                         EXECUTE_ASSERT (S_OK == GetCrossbarIPinAtIndex (
  185.                                         pXbar,
  186.                                         InputIndex,
  187.                                         TRUE,   // Input
  188.                                         &pPin));
  189.  
  190.                         //
  191.                         // We've found a route through this crossbar
  192.                         // so save our state before recusively searching
  193.                         // again.
  194.                         //
  195.                         ZeroMemory (&RoutingNext, sizeof (RoutingNext));
  196.  
  197.                         // doubly linked list
  198.                         RoutingNext.pRightRouting = pRouting;
  199.                         pRouting->pLeftRouting = &RoutingNext;
  200.  
  201.                         pRouting->pXbar = pXbar;
  202.                         pRouting->VideoInputIndex = InputIndex;
  203.                         pRouting->VideoOutputIndex = OutputIndex;
  204.                         pRouting->AudioInputIndex = InputIndexRelated;
  205.                         pRouting->AudioOutputIndex = OutputIndexRelated;
  206.                         pRouting->InputPhysicalType = InputPhysicalType;
  207.                         pRouting->OutputPhysicalType = OutputPhysicalType;
  208.                         pRouting->Depth = Depth;
  209.  
  210.                         hr = BuildRoutingList (
  211.                                     pPin,
  212.                                     &RoutingNext,
  213.                                     Depth + 1);
  214.                         
  215.                         if (hr == S_OK) {
  216.                             ; // Nothing to do?  
  217.                         }
  218.                         else if (hr == S_FALSE) {
  219.                             pRouting->pLeftRouting = NULL;
  220.                             SaveRouting (pRouting);
  221.                         }
  222.                         else if (hr == E_FAIL) {
  223.                             ;  // Nothing to do?
  224.                         }
  225.                     } // if we can route
  226.                 } // if its a video pin
  227.             } // for all input pins
  228.             pXbar->Release();
  229.         }
  230.         else {
  231.             // The filter doesn't support IAMCrossbar, so this
  232.             // is a terminal pin
  233.             pinInfo.pFilter->Release();
  234.             pStartingOutputPin->Release ();
  235.  
  236.             return (Depth == 0) ? E_FAIL : S_FALSE;
  237.         }
  238.  
  239.         pinInfo.pFilter->Release();
  240.     }
  241.  
  242.     pStartingOutputPin->Release ();
  243.  
  244.     return S_OK;
  245. }
  246.  
  247. //
  248. // Make a copy of the current routing, and AddRef the IAMCrossbar
  249. // interfaces.
  250. //
  251.  
  252. HRESULT
  253. CCrossbar::SaveRouting (CRouting *pRoutingNew)
  254. {
  255.     int j;
  256.     int Depth= pRoutingNew->Depth + 1;
  257.     CRouting *pr;
  258.     CRouting *pCurrent = pRoutingNew;
  259.  
  260.     DbgLog((LOG_TRACE,3,TEXT("CCrossbar::SaveRouting, Depth=%d, NumberOfRoutings=%d"), 
  261.             Depth, m_RoutingList->GetCount() + 1));
  262.  
  263.     pr = new CRouting[Depth];
  264.  
  265.     if (pr == NULL) {
  266.         return E_FAIL;
  267.     }
  268.  
  269.     m_RoutingList->AddTail (pr);
  270.  
  271.     for (j = 0; j < Depth; j++, pr++) {
  272.         *pr = *pCurrent;
  273.         ASSERT (pCurrent->pXbar != NULL);
  274.         //
  275.         // We're holding onto this interface, so AddRef
  276.         //
  277.         pCurrent->pXbar->AddRef();
  278.  
  279.         pCurrent = pCurrent->pRightRouting;
  280.  
  281.         //
  282.         // Pointers were stack based during recursive search, so update them
  283.         // in the allocated array
  284.         //
  285.         pr->pLeftRouting = &(*(pr-1));
  286.         pr->pRightRouting = pCurrent;
  287.  
  288.         if (j == 0) {                   // first element
  289.             pr->pLeftRouting = NULL;
  290.         } 
  291.         if (j == (Depth - 1)) {  // last element
  292.             pr->pRightRouting = NULL;
  293.         }
  294.     }
  295.  
  296.     return S_OK;
  297. }
  298.  
  299.  
  300. //
  301. //
  302. HRESULT
  303. CCrossbar::DestroyRoutingList()
  304. {
  305.     int k;
  306.     int Depth;
  307.     CRouting * pCurrent;
  308.  
  309.     DbgLog((LOG_TRACE,3,TEXT("DestroyRoutingList")));
  310.  
  311.     while (m_RoutingList->GetCount()) {
  312.         pCurrent = m_RoutingList->RemoveHead();
  313.         Depth = pCurrent->Depth + 1;
  314.  
  315.         for (k = 0; k < Depth; k++) {
  316.             ASSERT (pCurrent->pXbar != NULL);
  317.             pCurrent->pXbar->Release();
  318.  
  319.             pCurrent = pCurrent->pRightRouting;    
  320.         }
  321.     }
  322.  
  323.     return S_OK;
  324. }
  325.  
  326.  
  327. //
  328. // Does not AddRef the returned *Pin 
  329. //
  330. HRESULT
  331. CCrossbar::GetCrossbarIPinAtIndex(
  332.    IAMCrossbar *pXbar,
  333.    LONG PinIndex,
  334.    BOOL IsInputPin,
  335.    IPin ** ppPin)
  336. {
  337.     LONG         cntInPins, cntOutPins;
  338.     IPin        *pP = 0;
  339.     IBaseFilter *pFilter = NULL;
  340.     IEnumPins   *pins;
  341.     ULONG        n;
  342.     HRESULT      hr;
  343.  
  344.     *ppPin = 0;
  345.  
  346.     if(S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins)) {
  347.         return E_FAIL;
  348.     }
  349.  
  350.     LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
  351.  
  352.     hr = pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter);
  353.  
  354.     if (hr == S_OK) {
  355.         if(SUCCEEDED(pFilter->EnumPins(&pins))) {            
  356.             LONG i=0;
  357.             while(pins->Next(1, &pP, &n) == S_OK) {
  358.                 pP->Release();
  359.                 if (i == TrueIndex) {
  360.                     *ppPin = pP;
  361.                     break;
  362.                 }
  363.                 i++;
  364.             }
  365.             pins->Release();
  366.         }
  367.         pFilter->Release();
  368.     }
  369.     
  370.     return *ppPin ? S_OK : E_FAIL; 
  371. }
  372.  
  373.  
  374.  
  375. //
  376. // Find corresponding index of an IPin on a crossbar
  377. //
  378. HRESULT
  379. CCrossbar::GetCrossbarIndexFromIPin (
  380.     IAMCrossbar * pXbar,
  381.     LONG * PinIndex,
  382.     BOOL IsInputPin,
  383.     IPin * pPin)
  384.  
  385. {
  386.     LONG         cntInPins, cntOutPins;
  387.     IPin        *pP = 0;
  388.     IBaseFilter *pFilter = NULL;
  389.     IEnumPins   *pins;
  390.     ULONG        n;
  391.     BOOL         fOK = FALSE;
  392.     HRESULT      hr;
  393.  
  394.     if(S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins)) {
  395.         return E_FAIL;
  396.     }
  397.  
  398.     hr = pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter);
  399.  
  400.     if (hr == S_OK) {
  401.         if(SUCCEEDED(pFilter->EnumPins(&pins))) {            
  402.             LONG i=0;
  403.             while(pins->Next(1, &pP, &n) == S_OK) {
  404.                 pP->Release();
  405.                 if (pPin == pP) {
  406.                     *PinIndex = IsInputPin ? i : i - cntInPins;
  407.                     fOK = TRUE;
  408.                     break;
  409.                 }
  410.                 i++;
  411.             }
  412.             pins->Release();
  413.         }
  414.         pFilter->Release();
  415.     }
  416.     
  417.     return fOK ? S_OK : E_FAIL; 
  418. }
  419.  
  420. //
  421. // How many unique video inputs can be selected?
  422. //
  423. HRESULT 
  424. CCrossbar::GetInputCount (
  425.     LONG *pCount)
  426. {
  427.     *pCount = m_RoutingList->GetCount();
  428.     return S_OK;
  429. }
  430.  
  431. //
  432. // What is the physical type of a given input?
  433. //
  434. HRESULT 
  435. CCrossbar::GetInputType (
  436.     LONG Index, 
  437.     LONG * PhysicalType)
  438. {
  439.     CRouting *pCurrent = m_RoutingList->GetHead();
  440.  
  441.     if (Index >= m_RoutingList->GetCount()) {
  442.         return E_FAIL;
  443.     }
  444.  
  445.     POSITION pos = m_RoutingList->GetHeadPosition();
  446.     for (int j = 0; j <= Index; j++) {  
  447.        pCurrent = m_RoutingList->GetNext(pos);
  448.     }
  449.     ASSERT (pCurrent != NULL);
  450.  
  451.     *PhysicalType = pCurrent->InputPhysicalType;
  452.  
  453.     return S_OK;
  454. }
  455.  
  456.  
  457. //
  458. // Converts a PinType into a String
  459. //
  460.  
  461. BOOL 
  462. CCrossbar::StringFromPinType (TCHAR *pc, int nSize, long lType)
  463. {
  464.     TCHAR *pcT;
  465.     BOOL bSuccess;
  466.  
  467.     switch (lType) {
  468.     
  469.     case PhysConn_Video_Tuner:              pcT = TEXT("Video Tuner");          break;
  470.     case PhysConn_Video_Composite:          pcT = TEXT("Video Composite");      break;
  471.     case PhysConn_Video_SVideo:             pcT = TEXT("Video SVideo");         break;
  472.     case PhysConn_Video_RGB:                pcT = TEXT("Video RGB");            break;
  473.     case PhysConn_Video_YRYBY:              pcT = TEXT("Video YRYBY");          break;
  474.     case PhysConn_Video_SerialDigital:      pcT = TEXT("Video SerialDigital");  break;
  475.     case PhysConn_Video_ParallelDigital:    pcT = TEXT("Video ParallelDigital");break;
  476.     case PhysConn_Video_SCSI:               pcT = TEXT("Video SCSI");           break;
  477.     case PhysConn_Video_AUX:                pcT = TEXT("Video AUX");            break;
  478.     case PhysConn_Video_1394:               pcT = TEXT("Video 1394");           break;
  479.     case PhysConn_Video_USB:                pcT = TEXT("Video USB");            break;
  480.     case PhysConn_Video_VideoDecoder:       pcT = TEXT("Video Decoder");        break;
  481.     case PhysConn_Video_VideoEncoder:       pcT = TEXT("Video Encoder");        break;
  482.     
  483.     case PhysConn_Audio_Tuner:              pcT = TEXT("Audio Tuner");          break;
  484.     case PhysConn_Audio_Line:               pcT = TEXT("Audio Line");           break;
  485.     case PhysConn_Audio_Mic:                pcT = TEXT("Audio Mic");            break;
  486.     case PhysConn_Audio_AESDigital:         pcT = TEXT("Audio AESDigital");     break;
  487.     case PhysConn_Audio_SPDIFDigital:       pcT = TEXT("Audio SPDIFDigital");   break;
  488.     case PhysConn_Audio_SCSI:               pcT = TEXT("Audio SCSI");           break;
  489.     case PhysConn_Audio_AUX:                pcT = TEXT("Audio AUX");            break;
  490.     case PhysConn_Audio_1394:               pcT = TEXT("Audio 1394");           break;
  491.     case PhysConn_Audio_USB:                pcT = TEXT("Audio USB");            break;
  492.     case PhysConn_Audio_AudioDecoder:       pcT = TEXT("Audio Decoder");        break;
  493.     
  494.     default:
  495.         pcT = TEXT("Unknown");
  496.         break;
  497.     }
  498.     
  499.     // return TRUE on sucessful copy
  500.     if (lstrcpyn (pc, pcT, nSize) != NULL) {
  501.         bSuccess = TRUE;
  502.     }
  503.     else {
  504.         bSuccess = FALSE;
  505.     }
  506.     
  507.     return (bSuccess);
  508. };
  509.  
  510. //
  511. // Get a text version of an input
  512. //
  513. // Return S_OK if the buffer is large enough to copy the string name
  514. //
  515. HRESULT 
  516. CCrossbar::GetInputName (
  517.     LONG   Index, 
  518.     TCHAR *pName, 
  519.     LONG   Size)
  520. {
  521.     CRouting *pCurrent = m_RoutingList->GetHead();
  522.  
  523.     if ((Index >= m_RoutingList->GetCount()) || (pName == NULL)) {
  524.         return E_FAIL;
  525.     }
  526.  
  527.     POSITION pos = m_RoutingList->GetHeadPosition();
  528.     for (int j = 0; j <= Index; j++) { 
  529.        pCurrent = m_RoutingList->GetNext(pos);
  530.     }
  531.     ASSERT (pCurrent != NULL);
  532.  
  533.     return (StringFromPinType (pName, Size, pCurrent->InputPhysicalType) ?
  534.             S_OK : E_FAIL);
  535. }
  536.  
  537. //
  538. // Select an input 
  539. //
  540. HRESULT 
  541. CCrossbar::SetInputIndex (
  542.     LONG Index)
  543. {
  544.     HRESULT hr = E_FAIL;
  545.     CRouting *pCurrent = m_RoutingList->GetHead();
  546.     int j;
  547.  
  548.     if (Index >= m_RoutingList->GetCount()) {
  549.         return hr;
  550.     }
  551.  
  552.     POSITION pos = m_RoutingList->GetHeadPosition();
  553.     for (j = 0; j <= Index; j++) { 
  554.        pCurrent = m_RoutingList->GetNext(pos);
  555.     }
  556.  
  557.     ASSERT (pCurrent != NULL);
  558.  
  559.     int Depth= pCurrent->Depth + 1;
  560.  
  561.     for (j = 0; j < Depth; j++) {
  562.         hr = pCurrent->pXbar->Route (pCurrent->VideoOutputIndex, pCurrent->VideoInputIndex);
  563.         ASSERT (S_OK == hr);
  564.  
  565.         if ((pCurrent->AudioOutputIndex != -1) && (pCurrent->AudioInputIndex != -1)) {
  566.             EXECUTE_ASSERT (S_OK == pCurrent->pXbar->Route (pCurrent->AudioOutputIndex, pCurrent->AudioInputIndex));
  567.         }
  568.  
  569.         DbgLog((LOG_TRACE,3,TEXT("CCrossbar::Routing, VideoOutIndex=%d VideoInIndex=%d"), 
  570.                 pCurrent->VideoOutputIndex, pCurrent->VideoInputIndex));
  571.  
  572.         pCurrent++;
  573.     }
  574.  
  575.     m_CurrentRoutingIndex = Index;
  576.  
  577.     return hr;
  578. }
  579.  
  580. //
  581. // What input is currently selected?
  582. //
  583. HRESULT 
  584. CCrossbar::GetInputIndex (
  585.     LONG *Index)
  586. {
  587.     *Index = m_CurrentRoutingIndex;
  588.     return S_OK;
  589. }
  590.  
  591.