www.pudn.com > AMCap_example.rar > crossbar.cpp


//------------------------------------------------------------------------------ 
// File: Crossbar.cpp 
// 
// Desc: A class for controlling video crossbars.  
// 
//       This class creates a single object which encapsulates all connected 
//       crossbars, enumerates all unique inputs which can be reached from 
//       a given starting pin, and automatically routes audio when a video 
//       source is selected. 
// 
//       The class supports an arbitrarily complex graph of crossbars,  
//       which can be cascaded and disjoint, that is not all inputs need  
//       to traverse the same set of crossbars. 
// 
//       Given a starting input pin (typically the analog video input to 
//       the capture filter), the class recursively traces upstream  
//       searching for all viable inputs.  An input is considered viable if 
//       it is a video pin and is either: 
// 
//           - unconnected  
//           - connects to a filter which does not support IAMCrossbar  
// 
//       Methods: 
// 
//       CCrossbar (IPin *pPin);              
//       ~CCrossbar(); 
// 
//       HRESULT GetInputCount (LONG *pCount); 
//       HRESULT GetInputType  (LONG Index, LONG * PhysicalType); 
//       HRESULT GetInputName  (LONG Index, TCHAR * pName, LONG NameSize); 
//       HRESULT SetInputIndex (LONG Index); 
//       HRESULT GetInputIndex (LONG *Index); 
// 
// Copyright (c) Microsoft Corporation.  All rights reserved. 
//------------------------------------------------------------------------------ 
 
#include  
 
#include "crossbar.h" 
 
 
//------------------------------------------------------------------------------ 
// Name: CCrossbar::CCrossbar() 
// Desc: Constructor for the CCrossbar class 
//------------------------------------------------------------------------------ 
CCrossbar::CCrossbar( 
        IPin *pStartingInputPin, 
        HRESULT *phr 
    )  
    : m_pStartingPin (pStartingInputPin) 
    , m_CurrentRoutingIndex (0) 
    , m_RoutingList (NULL) 
 
{ 
    HRESULT hr; 
    ASSERT(phr); 
 
    DbgLog((LOG_TRACE,3,TEXT("CCrossbar Constructor"))); 
 
    ASSERT (pStartingInputPin != NULL); 
 
    // Init everything to zero 
    ZeroMemory (&m_RoutingRoot, sizeof (m_RoutingRoot)); 
 
    m_RoutingList = new CRoutingList (TEXT("RoutingList"), 5); 
 
    if (m_RoutingList) 
        hr = BuildRoutingList(pStartingInputPin, &m_RoutingRoot, 0 /* Depth */); 
    else 
        hr = E_OUTOFMEMORY; 
 
    // Return an error/success code from the constructor         
    if (phr) 
        *phr = hr; 
} 
 
 
//------------------------------------------------------------------------------ 
// Name: CCrossbar::CCrossbar() 
// Desc: Destructor for the CCrossbar class 
//------------------------------------------------------------------------------ 
CCrossbar::~CCrossbar() 
{ 
    DbgLog((LOG_TRACE,3,TEXT("CCrossbar Destructor"))); 
 
    HRESULT hr = DestroyRoutingList (); 
 
    delete m_RoutingList; 
} 
 
 
// 
// This function is called recursively, every time a new crossbar is 
// entered as we search upstream. 
// 
// Return values: 
// 
//  S_OK -    Returned on final exit after recursive search if at least 
//            one routing is possible 
//  S_FALSE - Normal return indicating we've reached the end of a  
//            recursive search, so save the current path 
//  E_FAIL -  Unable to route anything 
 
