]> git.sesse.net Git - vlc/blob - modules/access/dshow/crossbar.cpp
Qt: use %tmp%/$TMP folder for updates
[vlc] / modules / access / dshow / crossbar.cpp
1 /*****************************************************************************
2  * crossbar.c : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002, 2004, 2009 the VideoLAN team
5  * $Id$
6  *
7  * Author: Damien Fouilleul <damien dot fouilleul at laposte dot net>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33
34 #ifndef _MSC_VER
35     /* Work-around a bug in w32api-2.5 */
36 #   define QACONTAINERFLAGS QACONTAINERFLAGS_ANOTHERSOMETHINGELSE
37 #endif
38
39 #include "access.h"
40 #include "vlc_dshow.h"
41
42 // Helper function to associate a crossbar pin name with the type.
43 static const char * GetPhysicalPinName(long lType)
44 {
45     switch (lType)
46     {
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";
60
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";
71
72     default:                              return "Unknown Type";
73     }
74 }
75 /*****************************************************************************
76  * DeleteCrossbarRoutes
77  *****************************************************************************/
78 void DeleteCrossbarRoutes( access_sys_t *p_sys )
79 {
80     /* Remove crossbar filters from graph */
81     for( int i = 0; i < p_sys->i_crossbar_route_depth; i++ )
82     {
83         p_sys->crossbar_routes[i].pXbar->Release();
84     }
85     p_sys->i_crossbar_route_depth = 0;
86 }
87
88 /*****************************************************************************
89  * RouteCrossbars (Does not AddRef the returned *Pin)
90  *****************************************************************************/
91 static HRESULT GetCrossbarIPinAtIndex( IAMCrossbar *pXbar, LONG PinIndex,
92                                        BOOL IsInputPin, IPin ** ppPin )
93 {
94     LONG         cntInPins, cntOutPins;
95     IPin        *pP = NULL;
96     IBaseFilter *pFilter = NULL;
97     IEnumPins   *pins = NULL;
98     ULONG        n;
99
100     if( !pXbar || !ppPin ) return E_POINTER;
101
102     *ppPin = 0;
103
104     if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) ) return E_FAIL;
105
106     LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
107
108     if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
109     {
110         if( SUCCEEDED(pFilter->EnumPins(&pins)) )
111         {
112             LONG i = 0;
113             while( pins->Next(1, &pP, &n) == S_OK )
114             {
115                 pP->Release();
116                 if( i == TrueIndex )
117                 {
118                     *ppPin = pP;
119                     break;
120                 }
121                 i++;
122             }
123             pins->Release();
124         }
125         pFilter->Release();
126     }
127
128     return *ppPin ? S_OK : E_FAIL;
129 }
130
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 )
136 {
137     LONG         cntInPins, cntOutPins;
138     IPin        *pP = NULL;
139     IBaseFilter *pFilter = NULL;
140     IEnumPins   *pins = NULL;
141     ULONG        n;
142     BOOL         fOK = FALSE;
143
144     if(!pXbar || !PinIndex || !pPin )
145         return E_POINTER;
146
147     if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) )
148         return E_FAIL;
149
150     if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
151     {
152         if( SUCCEEDED(pFilter->EnumPins(&pins)) )
153         {
154             LONG i=0;
155
156             while( pins->Next(1, &pP, &n) == S_OK )
157             {
158                 pP->Release();
159                 if( pPin == pP )
160                 {
161                     *PinIndex = IsInputPin ? i : i - cntInPins;
162                     fOK = TRUE;
163                     break;
164                 }
165                 i++;
166             }
167             pins->Release();
168         }
169         pFilter->Release();
170     }
171
172     return fOK ? S_OK : E_FAIL;
173 }
174
175 /*****************************************************************************
176  * FindCrossbarRoutes
177  *****************************************************************************/
178 HRESULT FindCrossbarRoutes( vlc_object_t *p_this, access_sys_t *p_sys,
179                             IPin *p_input_pin, LONG physicalType, int depth )
180 {
181     HRESULT result = S_FALSE;
182
183     IPin *p_output_pin;
184     if( FAILED(p_input_pin->ConnectedTo(&p_output_pin)) ) return S_FALSE;
185
186     // It is connected, so now find out if the filter supports IAMCrossbar
187     PIN_INFO pinInfo;
188     if( FAILED(p_output_pin->QueryPinInfo(&pinInfo)) ||
189         PINDIR_OUTPUT != pinInfo.dir )
190     {
191         p_output_pin->Release ();
192         return S_FALSE;
193     }
194
195     IAMCrossbar *pXbar = NULL;
196     if( FAILED(pinInfo.pFilter->QueryInterface(IID_IAMCrossbar,
197                                                (void **)&pXbar)) )
198     {
199         pinInfo.pFilter->Release();
200         p_output_pin->Release ();
201         return S_FALSE;
202     }
203
204     LONG inputPinCount, outputPinCount;
205     if( FAILED(pXbar->get_PinCounts(&outputPinCount, &inputPinCount)) )
206     {
207         pXbar->Release();
208         pinInfo.pFilter->Release();
209         p_output_pin->Release ();
210         return S_FALSE;
211     }
212
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 )) )
221     {
222         pXbar->Release();
223         pinInfo.pFilter->Release();
224         p_output_pin->Release ();
225         return S_FALSE;
226     }
227
228     /*
229     ** if physical type is 0, then use default/existing route to physical connector
230     */
231     if( physicalType == 0 )
232     {
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)) )
236         {
237
238             if( SUCCEEDED( pXbar->get_CrossbarPinInfo( TRUE,  inputPinIndex,
239                            &inputPinIndexRelated, &inputPinPhysicalType )) )
240             {
241                 // remember connector type
242                 physicalType = inputPinPhysicalType;
243  
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 ) );
247  
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
250
251             }
252         }
253         else {
254             // reset to first pin for complete loop iteration
255             inputPinIndex = 0;
256         }
257     }
258  
259     //
260     // for all input pins
261     //
262     for( /* inputPinIndex has been set */ ; (S_OK != result) && (inputPinIndex < inputPinCount); ++inputPinIndex )
263     {
264         if( FAILED(pXbar->get_CrossbarPinInfo( TRUE,  inputPinIndex,
265             &inputPinIndexRelated, &inputPinPhysicalType )) ) continue;
266
267         // Is this pin matching required connector physical type?
268         if( inputPinPhysicalType != physicalType ) continue;
269
270         // Can we route it?
271         if( FAILED(pXbar->CanRoute(outputPinIndex, inputPinIndex)) ) continue;
272  
273  
274         IPin *pPin;
275         if( FAILED(GetCrossbarIPinAtIndex( pXbar, inputPinIndex,
276                                            TRUE, &pPin)) ) continue;
277
278         result = FindCrossbarRoutes( p_this, p_sys, pPin,
279                                      physicalType, depth+1 );
280
281         if( S_OK == result || (S_FALSE == result &&
282             physicalType == inputPinPhysicalType &&
283             (p_sys->i_crossbar_route_depth = depth+1) < MAX_CROSSBAR_DEPTH) )
284         {
285             // hold on crossbar, will be released when graph is destroyed
286             pXbar->AddRef();
287
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;
294
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 ) );
299
300             result = S_OK;
301         }
302     }
303
304     pXbar->Release();
305     pinInfo.pFilter->Release();
306     p_output_pin->Release ();
307
308     return result;
309 }