//------------------------------------------------------------------------------ // 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" #include //------------------------------------------------------------------------------ // 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 (SUCCEEDED(StringCbCopy(pc, nSize, pcT))) 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; }