]> git.sesse.net Git - vlc/blob - modules/access/dshow/crossbar.cpp
FSF address change.
[vlc] / modules / access / dshow / crossbar.cpp
1 /*****************************************************************************
2  * crossbar.c : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 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 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/vout.h>
34
35 #ifndef _MSC_VER
36     /* Work-around a bug in w32api-2.5 */
37 #   define QACONTAINERFLAGS QACONTAINERFLAGS_ANOTHERSOMETHINGELSE
38 #endif
39
40 #include "common.h"
41
42 /*****************************************************************************
43  * DeleteCrossbarRoutes
44  *****************************************************************************/
45 void DeleteCrossbarRoutes( access_sys_t *p_sys )
46 {
47     /* Remove crossbar filters from graph */
48     for( int i = 0; i < p_sys->i_crossbar_route_depth; i++ )
49     {
50         p_sys->crossbar_routes[i].pXbar->Release();
51     }
52     p_sys->i_crossbar_route_depth = 0;
53 }
54
55 /*****************************************************************************
56  * RouteCrossbars (Does not AddRef the returned *Pin)
57  *****************************************************************************/
58 static HRESULT GetCrossbarIPinAtIndex( IAMCrossbar *pXbar, LONG PinIndex,
59                                        BOOL IsInputPin, IPin ** ppPin )
60 {
61     LONG         cntInPins, cntOutPins;
62     IPin        *pP = 0;
63     IBaseFilter *pFilter = NULL;
64     IEnumPins   *pins=0;
65     ULONG        n;
66
67     if( !pXbar || !ppPin ) return E_POINTER;
68
69     *ppPin = 0;
70
71     if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) ) return E_FAIL;
72
73     LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
74
75     if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
76     {
77         if( SUCCEEDED(pFilter->EnumPins(&pins)) ) 
78         {
79             LONG i = 0;
80             while( pins->Next(1, &pP, &n) == S_OK ) 
81             {
82                 pP->Release();
83                 if( i == TrueIndex ) 
84                 {
85                     *ppPin = pP;
86                     break;
87                 }
88                 i++;
89             }
90             pins->Release();
91         }
92         pFilter->Release();
93     }
94
95     return *ppPin ? S_OK : E_FAIL; 
96 }
97
98 /*****************************************************************************
99  * GetCrossbarIndexFromIPin: Find corresponding index of an IPin on a crossbar
100  *****************************************************************************/
101 static HRESULT GetCrossbarIndexFromIPin( IAMCrossbar * pXbar, LONG * PinIndex,
102                                          BOOL IsInputPin, IPin * pPin )
103 {
104     LONG         cntInPins, cntOutPins;
105     IPin        *pP = 0;
106     IBaseFilter *pFilter = NULL;
107     IEnumPins   *pins = 0;
108     ULONG        n;
109     BOOL         fOK = FALSE;
110
111     if(!pXbar || !PinIndex || !pPin )
112         return E_POINTER;
113
114     if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) )
115         return E_FAIL;
116
117     if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
118     {
119         if( SUCCEEDED(pFilter->EnumPins(&pins)) )
120         {
121             LONG i=0;
122
123             while( pins->Next(1, &pP, &n) == S_OK )
124             {
125                 pP->Release();
126                 if( pPin == pP )
127                 {
128                     *PinIndex = IsInputPin ? i : i - cntInPins;
129                     fOK = TRUE;
130                     break;
131                 }
132                 i++;
133             }
134             pins->Release();
135         }
136         pFilter->Release();
137     }
138
139     return fOK ? S_OK : E_FAIL; 
140 }
141
142 /*****************************************************************************
143  * FindCrossbarRoutes
144  *****************************************************************************/
145 HRESULT FindCrossbarRoutes( vlc_object_t *p_this, access_sys_t *p_sys,
146                             IPin *p_input_pin, LONG physicalType, int depth )
147 {
148     HRESULT result = S_FALSE;
149
150     IPin *p_output_pin;
151     if( FAILED(p_input_pin->ConnectedTo(&p_output_pin)) ) return S_FALSE;
152
153     // It is connected, so now find out if the filter supports IAMCrossbar
154     PIN_INFO pinInfo;
155     if( FAILED(p_output_pin->QueryPinInfo(&pinInfo)) ||
156         PINDIR_OUTPUT != pinInfo.dir )
157     {
158         p_output_pin->Release ();
159         return S_FALSE;
160     }
161
162     IAMCrossbar *pXbar=0;
163     if( FAILED(pinInfo.pFilter->QueryInterface(IID_IAMCrossbar,
164                                                (void **)&pXbar)) )
165     {
166         pinInfo.pFilter->Release();
167         p_output_pin->Release ();
168         return S_FALSE;
169     }
170
171     LONG inputPinCount, outputPinCount;
172     if( FAILED(pXbar->get_PinCounts(&outputPinCount, &inputPinCount)) )
173     {
174         pXbar->Release();
175         pinInfo.pFilter->Release();
176         p_output_pin->Release ();
177         return S_FALSE;
178     }
179
180     LONG inputPinIndexRelated, outputPinIndexRelated;
181     LONG inputPinPhysicalType = 0, outputPinPhysicalType;
182     LONG inputPinIndex = 0, outputPinIndex;
183     if( FAILED(GetCrossbarIndexFromIPin( pXbar, &outputPinIndex,
184                                          FALSE, p_output_pin )) ||
185         FAILED(pXbar->get_CrossbarPinInfo( FALSE, outputPinIndex,
186                                            &outputPinIndexRelated,
187                                            &outputPinPhysicalType )) )
188     {
189         pXbar->Release();
190         pinInfo.pFilter->Release();
191         p_output_pin->Release ();
192         return S_FALSE;
193     }
194
195     /*
196     ** if physical type is 0, then use default/existing route to physical connector
197     */
198     if( physicalType == 0 )
199     {
200         /* use following as default connector type if we fail to find an existing route */
201         physicalType = PhysConn_Video_Tuner;
202         if( SUCCEEDED(pXbar->get_IsRoutedTo(outputPinIndex, &inputPinIndex)) )
203         {
204
205             if( SUCCEEDED( pXbar->get_CrossbarPinInfo( TRUE,  inputPinIndex,
206                            &inputPinIndexRelated, &inputPinPhysicalType )) )
207             {
208                 // remember connector type
209                 physicalType = inputPinPhysicalType;
210                 
211                 msg_Dbg( p_this, "Found Existing Route For ouput %ld (type %ld) to input %ld (type %ld)",
212                          outputPinIndex, outputPinPhysicalType, inputPinIndex,
213                          inputPinPhysicalType );
214                          
215                 // fall through to for loop, note 'inputPinIndex' is set to the pin we are looking for
216                 // hence, loop iteration should not wind back
217
218             }
219         }
220         else {
221             // reset to first pin for complete loop iteration
222             inputPinIndex = 0;
223         }
224     }                  
225          
226     //
227     // for all input pins
228     //
229     for( /* inputPinIndex has been set */ ; (S_OK != result) && (inputPinIndex < inputPinCount); ++inputPinIndex )
230     {
231         if( FAILED(pXbar->get_CrossbarPinInfo( TRUE,  inputPinIndex,
232             &inputPinIndexRelated, &inputPinPhysicalType )) ) continue;
233
234         // Is this pin matching required connector physical type?
235         if( inputPinPhysicalType != physicalType ) continue;
236
237         // Can we route it?
238         if( FAILED(pXbar->CanRoute(outputPinIndex, inputPinIndex)) ) continue;
239             
240    
241         IPin *pPin;
242         if( FAILED(GetCrossbarIPinAtIndex( pXbar, inputPinIndex,
243                                            TRUE, &pPin)) ) continue;
244
245         result = FindCrossbarRoutes( p_this, p_sys, pPin,
246                                      physicalType, depth+1 );
247
248         if( S_OK == result || (S_FALSE == result &&
249             physicalType == inputPinPhysicalType &&
250             (p_sys->i_crossbar_route_depth = depth+1) < MAX_CROSSBAR_DEPTH) )
251         {
252             // hold on crossbar, will be released when graph is destroyed
253             pXbar->AddRef();
254
255             // remember crossbar route
256             p_sys->crossbar_routes[depth].pXbar = pXbar;
257             p_sys->crossbar_routes[depth].VideoInputIndex = inputPinIndex;
258             p_sys->crossbar_routes[depth].VideoOutputIndex = outputPinIndex;
259             p_sys->crossbar_routes[depth].AudioInputIndex = inputPinIndexRelated;
260             p_sys->crossbar_routes[depth].AudioOutputIndex = outputPinIndexRelated;
261
262             msg_Dbg( p_this, "Crossbar at depth %d, Found Route For "
263                      "ouput %ld (type %ld) to input %ld (type %ld)", depth,
264                      outputPinIndex, outputPinPhysicalType, inputPinIndex,
265                      inputPinPhysicalType );
266
267             result = S_OK;
268         }
269     }
270
271     pXbar->Release();
272     pinInfo.pFilter->Release();
273     p_output_pin->Release ();
274
275     return result;
276 }