+ for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];
+ if( p_sys->i_streams ) free( p_sys->pp_streams );
+
+ vlc_mutex_destroy( &p_sys->lock );
+ vlc_cond_destroy( &p_sys->wait );
+
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * AccessClose: close device
+ *****************************************************************************/
+static void AccessClose( vlc_object_t *p_this )
+{
+ access_t *p_access = (access_t *)p_this;
+ access_sys_t *p_sys = p_access->p_sys;
+
+ /* Stop capturing stuff */
+ p_sys->p_control->Stop();
+
+ CommonClose( p_this, p_sys );
+}
+
+/*****************************************************************************
+ * DemuxClose: close device
+ *****************************************************************************/
+static void DemuxClose( vlc_object_t *p_this )
+{
+ demux_t *p_demux = (demux_t *)p_this;
+ access_sys_t *p_sys = (access_sys_t *)p_demux->p_sys;
+
+ /* Stop capturing stuff */
+ p_sys->p_control->Stop();
+
+ CommonClose( p_this, p_sys );
+}
+
+/****************************************************************************
+ * ConnectFilters
+ ****************************************************************************/
+static bool ConnectFilters( vlc_object_t *p_this, access_sys_t *p_sys,
+ IBaseFilter *p_filter,
+ CaptureFilter *p_capture_filter )
+{
+ 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, 0, (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 ||
+ mediaType.majortype == MEDIATYPE_Stream ) &&
+ 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) )
+ {
+ // is this pin an ANALOGVIDEOIN input pin?
+ if( pinInfo.dir == PINDIR_INPUT &&
+ 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_this, p_sys, pP, 0 );
+ // 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( vlc_object_t *p_this, access_sys_t *p_sys,
+ string devicename, bool b_audio )
+{
+ /* See if device is already opened */
+ for( int i = 0; i < p_sys->i_streams; i++ )
+ {
+ if( devicename.size() &&
+ p_sys->pp_streams[i]->devicename == devicename )
+ {
+ /* Already opened */
+ return VLC_SUCCESS;
+ }
+ }
+
+ list<string> list_devices;
+
+ /* Enumerate devices and display their names */
+ FindCaptureDevice( p_this, 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_this, "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( p_this, &devicename, 0, b_audio );
+ if( p_device_filter )
+ msg_Dbg( p_this, "using device: %s", devicename.c_str() );
+ else
+ {
+ msg_Err( p_this, "can't use device: %s, unsupported device type",
+ devicename.c_str() );
+ intf_UserFatal( p_this, false, _("Capturing failed"),
+ _("VLC cannot use the device \"%s\", because its "
+ "type is not supported.") );
+ return VLC_EGENERIC;
+ }
+
+ // Retreive acceptable media types supported by device
+ AM_MEDIA_TYPE media_types[MAX_MEDIA_TYPES];
+ size_t media_count =
+ EnumDeviceCaps( p_this, p_device_filter, b_audio ? 0 : p_sys->i_chroma,
+ p_sys->i_width, p_sys->i_height,
+ b_audio ? var_CreateGetInteger( p_this, "dshow-audio-channels" ) : 0,
+ b_audio ? var_CreateGetInteger( p_this, "dshow-audio-samplerate" ) : 0,
+ b_audio ? var_CreateGetInteger( p_this, "dshow-audio-bitspersample" ) : 0,
+ media_types, MAX_MEDIA_TYPES );
+
+ AM_MEDIA_TYPE *mt = NULL;
+
+ if( media_count > 0 )
+ {
+ mt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * media_count);
+
+ // Order and copy returned media types according to arbitrary
+ // fourcc priority
+ for( size_t c = 0; c < media_count; c++ )
+ {
+ int slot_priority =
+ GetFourCCPriority(GetFourCCFromMediaType(media_types[c]));
+ size_t slot_copy = c;
+ for( size_t d = c+1; d < media_count; d++ )
+ {
+ int priority =
+ GetFourCCPriority(GetFourCCFromMediaType(media_types[d]));
+ if( priority > slot_priority )
+ {
+ slot_priority = priority;
+ slot_copy = d;
+ }
+ }
+ if( slot_copy != c )
+ {
+ mt[c] = media_types[slot_copy];
+ media_types[slot_copy] = media_types[c];
+ }
+ else
+ {
+ mt[c] = media_types[c];
+ }
+ }
+ }
+ else {
+ /* capture device */
+ msg_Err( p_this, "capture device '%s' does not support required parameters !", devicename.c_str() );
+ intf_UserFatal( p_this, false, _("Capturing failed"),
+ _("The capture device \"%s\" does not support the "
+ "required parameters."), devicename.c_str() );
+ p_device_filter->Release();
+ return VLC_EGENERIC;
+ }
+
+ /* Create and add our capture filter */
+ CaptureFilter *p_capture_filter =
+ new CaptureFilter( p_this, p_sys, mt, media_count );
+ p_sys->p_graph->AddFilter( p_capture_filter, 0 );
+
+ /* Add the device filter to the graph (seems necessary with VfW before
+ * accessing pin attributes). */
+ p_sys->p_graph->AddFilter( p_device_filter, 0 );
+
+ /* Attempt to connect one of this device's capture output pins */
+ msg_Dbg( p_this, "connecting filters" );
+ if( ConnectFilters( p_this, p_sys, p_device_filter, p_capture_filter ) )
+ {
+ /* Success */
+ msg_Dbg( p_this, "filters connected successfully !" );
+
+ dshow_stream_t dshow_stream;
+ dshow_stream.b_pts = false;
+ dshow_stream.p_es = 0;
+ dshow_stream.mt =
+ p_capture_filter->CustomGetPin()->CustomGetMediaType();
+
+ /* Show Device properties. Done here so the VLC stream is setup with
+ * the proper parameters. */
+ vlc_value_t val;
+ var_Get( p_this, "dshow-config", &val );
+ if( val.b_bool )
+ {
+ ShowDeviceProperties( p_this, p_sys->p_capture_graph_builder2,
+ p_device_filter, b_audio );
+ }
+
+ ConfigTuner( p_this, p_sys->p_capture_graph_builder2,
+ p_device_filter );
+
+ var_Get( p_this, "dshow-tuner", &val );
+ if( val.b_bool && dshow_stream.mt.majortype != MEDIATYPE_Stream )
+ {
+ /* FIXME: we do MEDIATYPE_Stream later so we don't do it twice. */
+ ShowTunerProperties( p_this, p_sys->p_capture_graph_builder2,
+ p_device_filter, b_audio );
+ }
+
+ dshow_stream.mt =
+ p_capture_filter->CustomGetPin()->CustomGetMediaType();
+
+ dshow_stream.i_fourcc = GetFourCCFromMediaType( dshow_stream.mt );
+ if( dshow_stream.i_fourcc )
+ {
+ if( dshow_stream.mt.majortype == MEDIATYPE_Video )
+ {
+ dshow_stream.header.video =
+ *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
+ msg_Dbg( p_this, "MEDIATYPE_Video" );
+ msg_Dbg( p_this, "selected video pin accepts format: %4.4s",
+ (char *)&dshow_stream.i_fourcc);
+ }
+ else if( dshow_stream.mt.majortype == MEDIATYPE_Audio )
+ {
+ dshow_stream.header.audio =
+ *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
+ msg_Dbg( p_this, "MEDIATYPE_Audio" );
+ msg_Dbg( p_this, "selected audio pin accepts format: %4.4s",
+ (char *)&dshow_stream.i_fourcc);
+ }
+ else if( dshow_stream.mt.majortype == MEDIATYPE_Stream )
+ {
+ msg_Dbg( p_this, "MEDIATYPE_Stream" );
+ msg_Dbg( p_this, "selected stream pin accepts format: %4.4s",
+ (char *)&dshow_stream.i_fourcc);
+ }
+ else
+ {
+ msg_Dbg( p_this, "unknown stream majortype" );
+ goto fail;
+ }
+
+ /* Add directshow elementary stream to our list */
+ dshow_stream.p_device_filter = p_device_filter;
+ dshow_stream.p_capture_filter = p_capture_filter;
+
+ p_sys->pp_streams = (dshow_stream_t **)realloc( p_sys->pp_streams,
+ sizeof(dshow_stream_t *) * (p_sys->i_streams + 1) );
+ p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
+ *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
+
+ return VLC_SUCCESS;
+ }
+ }
+
+ fail:
+ /* Remove filters from graph */
+ p_sys->p_graph->RemoveFilter( p_device_filter );
+ p_sys->p_graph->RemoveFilter( p_capture_filter );
+
+ /* Release objects */
+ p_device_filter->Release();
+ p_capture_filter->Release();