1 /*****************************************************************************
2 * crossbar.c : DirectShow access module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002, 2004, 2009 the VideoLAN team
7 * Author: Damien Fouilleul <damien dot fouilleul at laposte dot net>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
35 /* Work-around a bug in w32api-2.5 */
36 # define QACONTAINERFLAGS QACONTAINERFLAGS_ANOTHERSOMETHINGELSE
40 #include "vlc_dshow.h"
42 // Helper function to associate a crossbar pin name with the type.
43 static const char * GetPhysicalPinName(long lType)
47 case PhysConn_Video_Tuner: return "Video Tuner";
48 case PhysConn_Video_Composite: return "Video Composite";
49 case PhysConn_Video_SVideo: return "S-Video";
50 case PhysConn_Video_RGB: return "Video RGB";
51 case PhysConn_Video_YRYBY: return "Video YRYBY";
52 case PhysConn_Video_SerialDigital: return "Video Serial Digital";
53 case PhysConn_Video_ParallelDigital: return "Video Parallel Digital";
54 case PhysConn_Video_SCSI: return "Video SCSI";
55 case PhysConn_Video_AUX: return "Video AUX";
56 case PhysConn_Video_1394: return "Video 1394";
57 case PhysConn_Video_USB: return "Video USB";
58 case PhysConn_Video_VideoDecoder: return "Video Decoder";
59 case PhysConn_Video_VideoEncoder: return "Video Encoder";
61 case PhysConn_Audio_Tuner: return "Audio Tuner";
62 case PhysConn_Audio_Line: return "Audio Line";
63 case PhysConn_Audio_Mic: return "Audio Microphone";
64 case PhysConn_Audio_AESDigital: return "Audio AES/EBU Digital";
65 case PhysConn_Audio_SPDIFDigital: return "Audio S/PDIF";
66 case PhysConn_Audio_SCSI: return "Audio SCSI";
67 case PhysConn_Audio_AUX: return "Audio AUX";
68 case PhysConn_Audio_1394: return "Audio 1394";
69 case PhysConn_Audio_USB: return "Audio USB";
70 case PhysConn_Audio_AudioDecoder: return "Audio Decoder";
72 default: return "Unknown Type";
75 /*****************************************************************************
76 * DeleteCrossbarRoutes
77 *****************************************************************************/
78 void DeleteCrossbarRoutes( access_sys_t *p_sys )
80 /* Remove crossbar filters from graph */
81 for( int i = 0; i < p_sys->i_crossbar_route_depth; i++ )
83 p_sys->crossbar_routes[i].pXbar->Release();
85 p_sys->i_crossbar_route_depth = 0;
88 /*****************************************************************************
89 * RouteCrossbars (Does not AddRef the returned *Pin)
90 *****************************************************************************/
91 static HRESULT GetCrossbarIPinAtIndex( IAMCrossbar *pXbar, LONG PinIndex,
92 BOOL IsInputPin, IPin ** ppPin )
94 LONG cntInPins, cntOutPins;
96 IBaseFilter *pFilter = NULL;
97 IEnumPins *pins = NULL;
100 if( !pXbar || !ppPin ) return E_POINTER;
104 if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) ) return E_FAIL;
106 LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
108 if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
110 if( SUCCEEDED(pFilter->EnumPins(&pins)) )
113 while( pins->Next(1, &pP, &n) == S_OK )
128 return *ppPin ? S_OK : E_FAIL;
131 /*****************************************************************************
132 * GetCrossbarIndexFromIPin: Find corresponding index of an IPin on a crossbar
133 *****************************************************************************/
134 static HRESULT GetCrossbarIndexFromIPin( IAMCrossbar * pXbar, LONG * PinIndex,
135 BOOL IsInputPin, IPin * pPin )
137 LONG cntInPins, cntOutPins;
139 IBaseFilter *pFilter = NULL;
140 IEnumPins *pins = NULL;
144 if(!pXbar || !PinIndex || !pPin )
147 if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) )
150 if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
152 if( SUCCEEDED(pFilter->EnumPins(&pins)) )
156 while( pins->Next(1, &pP, &n) == S_OK )
161 *PinIndex = IsInputPin ? i : i - cntInPins;
172 return fOK ? S_OK : E_FAIL;
175 /*****************************************************************************
177 *****************************************************************************/
178 HRESULT FindCrossbarRoutes( vlc_object_t *p_this, access_sys_t *p_sys,
179 IPin *p_input_pin, LONG physicalType, int depth )
181 HRESULT result = S_FALSE;
184 if( FAILED(p_input_pin->ConnectedTo(&p_output_pin)) ) return S_FALSE;
186 // It is connected, so now find out if the filter supports IAMCrossbar
188 if( FAILED(p_output_pin->QueryPinInfo(&pinInfo)) ||
189 PINDIR_OUTPUT != pinInfo.dir )
191 p_output_pin->Release ();
195 IAMCrossbar *pXbar = NULL;
196 if( FAILED(pinInfo.pFilter->QueryInterface(IID_IAMCrossbar,
199 pinInfo.pFilter->Release();
200 p_output_pin->Release ();
204 LONG inputPinCount, outputPinCount;
205 if( FAILED(pXbar->get_PinCounts(&outputPinCount, &inputPinCount)) )
208 pinInfo.pFilter->Release();
209 p_output_pin->Release ();
213 LONG inputPinIndexRelated, outputPinIndexRelated;
214 LONG inputPinPhysicalType = 0, outputPinPhysicalType;
215 LONG inputPinIndex = 0, outputPinIndex;
216 if( FAILED(GetCrossbarIndexFromIPin( pXbar, &outputPinIndex,
217 FALSE, p_output_pin )) ||
218 FAILED(pXbar->get_CrossbarPinInfo( FALSE, outputPinIndex,
219 &outputPinIndexRelated,
220 &outputPinPhysicalType )) )
223 pinInfo.pFilter->Release();
224 p_output_pin->Release ();
229 ** if physical type is 0, then use default/existing route to physical connector
231 if( physicalType == 0 )
233 /* use following as default connector type if we fail to find an existing route */
234 physicalType = PhysConn_Video_Tuner;
235 if( SUCCEEDED(pXbar->get_IsRoutedTo(outputPinIndex, &inputPinIndex)) )
238 if( SUCCEEDED( pXbar->get_CrossbarPinInfo( TRUE, inputPinIndex,
239 &inputPinIndexRelated, &inputPinPhysicalType )) )
241 // remember connector type
242 physicalType = inputPinPhysicalType;
244 msg_Dbg( p_this, "found existing route for output %ld (type %s) to input %ld (type %s)",
245 outputPinIndex, GetPhysicalPinName( outputPinPhysicalType ),
246 inputPinIndex, GetPhysicalPinName( inputPinPhysicalType ) );
248 // fall through to for loop, note 'inputPinIndex' is set to the pin we are looking for
249 // hence, loop iteration should not wind back
254 // reset to first pin for complete loop iteration
260 // for all input pins
262 for( /* inputPinIndex has been set */ ; (S_OK != result) && (inputPinIndex < inputPinCount); ++inputPinIndex )
264 if( FAILED(pXbar->get_CrossbarPinInfo( TRUE, inputPinIndex,
265 &inputPinIndexRelated, &inputPinPhysicalType )) ) continue;
267 // Is this pin matching required connector physical type?
268 if( inputPinPhysicalType != physicalType ) continue;
271 if( FAILED(pXbar->CanRoute(outputPinIndex, inputPinIndex)) ) continue;
275 if( FAILED(GetCrossbarIPinAtIndex( pXbar, inputPinIndex,
276 TRUE, &pPin)) ) continue;
278 result = FindCrossbarRoutes( p_this, p_sys, pPin,
279 physicalType, depth+1 );
281 if( S_OK == result || (S_FALSE == result &&
282 physicalType == inputPinPhysicalType &&
283 (p_sys->i_crossbar_route_depth = depth+1) < MAX_CROSSBAR_DEPTH) )
285 // hold on crossbar, will be released when graph is destroyed
288 // remember crossbar route
289 p_sys->crossbar_routes[depth].pXbar = pXbar;
290 p_sys->crossbar_routes[depth].VideoInputIndex = inputPinIndex;
291 p_sys->crossbar_routes[depth].VideoOutputIndex = outputPinIndex;
292 p_sys->crossbar_routes[depth].AudioInputIndex = inputPinIndexRelated;
293 p_sys->crossbar_routes[depth].AudioOutputIndex = outputPinIndexRelated;
295 msg_Dbg( p_this, "crossbar at depth %d, found route for "
296 "output %ld (type %s) to input %ld (type %s)", depth,
297 outputPinIndex, GetPhysicalPinName( outputPinPhysicalType ),
298 inputPinIndex, GetPhysicalPinName( inputPinPhysicalType ) );
305 pinInfo.pFilter->Release();
306 p_output_pin->Release ();