HRESULT CCrossbar::BuildRoutingList ( 
   IPin     *pStartingInputPin, 
   CRouting *pRouting, 
   int       Depth 
   ) 
{ 
    HRESULT  hr; 
    LONG     InputIndexRelated, OutputIndexRelated; 
    LONG     InputPhysicalType, OutputPhysicalType; 
    LONG     Inputs, Outputs, InputIndex, OutputIndex; 
 
    IPin    *pPin=0; 
    IPin    *pStartingOutputPin=0; 
    PIN_INFO pinInfo; 
    CRouting RoutingNext; 
    IAMCrossbar *pXbar=0; 
 
 
    ASSERT (pStartingInputPin != NULL); 
    ASSERT (pRouting != NULL); 
 
    if (!pStartingInputPin || !pRouting) 
        return E_POINTER; 
 
    // 
    // If the pin isn't connected, then it's a terminal pin 
    // 
 
    hr = pStartingInputPin->ConnectedTo (&pStartingOutputPin); 
    if (hr != S_OK) 
        return (Depth == 0) ? E_FAIL : S_FALSE; 
 
    // 
    // It is connected, so now find out if the filter supports  
    // IAMCrossbar 
    // 
 
    if (S_OK == pStartingOutputPin->QueryPinInfo(&pinInfo))  
    { 
        ASSERT (pinInfo.dir == PINDIR_OUTPUT); 
 
        hr = pinInfo.pFilter->QueryInterface(IID_IAMCrossbar, (void **)&pXbar); 
        if (hr == S_OK)  
        { 
            EXECUTE_ASSERT (S_OK == pXbar->get_PinCounts(&Outputs, &Inputs)); 
 
            EXECUTE_ASSERT (S_OK == GetCrossbarIndexFromIPin ( 
                                    pXbar, 
                                    &OutputIndex, 
                                    FALSE,   // Input ? 
                                    pStartingOutputPin)); 
 
            EXECUTE_ASSERT (S_OK == pXbar->get_CrossbarPinInfo( 
                                    FALSE, // Input ? 
                                    OutputIndex, 
                                    &OutputIndexRelated, 
                                    &OutputPhysicalType)); 
 
            // 
            // for all input pins 
            // 
 
            for (InputIndex = 0; InputIndex < Inputs; InputIndex++)  
            { 
                EXECUTE_ASSERT (S_OK == pXbar->get_CrossbarPinInfo( 
                                        TRUE, // Input? 
                                        InputIndex, 
                                        &InputIndexRelated, 
                                        &InputPhysicalType)); 
 
                // 
                // Is the pin a video pin? 
                // 
                if (InputPhysicalType < PhysConn_Audio_Tuner)  
                { 
                    // 
                    // Can we route it? 
                    // 
                    if (S_OK == pXbar->CanRoute(OutputIndex, InputIndex))  
                    { 
 
                        EXECUTE_ASSERT (S_OK == GetCrossbarIPinAtIndex ( 
                                        pXbar, 
                                        InputIndex, 
                                        TRUE,   // Input 
                                        &pPin)); 
 
                        // 
                        // We've found a route through this crossbar 
                        // so save our state before recusively searching 
                        // again. 
                        // 
                        ZeroMemory (&RoutingNext, sizeof (RoutingNext)); 
 
                        // doubly linked list 
                        RoutingNext.pRightRouting = pRouting; 
                        pRouting->pLeftRouting = &RoutingNext; 
 
                        pRouting->pXbar = pXbar; 
                        pRouting->VideoInputIndex = InputIndex; 
                        pRouting->VideoOutputIndex = OutputIndex; 
                        pRouting->AudioInputIndex = InputIndexRelated; 
                        pRouting->AudioOutputIndex = OutputIndexRelated; 
                        pRouting->InputPhysicalType = InputPhysicalType; 
                        pRouting->OutputPhysicalType = OutputPhysicalType; 
                        pRouting->Depth = Depth; 
 
                        hr = BuildRoutingList (pPin, &RoutingNext, Depth + 1); 
                         
                        if (hr == S_FALSE)  
                        { 
                            pRouting->pLeftRouting = NULL; 
                            SaveRouting (pRouting); 
                        } 
                    } // if we can route 
 
                } // if its a video pin 
 
            } // for all input pins 
 
            pXbar->Release(); 
        } 
        else  
        { 
            // The filter doesn't support IAMCrossbar, so this 
            // is a terminal pin 
            pinInfo.pFilter->Release(); 
            pStartingOutputPin->Release (); 
 
            return (Depth == 0) ? E_FAIL : S_FALSE; 
        } 
 
        pinInfo.pFilter->Release(); 
    } 
 
    pStartingOutputPin->Release (); 
 
    return S_OK; 
} 
 
