home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Capture / AMCap / crossbar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  17.1 KB  |  594 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-2001 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.     m_RoutingList = new CRoutingList (TEXT("RoutingList"), 5);
  65.     if (m_RoutingList) {
  66.  
  67.         hr = BuildRoutingList(
  68.                 pStartingInputPin,
  69.                 &m_RoutingRoot, 
  70.                 0 /* Depth */);
  71.     }
  72. }
  73.  
  74.  
  75. //------------------------------------------------------------------------------
  76. // Name: CCrossbar::CCrossbar()
  77. // Desc: Destructor for the CCrossbar class
  78. //------------------------------------------------------------------------------
  79. CCrossbar::~CCrossbar()
  80. {
  81.     HRESULT hr;
  82.  
  83.     DbgLog((LOG_TRACE,3,TEXT("CCrossbar Destructor")));
  84.  
  85.     hr = DestroyRoutingList ();
  86.  
  87.     delete m_RoutingList;
  88. }
  89.  
  90.  
  91. //
  92. // This function is called recursively, every time a new crossbar is
  93. // entered as we search upstream.
  94. //
  95. // Return values:
  96. //
  97. //  S_OK -    Returned on final exit after recursive search if at least
  98. //            one routing is possible
  99. //  S_FALSE - Normal return indicating we've reached the end of a 
  100. //            recursive search, so save the current path
  101. //  E_FAIL -  Unable to route anything
  102.  
  103. HRESULT
  104. CCrossbar::BuildRoutingList (
  105.    IPin     *pStartingInputPin,
  106.    CRouting *pRouting,
  107.    int       Depth
  108.    )
  109. {
  110.     HRESULT  hr;
  111.     LONG     InputIndexRelated;
  112.     LONG     InputPhysicalType;
  113.     LONG     OutputIndexRelated;
  114.     LONG     OutputPhysicalType;
  115.     IPin    *pPin;
  116.     IPin    *pStartingOutputPin;
  117.     CRouting RoutingNext;
  118.  
  119.     LONG     Inputs;
  120.     LONG     Outputs;
  121.     LONG     InputIndex;
  122.     LONG     OutputIndex;
  123.     PIN_INFO pinInfo;
  124.     IAMCrossbar *pXbar;
  125.  
  126.     ASSERT (pStartingInputPin != NULL);
  127.     ASSERT (pRouting != NULL);
  128.  
  129.     //
  130.     // If the pin isn't connected, then it's a terminal pin
  131.     //
  132.  
  133.     hr = pStartingInputPin->ConnectedTo (&pStartingOutputPin);
  134.     if (hr != S_OK) {
  135.         return (Depth == 0) ? E_FAIL : S_FALSE;
  136.     }
  137.  
  138.     //
  139.     // It is connected, so now find out if the filter supports 
  140.     // IAMCrossbar
  141.     //
  142.  
  143.     if (S_OK == pStartingOutputPin->QueryPinInfo(&pinInfo)) {
  144.         ASSERT (pinInfo.dir == PINDIR_OUTPUT);
  145.  
  146.         hr = pinInfo.pFilter->QueryInterface(IID_IAMCrossbar, 
  147.                             (void **)&pXbar);
  148.         if (hr == S_OK) {
  149.             EXECUTE_ASSERT (S_OK == pXbar->get_PinCounts(&Outputs, &Inputs));
  150.  
  151.             EXECUTE_ASSERT (S_OK == GetCrossbarIndexFromIPin (
  152.                                     pXbar,
  153.                                     &OutputIndex,
  154.                                     FALSE,   // Input ?
  155.                                     pStartingOutputPin));
  156.  
  157.             EXECUTE_ASSERT (S_OK == pXbar->get_CrossbarPinInfo(
  158.                                     FALSE, // Input ?
  159.                                     OutputIndex,
  160.                                     &OutputIndexRelated,
  161.                                     &OutputPhysicalType));
  162.  
  163.             //
  164.             // for all input pins
  165.             //
  166.  
  167.             for (InputIndex = 0; InputIndex < Inputs; InputIndex++) {
  168.                 EXECUTE_ASSERT (S_OK == pXbar->get_CrossbarPinInfo(
  169.                                         TRUE, // Input?
  170.                                         InputIndex,
  171.                                         &InputIndexRelated,
  172.                                         &InputPhysicalType));
  173.  
  174.                 //
  175.                 // Is the pin a video pin?
  176.                 //
  177.                 if (InputPhysicalType < PhysConn_Audio_Tuner) {
  178.                     //
  179.                     // Can we route it?
  180.                     //
  181.                     if (S_OK == pXbar->CanRoute(OutputIndex, InputIndex)) {
  182.  
  183.                         EXECUTE_ASSERT (S_OK == GetCrossbarIPinAtIndex (
  184.                                         pXbar,
  185.                                         InputIndex,
  186.                                         TRUE,   // Input
  187.                                         &pPin));
  188.  
  189.                         //
  190.                         // We've found a route through this crossbar
  191.                         // so save our state before recusively searching
  192.                         // again.
  193.                         //
  194.                         ZeroMemory (&RoutingNext, sizeof (RoutingNext));
  195.  
  196.                         // doubly linked list
  197.                         RoutingNext.pRightRouting = pRouting;
  198.                         pRouting->pLeftRouting = &RoutingNext;
  199.  
  200.                         pRouting->pXbar = pXbar;
  201.                         pRouting->VideoInputIndex = InputIndex;
  202.                         pRouting->VideoOutputIndex = OutputIndex;
  203.                         pRouting->AudioInputIndex = InputIndexRelated;
  204.                         pRouting->AudioOutputIndex = OutputIndexRelated;
  205.                         pRouting->InputPhysicalType = InputPhysicalType;
  206.                         pRouting->OutputPhysicalType = OutputPhysicalType;
  207.                         pRouting->Depth = Depth;
  208.  
  209.                         hr = BuildRoutingList (
  210.                                     pPin,
  211.                                     &RoutingNext,
  212.                                     Depth + 1);
  213.                         
  214.                         if (hr == S_OK) {
  215.                             ; // Nothing to do?  
  216.                         }
  217.                         else if (hr == S_FALSE) {
  218.                             pRouting->pLeftRouting = NULL;
  219.                             SaveRouting (pRouting);
  220.                         }
  221.                         else if (hr == E_FAIL) {
  222.                             ;  // Nothing to do?
  223.                         }
  224.                     } // if we can route
  225.                 } // if its a video pin
  226.             } // for all input pins
  227.             pXbar->Release();
  228.         }
  229.         else {
  230.             // The filter doesn't support IAMCrossbar, so this
  231.             // is a terminal pin
  232.             pinInfo.pFilter->Release();
  233.             pStartingOutputPin->Release ();
  234.  
  235.             return (Depth == 0) ? E_FAIL : S_FALSE;
  236.         }
  237.  
  238.         pinInfo.pFilter->Release();
  239.     }
  240.  
  241.     pStartingOutputPin->Release ();
  242.  
  243.     return S_OK;
  244. }
  245.  
  246. //
  247. // Make a copy of the current routing, and AddRef the IAMCrossbar
  248. // interfaces.
  249. //
  250.  
  251. HRESULT
  252. CCrossbar::SaveRouting (CRouting *pRoutingNew)
  253. {
  254.     int j;
  255.     int Depth= pRoutingNew->Depth + 1;
  256.     CRouting *pr;
  257.     CRouting *pCurrent = pRoutingNew;
  258.  
  259.     DbgLog((LOG_TRACE,3,TEXT("CCrossbar::SaveRouting, Depth=%d, NumberOfRoutings=%d"), 
  260.             Depth, m_RoutingList->GetCount() + 1));
  261.  
  262.     pr = new CRouting[Depth];
  263.  
  264.     if (pr == NULL) {
  265.         return E_FAIL;
  266.     }
  267.  
  268.     m_RoutingList->AddTail (pr);
  269.  
  270.     for (j = 0; j < Depth; j++, pr++) {
  271.         *pr = *pCurrent;
  272.         ASSERT (pCurrent->pXbar != NULL);
  273.         //
  274.         // We're holding onto this interface, so AddRef
  275.         //
  276.         pCurrent->pXbar->AddRef();
  277.  
  278.         pCurrent = pCurrent->pRightRouting;
  279.  
  280.         //
  281.         // Pointers were stack based during recursive search, so update them
  282.         // in the allocated array
  283.         //
  284.         pr->pLeftRouting = &(*(pr-1));
  285.         pr->pRightRouting = pCurrent;
  286.  
  287.         if (j == 0) {                   // first element
  288.             pr->pLeftRouting = NULL;
  289.         } 
  290.         if (j == (Depth - 1)) {  // last element
  291.             pr->pRightRouting = NULL;
  292.         }
  293.     }
  294.  
  295.     return S_OK;
  296. }
  297.  
  298.  
  299. //
  300. //
  301. HRESULT
  302. CCrossbar::DestroyRoutingList()
  303. {
  304.     int k;
  305.     int Depth;
  306.     CRouting * pCurrent;
  307.  
  308.     DbgLog((LOG_TRACE,3,TEXT("DestroyRoutingList")));
  309.  
  310.     while (m_RoutingList->GetCount()) {
  311.         pCurrent = m_RoutingList->RemoveHead();
  312.         Depth = pCurrent->Depth + 1;
  313.  
  314.         for (k = 0; k < Depth; k++) {
  315.             ASSERT (pCurrent->pXbar != NULL);
  316.             pCurrent->pXbar->Release();
  317.  
  318.             pCurrent = pCurrent->pRightRouting;    
  319.         }
  320.     }
  321.  
  322.     return S_OK;
  323. }
  324.  
  325.  
  326. //
  327. // Does not AddRef the returned *Pin 
  328. //
  329. HRESULT
  330. CCrossbar::GetCrossbarIPinAtIndex(
  331.    IAMCrossbar *pXbar,
  332.    LONG PinIndex,
  333.    BOOL IsInputPin,
  334.    IPin ** ppPin)
  335. {
  336.     LONG         cntInPins, cntOutPins;
  337.     IPin        *pP = 0;
  338.     IBaseFilter *pFilter = NULL;
  339.     IEnumPins   *pins;
  340.     ULONG        n;
  341.     HRESULT      hr;
  342.  
  343.     *ppPin = 0;
  344.  
  345.     if(S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins)) {
  346.         return E_FAIL;
  347.     }
  348.  
  349.     LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
  350.  
  351.     hr = pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter);
  352.  
  353.     if (hr == S_OK) {
  354.         if(SUCCEEDED(pFilter->EnumPins(&pins))) {            
  355.             LONG i=0;
  356.             while(pins->Next(1, &pP, &n) == S_OK) {
  357.                 pP->Release();
  358.                 if (i == TrueIndex) {
  359.                     *ppPin = pP;
  360.                     break;
  361.                 }
  362.                 i++;
  363.             }
  364.             pins->Release();
  365.         }
  366.         pFilter->Release();
  367.     }
  368.     
  369.     return *ppPin ? S_OK : E_FAIL; 
  370. }
  371.  
  372.  
  373.  
  374. //
  375. // Find corresponding index of an IPin on a crossbar
  376. //
  377. HRESULT
  378. CCrossbar::GetCrossbarIndexFromIPin (
  379.     IAMCrossbar * pXbar,
  380.     LONG * PinIndex,
  381.     BOOL IsInputPin,
  382.     IPin * pPin)
  383.  
  384. {
  385.     LONG         cntInPins, cntOutPins;
  386.     IPin        *pP = 0;
  387.     IBaseFilter *pFilter = NULL;
  388.     IEnumPins   *pins;
  389.     ULONG        n;
  390.     BOOL         fOK = FALSE;
  391.     HRESULT      hr;
  392.  
  393.     if(S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins)) {
  394.         return E_FAIL;
  395.     }
  396.  
  397.     hr = pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter);
  398.  
  399.     if (hr == S_OK) {
  400.         if(SUCCEEDED(pFilter->EnumPins(&pins))) {            
  401.             LONG i=0;
  402.             while(pins->Next(1, &pP, &n) == S_OK) {
  403.                 pP->Release();
  404.                 if (pPin == pP) {
  405.                     *PinIndex = IsInputPin ? i : i - cntInPins;
  406.                     fOK = TRUE;
  407.                     break;
  408.                 }
  409.                 i++;
  410.             }
  411.             pins->Release();
  412.         }
  413.         pFilter->Release();
  414.     }
  415.     
  416.     return fOK ? S_OK : E_FAIL; 
  417. }
  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. //
  433. // What is the physical type of a given input?
  434. //
  435. HRESULT 
  436. CCrossbar::GetInputType (
  437.     LONG Index, 
  438.     LONG * PhysicalType)
  439. {
  440.     CRouting *pCurrent = m_RoutingList->GetHead();
  441.  
  442.     if (Index >= m_RoutingList->GetCount()) {
  443.         return E_FAIL;
  444.     }
  445.  
  446.     POSITION pos = m_RoutingList->GetHeadPosition();
  447.     for (int j = 0; j <= Index; j++) {  
  448.        pCurrent = m_RoutingList->GetNext(pos);
  449.     }
  450.     ASSERT (pCurrent != NULL);
  451.  
  452.     *PhysicalType = pCurrent->InputPhysicalType;
  453.  
  454.     return S_OK;
  455. }
  456.  
  457.  
  458. //
  459. // Converts a PinType into a String
  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. //
  512. // Get a text version of an input
  513. //
  514. // Return S_OK if the buffer is large enough to copy the string name
  515. //
  516. HRESULT 
  517. CCrossbar::GetInputName (
  518.     LONG   Index, 
  519.     TCHAR *pName, 
  520.     LONG   Size)
  521. {
  522.     CRouting *pCurrent = m_RoutingList->GetHead();
  523.  
  524.     if ((Index >= m_RoutingList->GetCount()) || (pName == NULL)) {
  525.         return E_FAIL;
  526.     }
  527.  
  528.     POSITION pos = m_RoutingList->GetHeadPosition();
  529.     for (int j = 0; j <= Index; j++) { 
  530.        pCurrent = m_RoutingList->GetNext(pos);
  531.     }
  532.     ASSERT (pCurrent != NULL);
  533.  
  534.     return (StringFromPinType (pName, Size, pCurrent->InputPhysicalType) ?
  535.             S_OK : E_FAIL);
  536. }
  537.  
  538.  
  539. //
  540. // Select an input 
  541. //
  542. HRESULT 
  543. CCrossbar::SetInputIndex (
  544.     LONG Index)
  545. {
  546.     HRESULT hr = E_FAIL;
  547.     CRouting *pCurrent = m_RoutingList->GetHead();
  548.     int j;
  549.  
  550.     if (Index >= m_RoutingList->GetCount()) {
  551.         return hr;
  552.     }
  553.  
  554.     POSITION pos = m_RoutingList->GetHeadPosition();
  555.     for (j = 0; j <= Index; j++) { 
  556.        pCurrent = m_RoutingList->GetNext(pos);
  557.     }
  558.  
  559.     ASSERT (pCurrent != NULL);
  560.  
  561.     int Depth= pCurrent->Depth + 1;
  562.  
  563.     for (j = 0; j < Depth; j++) {
  564.         hr = pCurrent->pXbar->Route (pCurrent->VideoOutputIndex, pCurrent->VideoInputIndex);
  565.         ASSERT (S_OK == hr);
  566.  
  567.         if ((pCurrent->AudioOutputIndex != -1) && (pCurrent->AudioInputIndex != -1)) {
  568.             EXECUTE_ASSERT (S_OK == pCurrent->pXbar->Route (pCurrent->AudioOutputIndex, pCurrent->AudioInputIndex));
  569.         }
  570.  
  571.         DbgLog((LOG_TRACE,3,TEXT("CCrossbar::Routing, VideoOutIndex=%d VideoInIndex=%d"), 
  572.                 pCurrent->VideoOutputIndex, pCurrent->VideoInputIndex));
  573.  
  574.         pCurrent++;
  575.     }
  576.  
  577.     m_CurrentRoutingIndex = Index;
  578.  
  579.     return hr;
  580. }
  581.  
  582.  
  583. //
  584. // What input is currently selected?
  585. //
  586. HRESULT 
  587. CCrossbar::GetInputIndex (
  588.     LONG *Index)
  589. {
  590.     *Index = m_CurrentRoutingIndex;
  591.     return S_OK;
  592. }
  593.  
  594.