+ return fOK ? S_OK : E_FAIL;
+}
+
+/****************************************************************************
+ * FindCrossbarRoutes
+ ****************************************************************************/
+static HRESULT FindCrossbarRoutes( access_t *p_access, IPin *p_input_pin,
+ LONG physicalType, int depth = 0 )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ HRESULT result = S_FALSE;
+
+ IPin *p_output_pin;
+ if( FAILED(p_input_pin->ConnectedTo(&p_output_pin)) ) return S_FALSE;
+
+ // It is connected, so now find out if the filter supports IAMCrossbar
+ PIN_INFO pinInfo;
+ if( FAILED(p_output_pin->QueryPinInfo(&pinInfo)) ||
+ PINDIR_OUTPUT != pinInfo.dir )
+ {
+ p_output_pin->Release ();
+ return S_FALSE;
+ }
+
+ IAMCrossbar *pXbar=0;
+ if( FAILED(pinInfo.pFilter->QueryInterface(IID_IAMCrossbar,
+ (void **)&pXbar)) )
+ {
+ pinInfo.pFilter->Release();
+ p_output_pin->Release ();
+ return S_FALSE;
+ }
+
+ LONG inputPinCount, outputPinCount;
+ if( FAILED(pXbar->get_PinCounts(&outputPinCount, &inputPinCount)) )
+ {
+ pXbar->Release();
+ pinInfo.pFilter->Release();
+ p_output_pin->Release ();
+ return S_FALSE;
+ }
+
+ LONG inputPinIndexRelated, outputPinIndexRelated;
+ LONG inputPinPhysicalType, outputPinPhysicalType;
+ LONG inputPinIndex, outputPinIndex;
+ if( FAILED(GetCrossbarIndexFromIPin( pXbar, &outputPinIndex,
+ FALSE, p_output_pin )) ||
+ FAILED(pXbar->get_CrossbarPinInfo( FALSE, outputPinIndex,
+ &outputPinIndexRelated,
+ &outputPinPhysicalType )) )
+ {
+ pXbar->Release();
+ pinInfo.pFilter->Release();
+ p_output_pin->Release ();
+ return S_FALSE;
+ }
+
+ //
+ // for all input pins
+ //
+ for( inputPinIndex = 0; S_OK != result && inputPinIndex < inputPinCount;
+ inputPinIndex++ )
+ {
+ if( FAILED(pXbar->get_CrossbarPinInfo( TRUE, inputPinIndex,
+ &inputPinIndexRelated, &inputPinPhysicalType )) ) continue;
+
+ // Is the pin a video pin?
+ if( inputPinPhysicalType != physicalType ) continue;
+
+ // Can we route it?
+ if( FAILED(pXbar->CanRoute(outputPinIndex, inputPinIndex)) ) continue;
+
+ IPin *pPin;
+ if( FAILED(GetCrossbarIPinAtIndex( pXbar, inputPinIndex,
+ TRUE, &pPin)) ) continue;
+
+ result = FindCrossbarRoutes( p_access, pPin, physicalType, depth+1 );
+ if( S_OK == result || (S_FALSE == result &&
+ physicalType == inputPinPhysicalType &&
+ (p_sys->i_crossbar_route_depth = depth+1) < MAX_CROSSBAR_DEPTH) )
+ {
+ // hold on crossbar
+ pXbar->AddRef();
+
+ // remember crossbar route
+ p_sys->crossbar_routes[depth].pXbar = pXbar;
+ p_sys->crossbar_routes[depth].VideoInputIndex = inputPinIndex;
+ p_sys->crossbar_routes[depth].VideoOutputIndex = outputPinIndex;
+ p_sys->crossbar_routes[depth].AudioInputIndex = inputPinIndexRelated;
+ p_sys->crossbar_routes[depth].AudioOutputIndex = outputPinIndexRelated;
+
+ msg_Dbg( p_access, "Crossbar at depth %d, Found Route For "
+ "ouput %ld (type %ld) to input %ld (type %ld)", depth,
+ outputPinIndex, outputPinPhysicalType, inputPinIndex,
+ inputPinPhysicalType );
+
+ result = S_OK;
+ }
+ }
+
+ pXbar->Release();
+ pinInfo.pFilter->Release();
+ p_output_pin->Release ();
+
+ return result;
+}
+
+/****************************************************************************
+ * ConnectFilters
+ ****************************************************************************/
+static bool ConnectFilters( access_t *p_access, IBaseFilter *p_filter,
+ CaptureFilter *p_capture_filter )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ CapturePin *p_input_pin = p_capture_filter->CustomGetPin();
+
+ AM_MEDIA_TYPE mediaType = p_input_pin->CustomGetMediaType();
+
+ if( p_sys->p_capture_graph_builder2 )
+ {
+ if( FAILED(p_sys->p_capture_graph_builder2->
+ RenderStream( &PIN_CATEGORY_CAPTURE, &mediaType.majortype,
+ p_filter, NULL,
+ (IBaseFilter *)p_capture_filter )) )
+ {
+ return false;
+ }
+
+ // Sort out all the possible video inputs
+ // The class needs to be given the capture filters ANALOGVIDEO input pin
+ IEnumPins *pins = 0;
+ if( mediaType.majortype == MEDIATYPE_Video &&
+ SUCCEEDED(p_filter->EnumPins(&pins)) )
+ {
+ IPin *pP = 0;
+ ULONG n;
+ PIN_INFO pinInfo;
+ BOOL Found = FALSE;
+ IKsPropertySet *pKs=0;
+ GUID guid;
+ DWORD dw;
+
+ while( !Found && (S_OK == pins->Next(1, &pP, &n)) )
+ {
+ if(S_OK == pP->QueryPinInfo(&pinInfo))
+ {
+ if(pinInfo.dir == PINDIR_INPUT)
+ {
+ // is this pin an ANALOGVIDEOIN input pin?
+ if( pP->QueryInterface(IID_IKsPropertySet,
+ (void **)&pKs) == S_OK )
+ {
+ if( pKs->Get(AMPROPSETID_Pin,
+ AMPROPERTY_PIN_CATEGORY, NULL, 0,
+ &guid, sizeof(GUID), &dw) == S_OK )
+ {
+ if( guid == PIN_CATEGORY_ANALOGVIDEOIN )
+ {
+ // recursively search crossbar routes
+ FindCrossbarRoutes( p_access, pP,
+ PhysConn_Video_Tuner );
+ // found it
+ Found = TRUE;
+ }
+ }
+ pKs->Release();
+ }
+ }
+ pinInfo.pFilter->Release();
+ }
+ pP->Release();
+ }
+ pins->Release();
+ }
+ return true;
+ }
+ else
+ {
+ IEnumPins *p_enumpins;
+ IPin *p_pin;
+
+ if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
+
+ while( S_OK == p_enumpins->Next( 1, &p_pin, NULL ) )
+ {
+ PIN_DIRECTION pin_dir;
+ p_pin->QueryDirection( &pin_dir );
+
+ if( pin_dir == PINDIR_OUTPUT &&
+ p_sys->p_graph->ConnectDirect( p_pin, (IPin *)p_input_pin,
+ 0 ) == S_OK )
+ {
+ p_pin->Release();
+ p_enumpins->Release();
+ return true;
+ }
+ p_pin->Release();
+ }
+
+ p_enumpins->Release();
+ return false;
+ }
+}
+
+/*
+** get fourcc priority from arbritary preference, the higher the better
+*/
+static int GetFourCCPriority(int i_fourcc)
+{
+ switch( i_fourcc )
+ {
+ case VLC_FOURCC('I','4','2','0'):
+ case VLC_FOURCC('f','l','3','2'):
+ {
+ return 9;
+ }
+
+ case VLC_FOURCC('Y','V','1','2'):
+ case VLC_FOURCC('a','r','a','w'):
+ {
+ return 8;
+ }
+
+ case VLC_FOURCC('R','V','2','4'):
+ {
+ return 7;
+ }
+
+ case VLC_FOURCC('Y','U','Y','2'):
+ case VLC_FOURCC('R','V','3','2'):
+ case VLC_FOURCC('R','G','B','A'):
+ {
+ return 6;
+ }
+ }
+ return 0;
+}
+
+#define MAX_MEDIA_TYPES 32
+
+static int OpenDevice( access_t *p_access, string devicename,
+ vlc_bool_t b_audio )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ /* See if device is already opened */
+ for( int i = 0; i < p_sys->i_streams; i++ )
+ {
+ if( p_sys->pp_streams[i]->devicename == devicename )
+ {
+ /* Already opened */
+ return VLC_SUCCESS;
+ }
+ }
+
+ list<string> list_devices;
+
+ /* Enumerate devices and display their names */
+ FindCaptureDevice( (vlc_object_t *)p_access, NULL, &list_devices, b_audio );
+
+ if( !list_devices.size() )
+ return VLC_EGENERIC;
+
+ list<string>::iterator iter;
+ for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
+ msg_Dbg( p_access, "found device: %s", iter->c_str() );
+
+ /* If no device name was specified, pick the 1st one */
+ if( devicename.size() == 0 )
+ {
+ devicename = *list_devices.begin();
+ }
+
+ // Use the system device enumerator and class enumerator to find
+ // a capture/preview device, such as a desktop USB video camera.
+ IBaseFilter *p_device_filter =
+ FindCaptureDevice( (vlc_object_t *)p_access, &devicename,
+ NULL, b_audio );
+ if( p_device_filter )
+ msg_Dbg( p_access, "using device: %s", devicename.c_str() );
+ else
+ {
+ msg_Err( p_access, "can't use device: %s, unsupported device type",
+ devicename.c_str() );