// 
// Make a copy of the current routing, and AddRef the IAMCrossbar 
// interfaces. 
// 
 
HRESULT CCrossbar::SaveRouting (CRouting *pRoutingNew) 
{ 
    int Depth = pRoutingNew->Depth + 1; 
    CRouting *pr=0; 
    CRouting *pCurrent = pRoutingNew; 
 
    if (!pRoutingNew || !m_RoutingList) 
        return E_POINTER; 
 
    DbgLog((LOG_TRACE,3,TEXT("CCrossbar::SaveRouting, Depth=%d, NumberOfRoutings=%d"),  
            Depth, m_RoutingList->GetCount() + 1)); 
 
    pr = new CRouting[Depth]; 
    if (pr == NULL) 
        return E_FAIL; 
 
    m_RoutingList->AddTail (pr); 
 
    for (int j = 0; j < Depth; j++, pr++)  
    { 
        *pr = *pCurrent; 
        ASSERT (pCurrent->pXbar != NULL); 
 
        // 
        // We're holding onto this interface, so AddRef 
        // 
        pCurrent->pXbar->AddRef(); 
        pCurrent = pCurrent->pRightRouting; 
 
        // 
        // Pointers were stack based during recursive search, so update them 
        // in the allocated array 
        // 
        pr->pLeftRouting  = pr - 1; 
        pr->pRightRouting = pr + 1; 
 
        if (j == 0) {                   // first element 
            pr->pLeftRouting = NULL; 
        }  
        if (j == (Depth - 1)) {  // last element 
            pr->pRightRouting = NULL; 
        } 
    } 
 
    return S_OK; 
} 
 
 
HRESULT CCrossbar::DestroyRoutingList() 
{ 
    int k, Depth; 
    CRouting *pCurrent=0, *pFirst=0; 
 
    if (!m_RoutingList) 
        return E_POINTER; 
 
    DbgLog((LOG_TRACE,3,TEXT("DestroyRoutingList"))); 
 
    while (m_RoutingList->GetCount())  
    { 
        pCurrent = pFirst = m_RoutingList->RemoveHead(); 
 
        if (pCurrent) 
        { 
            Depth = pCurrent->Depth + 1; 
 
            for (k = 0; k < Depth; k++)  
            { 
                ASSERT (pCurrent->pXbar != NULL); 
 
                // Release the crossbar interface 
                pCurrent->pXbar->Release(); 
 
                // Move to the next node in the list 
                pCurrent = pCurrent->pRightRouting; 
            } 
        } 
         
        delete [] pFirst; 
    } 
 
    return S_OK; 
} 
 
 
// 
// Does not AddRef the returned *Pin  
// 
HRESULT CCrossbar::GetCrossbarIPinAtIndex( 
   IAMCrossbar *pXbar, 
   LONG PinIndex, 
   BOOL IsInputPin, 
   IPin ** ppPin) 
{ 
    LONG         cntInPins, cntOutPins; 
    IPin        *pP = 0; 
    IBaseFilter *pFilter = NULL; 
    IEnumPins   *pins=0; 
    ULONG        n; 
    HRESULT      hr; 
 
    if (!pXbar || !ppPin) 
        return E_POINTER; 
 
    *ppPin = 0; 
 
    if(S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins)) 
        return E_FAIL; 
 
    LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins; 
 
    hr = pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter); 
 
    if (hr == S_OK)  
    { 
        if(SUCCEEDED(pFilter->EnumPins(&pins)))  
        { 
            LONG i=0; 
            while(pins->Next(1, &pP, &n) == S_OK)  
            { 
                pP->Release(); 
                if (i == TrueIndex)  
                { 
                    *ppPin = pP; 
                    break; 
                } 
                i++; 
            } 
            pins->Release(); 
        } 
        pFilter->Release(); 
    } 
     
    return *ppPin ? S_OK : E_FAIL;  
} 
 
 
// 
// Find corresponding index of an IPin on a crossbar 
// 
HRESULT CCrossbar::GetCrossbarIndexFromIPin ( 
    IAMCrossbar * pXbar, 
    LONG * PinIndex, 
    BOOL IsInputPin, 
    IPin * pPin) 
{ 
    LONG         cntInPins, cntOutPins; 
    IPin        *pP = 0; 
    IBaseFilter *pFilter = NULL; 
    IEnumPins   *pins = 0; 
    ULONG        n; 
    BOOL         fOK = FALSE; 
    HRESULT      hr; 
 
    if (!pXbar || !PinIndex || !pPin) 
        return E_POINTER; 
 
    if(S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins)) 
        return E_FAIL; 
 
    hr = pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter); 
 
    if (hr == S_OK)  
    { 
        if(SUCCEEDED(pFilter->EnumPins(&pins)))  
        { 
            LONG i=0; 
         
            while(pins->Next(1, &pP, &n) == S_OK)  
            { 
                pP->Release(); 
                if (pPin == pP)  
                { 
                    *PinIndex = IsInputPin ? i : i - cntInPins; 
                    fOK = TRUE; 
                    break; 
                } 
                i++; 
            } 
            pins->Release(); 
        } 
        pFilter->Release(); 
    } 
     
    return fOK ? S_OK : E_FAIL;  
} 
 
 
// 
// How many unique video inputs can be selected? 
// 
HRESULT CCrossbar::GetInputCount (LONG *pCount) 
{ 
    if (pCount && m_RoutingList) 
    { 
        *pCount = m_RoutingList->GetCount(); 
        return S_OK; 
    } 
    else 
        return E_POINTER; 
} 
 
 
// 
// What is the physical type of a given input? 
// 
HRESULT CCrossbar::GetInputType ( 
    LONG Index,  
    LONG * plPhysicalType) 
{ 
    if (!plPhysicalType || !m_RoutingList) 
        return E_POINTER; 
 
    CRouting *pCurrent = m_RoutingList->GetHead(); 
 
    if (Index >= m_RoutingList->GetCount()) { 
        return E_FAIL; 
    } 
 
    POSITION pos = m_RoutingList->GetHeadPosition(); 
 
    for (int j = 0; j <= Index; j++) {   
       pCurrent = m_RoutingList->GetNext(pos); 
    } 
    ASSERT (pCurrent != NULL); 
 
    *plPhysicalType = pCurrent->InputPhysicalType; 
 
    return S_OK; 
} 
 
 
// 
// Converts a PinType into a String 
// 
BOOL  CCrossbar::StringFromPinType (TCHAR *pc, int nSize, long lType) 
{ 
    TCHAR *pcT; 
    BOOL bSuccess; 
 
    if (!pc || !nSize) 
        return FALSE; 
 
    switch (lType)  
    {    
        case PhysConn_Video_Tuner:           pcT = TEXT("Video Tuner\0");          break; 
        case PhysConn_Video_Composite:       pcT = TEXT("Video Composite\0");      break; 
        case PhysConn_Video_SVideo:          pcT = TEXT("Video SVideo\0");         break; 
        case PhysConn_Video_RGB:             pcT = TEXT("Video RGB\0");            break; 
        case PhysConn_Video_YRYBY:           pcT = TEXT("Video YRYBY\0");          break; 
        case PhysConn_Video_SerialDigital:   pcT = TEXT("Video SerialDigital\0");  break; 
        case PhysConn_Video_ParallelDigital: pcT = TEXT("Video ParallelDigital\0");break; 
        case PhysConn_Video_SCSI:            pcT = TEXT("Video SCSI\0");           break; 
        case PhysConn_Video_AUX:             pcT = TEXT("Video AUX\0");            break; 
        case PhysConn_Video_1394:            pcT = TEXT("Video 1394\0");           break; 
        case PhysConn_Video_USB:             pcT = TEXT("Video USB\0");            break; 
        case PhysConn_Video_VideoDecoder:    pcT = TEXT("Video Decoder\0");        break; 
        case PhysConn_Video_VideoEncoder:    pcT = TEXT("Video Encoder\0");        break; 
     
        case PhysConn_Audio_Tuner:           pcT = TEXT("Audio Tuner\0");          break; 
        case PhysConn_Audio_Line:            pcT = TEXT("Audio Line\0");           break; 
        case PhysConn_Audio_Mic:             pcT = TEXT("Audio Mic\0");            break; 
        case PhysConn_Audio_AESDigital:      pcT = TEXT("Audio AESDigital\0");     break; 
        case PhysConn_Audio_SPDIFDigital:    pcT = TEXT("Audio SPDIFDigital\0");   break; 
        case PhysConn_Audio_SCSI:            pcT = TEXT("Audio SCSI\0");           break; 
        case PhysConn_Audio_AUX:             pcT = TEXT("Audio AUX\0");            break; 
        case PhysConn_Audio_1394:            pcT = TEXT("Audio 1394\0");           break; 
        case PhysConn_Audio_USB:             pcT = TEXT("Audio USB\0");            break; 
        case PhysConn_Audio_AudioDecoder:    pcT = TEXT("Audio Decoder\0");        break; 
     
        default: 
            pcT = TEXT("Unknown\0"); 
            break; 
    } 
     
    // return TRUE on sucessful copy 
    if (lstrcpyn (pc, pcT, nSize) != NULL) 
        bSuccess = TRUE; 
    else 
        bSuccess = FALSE; 
     
    return (bSuccess); 
} 
 
 
// 
// Get a text version of an input 
// 
// Return S_OK if the buffer is large enough to copy the string name 
// 
HRESULT CCrossbar::GetInputName ( 
    LONG   Index,  
    TCHAR *pName,  
    LONG   Size) 
{ 
    if (!m_RoutingList) 
        return E_POINTER; 
 
    CRouting *pCurrent = m_RoutingList->GetHead(); 
 
    if ((Index >= m_RoutingList->GetCount()) || (pName == NULL)) { 
        return E_FAIL; 
    } 
 
    POSITION pos = m_RoutingList->GetHeadPosition(); 
 
    for (int j = 0; j <= Index; j++) {  
       pCurrent = m_RoutingList->GetNext(pos); 
    } 
    ASSERT (pCurrent != NULL); 
 
    return (StringFromPinType (pName, Size, pCurrent->InputPhysicalType) ? 
            S_OK : E_FAIL); 
} 
 
 
// 
// Select an input  
// 
HRESULT CCrossbar::SetInputIndex ( 
    LONG Index) 
{ 
    HRESULT hr = E_FAIL; 
 
    if (!m_RoutingList) 
        return E_POINTER; 
 
    CRouting *pCurrent = m_RoutingList->GetHead(); 
    int j; 
 
    if (Index >= m_RoutingList->GetCount()) 
        return hr; 
 
    POSITION pos = m_RoutingList->GetHeadPosition(); 
    for (j = 0; j <= Index; j++) {  
       pCurrent = m_RoutingList->GetNext(pos); 
    } 
 
    ASSERT (pCurrent != NULL); 
 
    int Depth= pCurrent->Depth + 1; 
 
    for (j = 0; j < Depth; j++)  
    { 
        hr = pCurrent->pXbar->Route (pCurrent->VideoOutputIndex, pCurrent->VideoInputIndex); 
        ASSERT (S_OK == hr); 
 
        if ((pCurrent->AudioOutputIndex != -1) && (pCurrent->AudioInputIndex != -1)) { 
            EXECUTE_ASSERT (S_OK == pCurrent->pXbar->Route (pCurrent->AudioOutputIndex,  
                            pCurrent->AudioInputIndex)); 
        } 
 
        DbgLog((LOG_TRACE,3,TEXT("CCrossbar::Routing, VideoOutIndex=%d VideoInIndex=%d"),  
                pCurrent->VideoOutputIndex, pCurrent->VideoInputIndex)); 
 
        pCurrent++; 
    } 
 
    m_CurrentRoutingIndex = Index; 
 
    return hr; 
} 
 
 
// 
// What input is currently selected? 
// 
HRESULT CCrossbar::GetInputIndex ( 
    LONG *plIndex) 
{ 
    if (plIndex) 
    {     
        *plIndex = m_CurrentRoutingIndex; 
        return S_OK; 
    } 
    else 
        return E_POINTER; 
}