]> git.sesse.net Git - vlc/blob - modules/access/dshow/crossbar.cpp
* modules/access/dshow/*:
[vlc] / modules / access / dshow / crossbar.cpp
1 /*****************************************************************************
2  * crossbar.c : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, 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 #include "common.h"
36
37 /*****************************************************************************
38  * DeleteCrossbarRoutes
39  *****************************************************************************/
40 void DeleteCrossbarRoutes( access_sys_t *p_sys )
41 {
42     /* Remove crossbar filters from graph */
43     for( int i = 0; i < p_sys->i_crossbar_route_depth; i++ )
44     {
45         p_sys->crossbar_routes[i].pXbar->Release();
46     }
47     p_sys->i_crossbar_route_depth = 0;
48 }
49
50 /*****************************************************************************
51  * RouteCrossbars (Does not AddRef the returned *Pin)
52  *****************************************************************************/
53 static HRESULT GetCrossbarIPinAtIndex( IAMCrossbar *pXbar, LONG PinIndex,
54                                        BOOL IsInputPin, IPin ** ppPin )
55 {
56     LONG         cntInPins, cntOutPins;
57     IPin        *pP = 0;
58     IBaseFilter *pFilter = NULL;
59     IEnumPins   *pins=0;
60     ULONG        n;
61
62     if( !pXbar || !ppPin ) return E_POINTER;
63
64     *ppPin = 0;
65
66     if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) ) return E_FAIL;
67
68     LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
69
70     if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
71     {
72         if( SUCCEEDED(pFilter->EnumPins(&pins)) ) 
73         {
74             LONG i = 0;
75             while( pins->Next(1, &pP, &n) == S_OK ) 
76             {
77                 pP->Release();
78                 if( i == TrueIndex ) 
79                 {
80                     *ppPin = pP;
81                     break;
82                 }
83                 i++;
84             }
85             pins->Release();
86         }
87         pFilter->Release();
88     }
89
90     return *ppPin ? S_OK : E_FAIL; 
91 }
92
93 /*****************************************************************************
94  * GetCrossbarIndexFromIPin: Find corresponding index of an IPin on a crossbar
95  *****************************************************************************/
96 static HRESULT GetCrossbarIndexFromIPin( IAMCrossbar * pXbar, LONG * PinIndex,
97                                          BOOL IsInputPin, IPin * pPin )
98 {
99     LONG         cntInPins, cntOutPins;
100     IPin        *pP = 0;
101     IBaseFilter *pFilter = NULL;
102     IEnumPins   *pins = 0;
103     ULONG        n;
104     BOOL         fOK = FALSE;
105
106     if(!pXbar || !PinIndex || !pPin )
107         return E_POINTER;
108
109     if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) )
110         return E_FAIL;
111
112     if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
113     {
114         if( SUCCEEDED(pFilter->EnumPins(&pins)) )
115         {
116             LONG i=0;
117
118             while( pins->Next(1, &pP, &n) == S_OK )
119             {
120                 pP->Release();
121                 if( pPin == pP )
122                 {
123                     *PinIndex = IsInputPin ? i : i - cntInPins;
124                     fOK = TRUE;
125                     break;
126                 }
127                 i++;
128             }
129             pins->Release();
130         }
131         pFilter->Release();
132     }
133
134     return fOK ? S_OK : E_FAIL; 
135 }
136
137 /*****************************************************************************
138  * FindCrossbarRoutes
139  *****************************************************************************/
140 HRESULT FindCrossbarRoutes( vlc_object_t *p_this, access_sys_t *p_sys,
141                             IPin *p_input_pin, LONG physicalType, int depth )
142 {
143     HRESULT result = S_FALSE;
144
145     IPin *p_output_pin;
146     if( FAILED(p_input_pin->ConnectedTo(&p_output_pin)) ) return S_FALSE;
147
148     // It is connected, so now find out if the filter supports IAMCrossbar
149     PIN_INFO pinInfo;
150     if( FAILED(p_output_pin->QueryPinInfo(&pinInfo)) ||
151         PINDIR_OUTPUT != pinInfo.dir )
152     {
153         p_output_pin->Release ();
154         return S_FALSE;
155     }
156
157     IAMCrossbar *pXbar=0;
158     if( FAILED(pinInfo.pFilter->QueryInterface(IID_IAMCrossbar,
159                                                (void **)&pXbar)) )
160     {
161         pinInfo.pFilter->Release();
162         p_output_pin->Release ();
163         return S_FALSE;
164     }
165
166     LONG inputPinCount, outputPinCount;
167     if( FAILED(pXbar->get_PinCounts(&outputPinCount, &inputPinCount)) )
168     {
169         pXbar->Release();
170         pinInfo.pFilter->Release();
171         p_output_pin->Release ();
172         return S_FALSE;
173     }
174
175     LONG inputPinIndexRelated, outputPinIndexRelated;
176     LONG inputPinPhysicalType, outputPinPhysicalType;
177     LONG inputPinIndex, outputPinIndex;
178     if( FAILED(GetCrossbarIndexFromIPin( pXbar, &outputPinIndex,
179                                          FALSE, p_output_pin )) ||
180         FAILED(pXbar->get_CrossbarPinInfo( FALSE, outputPinIndex,
181                                            &outputPinIndexRelated,
182                                            &outputPinPhysicalType )) )
183     {
184         pXbar->Release();
185         pinInfo.pFilter->Release();
186         p_output_pin->Release ();
187         return S_FALSE;
188     }
189
190     //
191     // for all input pins
192     //
193     for( inputPinIndex = 0; S_OK != result && inputPinIndex < inputPinCount;
194          inputPinIndex++ ) 
195     {
196         if( FAILED(pXbar->get_CrossbarPinInfo( TRUE,  inputPinIndex,
197                 &inputPinIndexRelated, &inputPinPhysicalType )) ) continue;
198    
199         // Is the pin a video pin?
200         if( inputPinPhysicalType != physicalType ) continue;
201
202         // Can we route it?
203         if( FAILED(pXbar->CanRoute(outputPinIndex, inputPinIndex)) ) continue;
204
205         IPin *pPin;
206         if( FAILED(GetCrossbarIPinAtIndex( pXbar, inputPinIndex,
207                                            TRUE, &pPin)) ) continue;
208
209         result = FindCrossbarRoutes( p_this, p_sys, pPin,
210                                      physicalType, depth+1 );
211
212         if( S_OK == result || (S_FALSE == result &&
213             physicalType == inputPinPhysicalType &&
214             (p_sys->i_crossbar_route_depth = depth+1) < MAX_CROSSBAR_DEPTH) )
215         {
216             // hold on crossbar
217             pXbar->AddRef();
218
219             // remember crossbar route
220             p_sys->crossbar_routes[depth].pXbar = pXbar;
221             p_sys->crossbar_routes[depth].VideoInputIndex = inputPinIndex;
222             p_sys->crossbar_routes[depth].VideoOutputIndex = outputPinIndex;
223             p_sys->crossbar_routes[depth].AudioInputIndex = inputPinIndexRelated;
224             p_sys->crossbar_routes[depth].AudioOutputIndex = outputPinIndexRelated;
225
226             msg_Dbg( p_this, "Crossbar at depth %d, Found Route For "
227                      "ouput %ld (type %ld) to input %ld (type %ld)", depth,
228                      outputPinIndex, outputPinPhysicalType, inputPinIndex,
229                      inputPinPhysicalType );
230
231             result = S_OK;
232         }
233     }
234
235     pXbar->Release();
236     pinInfo.pFilter->Release();
237     p_output_pin->Release ();
238
239     return result;
240 }