dshow.cpp 76.7 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1
/*****************************************************************************
2
 * dshow.cpp : DirectShow access module for vlc
Gildas Bazin's avatar
 
Gildas Bazin committed
3
 *****************************************************************************
4
 * Copyright (C) 2002, 2003 the VideoLAN team
5
 * $Id$
Gildas Bazin's avatar
 
Gildas Bazin committed
6
 *
7
 * Author: Gildas Bazin <gbazin@videolan.org>
8
 *         Damien Fouilleul <damienf@videolan.org>
Gildas Bazin's avatar
 
Gildas Bazin committed
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Gildas Bazin's avatar
 
Gildas Bazin committed
23 24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdio.h>
29

Gildas Bazin's avatar
 
Gildas Bazin committed
30
#include <vlc/vlc.h>
Clément Stenac's avatar
Clément Stenac committed
31 32
#include <vlc_input.h>
#include <vlc_access.h>
33
#include <vlc_demux.h>
Clément Stenac's avatar
Clément Stenac committed
34
#include <vlc_vout.h>
Clément Stenac's avatar
Round 2  
Clément Stenac committed
35
#include <vlc_interface.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
36

Gildas Bazin's avatar
Gildas Bazin committed
37
#include "common.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
38 39
#include "filter.h"

Gildas Bazin's avatar
 
Gildas Bazin committed
40 41 42
/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/
43
static block_t *ReadCompressed( access_t * );
44
static int AccessControl ( access_t *, int, va_list );
Gildas Bazin's avatar
 
Gildas Bazin committed
45

Gildas Bazin's avatar
Gildas Bazin committed
46 47 48 49
static int Demux       ( demux_t * );
static int DemuxControl( demux_t *, int, va_list );

static int OpenDevice( vlc_object_t *, access_sys_t *, string, vlc_bool_t );
Gildas Bazin's avatar
 
Gildas Bazin committed
50 51
static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
                                       list<string> *, vlc_bool_t );
52
static size_t EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
53 54
                              int, int, int, int, int, int,
                              AM_MEDIA_TYPE *mt, size_t );
Gildas Bazin's avatar
Gildas Bazin committed
55 56
static bool ConnectFilters( vlc_object_t *, access_sys_t *,
                            IBaseFilter *, CaptureFilter * );
Gildas Bazin's avatar
 
Gildas Bazin committed
57 58
static int FindDevicesCallback( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );
59 60
static int ConfigDevicesCallback( vlc_object_t *, char const *,
                                  vlc_value_t, vlc_value_t, void * );
Gildas Bazin's avatar
 
Gildas Bazin committed
61

62 63
static void ShowPropertyPage( IUnknown * );
static void ShowDeviceProperties( vlc_object_t *, ICaptureGraphBuilder2 *, 
64
                                  IBaseFilter *, vlc_bool_t );
65 66
static void ShowTunerProperties( vlc_object_t *, ICaptureGraphBuilder2 *, 
                                 IBaseFilter *, vlc_bool_t );
67 68
static void ConfigTuner( vlc_object_t *, ICaptureGraphBuilder2 *,
                         IBaseFilter * );
Gildas Bazin's avatar
 
Gildas Bazin committed
69

Gildas Bazin's avatar
 
Gildas Bazin committed
70
/*****************************************************************************
71
 * Module descriptor
Gildas Bazin's avatar
 
Gildas Bazin committed
72
 *****************************************************************************/
73 74 75 76
static const char *ppsz_vdev[] = { "", "none" };
static const char *ppsz_vdev_text[] = { N_("Default"), N_("None") };
static const char *ppsz_adev[] = { "", "none" };
static const char *ppsz_adev_text[] = { N_("Default"), N_("None") };
77
static int  pi_tuner_input[] = { 0, 1, 2 };
78
static const char *ppsz_tuner_input_text[] =
79
    {N_("Default"), N_("Cable"), N_("Antenna")};
80
static const int pi_amtuner_mode[]  = { AMTUNER_MODE_DEFAULT,
81 82 83 84
                                 AMTUNER_MODE_TV,
                                 AMTUNER_MODE_FM_RADIO,
                                 AMTUNER_MODE_AM_RADIO,
                                 AMTUNER_MODE_DSS };
85
static const char *ppsz_amtuner_mode_text[] = { N_("Default"),
86 87 88 89
                                          N_("TV"),
                                          N_("FM radio"),
                                          N_("AM radio"),
                                          N_("DSS") };
90

Gildas Bazin's avatar
 
Gildas Bazin committed
91 92
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
93
    "Caching value for DirectShow streams. " \
Clément Stenac's avatar
Clément Stenac committed
94
    "This value should be set in millisecondss." )
95 96
#define VDEV_TEXT N_("Video device name")
#define VDEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
97
    "Name of the video device that will be used by the " \
98 99 100 101
    "DirectShow plugin. If you don't specify anything, the default device " \
    "will be used.")
#define ADEV_TEXT N_("Audio device name")
#define ADEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
102
    "Name of the audio device that will be used by the " \
103
    "DirectShow plugin. If you don't specify anything, the default device " \
Christophe Mutricy's avatar
Christophe Mutricy committed
104
    "will be used. ")
105 106
#define SIZE_TEXT N_("Video size")
#define SIZE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
107
    "Size of the video that will be displayed by the " \
108
    "DirectShow plugin. If you don't specify anything the default size for " \
Christophe Mutricy's avatar
Christophe Mutricy committed
109
    "your device will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>.")
110 111 112
#define CHROMA_TEXT N_("Video input chroma format")
#define CHROMA_LONGTEXT N_( \
    "Force the DirectShow video input to use a specific chroma format " \
113
    "(eg. I420 (default), RV24, etc.)")
114 115 116
#define FPS_TEXT N_("Video input frame rate")
#define FPS_LONGTEXT N_( \
    "Force the DirectShow video input to use a specific frame rate" \
Christophe Mutricy's avatar
Christophe Mutricy committed
117
    "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
118
#define CONFIG_TEXT N_("Device properties")
Gildas Bazin's avatar
 
Gildas Bazin committed
119
#define CONFIG_LONGTEXT N_( \
120 121
    "Show the properties dialog of the selected device before starting the " \
    "stream.")
122 123 124
#define TUNER_TEXT N_("Tuner properties")
#define TUNER_LONGTEXT N_( \
    "Show the tuner properties [channel selection] page." )
125 126
#define CHANNEL_TEXT N_("Tuner TV Channel")
#define CHANNEL_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
127
    "Set the TV channel the tuner will set to " \
128 129 130
    "(0 means default)." )
#define COUNTRY_TEXT N_("Tuner country code")
#define COUNTRY_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
131
    "Set the tuner country code that establishes the current " \
132 133 134
    "channel-to-frequency mapping (0 means default)." )
#define TUNER_INPUT_TEXT N_("Tuner input type")
#define TUNER_INPUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
135
    "Select the tuner input type (Cable/Antenna)." )
136 137
#define VIDEO_IN_TEXT N_("Video input pin")
#define VIDEO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
138
  "Select the video input source, such as composite, s-video, " \
139
  "or tuner. Since these settings are hardware-specific, you should find good " \
Clément Stenac's avatar
Clément Stenac committed
140 141
  "settings in the \"Device config\" area, and use those numbers here. -1 " \
  "means that settings will not be changed.")
142 143
#define AUDIO_IN_TEXT N_("Audio input pin")
#define AUDIO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
144
  "Select the audio input source. See the \"video input\" option." )
145 146
#define VIDEO_OUT_TEXT N_("Video output pin")
#define VIDEO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
147
  "Select the video output type. See the \"video input\" option." )
148 149
#define AUDIO_OUT_TEXT N_("Audio output pin")
#define AUDIO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
150
  "Select the audio output type. See the \"video input\" option." )
Gildas Bazin's avatar
 
Gildas Bazin committed
151

152
#define AMTUNER_MODE_TEXT N_("AM Tuner mode")
153
#define AMTUNER_MODE_LONGTEXT N_( \
154 155
    "AM Tuner mode. Can be one of DEFAULT, TV, AM_RADIO, FM_RADIO or DSS.")

Gildas Bazin's avatar
Gildas Bazin committed
156 157 158
static int  CommonOpen ( vlc_object_t *, access_sys_t *, vlc_bool_t );
static void CommonClose( vlc_object_t *, access_sys_t * );

159 160 161 162 163 164
static int  AccessOpen ( vlc_object_t * );
static void AccessClose( vlc_object_t * );

static int  DemuxOpen  ( vlc_object_t * );
static void DemuxClose ( vlc_object_t * );

Gildas Bazin's avatar
 
Gildas Bazin committed
165
vlc_module_begin();
166
    set_shortname( _("DirectShow") );
Gildas Bazin's avatar
 
Gildas Bazin committed
167
    set_description( _("DirectShow input") );
Clément Stenac's avatar
Clément Stenac committed
168 169
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACCESS );
170
    add_integer( "dshow-caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
Gildas Bazin's avatar
 
Gildas Bazin committed
171
                 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
172

173
    add_string( "dshow-vdev", NULL, NULL, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE);
174
        change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback );
175 176
        change_action_add( FindDevicesCallback, N_("Refresh list") );
        change_action_add( ConfigDevicesCallback, N_("Configure") );
177

178
    add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE);
179
        change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback );
180 181
        change_action_add( FindDevicesCallback, N_("Refresh list") );
        change_action_add( ConfigDevicesCallback, N_("Configure") );
182

183
    add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE);
184

185 186
    add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
                VLC_TRUE );
Gildas Bazin's avatar
 
Gildas Bazin committed
187

188 189 190
    add_float( "dshow-fps", 0.0f, NULL, FPS_TEXT, FPS_LONGTEXT,
                VLC_TRUE );

Gildas Bazin's avatar
 
Gildas Bazin committed
191
    add_bool( "dshow-config", VLC_FALSE, NULL, CONFIG_TEXT, CONFIG_LONGTEXT,
192
              VLC_TRUE );
Gildas Bazin's avatar
 
Gildas Bazin committed
193

194
    add_bool( "dshow-tuner", VLC_FALSE, NULL, TUNER_TEXT, TUNER_LONGTEXT,
195
              VLC_TRUE );
196

197 198 199 200 201 202 203 204 205 206
    add_integer( "dshow-tuner-channel", 0, NULL, CHANNEL_TEXT,
                 CHANNEL_LONGTEXT, VLC_TRUE );

    add_integer( "dshow-tuner-country", 0, NULL, COUNTRY_TEXT,
                 COUNTRY_LONGTEXT, VLC_TRUE );

    add_integer( "dshow-tuner-input", 0, NULL, TUNER_INPUT_TEXT,
                 TUNER_INPUT_LONGTEXT, VLC_TRUE );
        change_integer_list( pi_tuner_input, ppsz_tuner_input_text, 0 );

207
    add_integer( "dshow-video-input",  -1, NULL, VIDEO_IN_TEXT,
208
                 VIDEO_IN_LONGTEXT, VLC_TRUE );
209 210

    add_integer( "dshow-audio-input",  -1, NULL, AUDIO_IN_TEXT,
211
                 AUDIO_IN_LONGTEXT, VLC_TRUE );
212 213

    add_integer( "dshow-video-output", -1, NULL, VIDEO_OUT_TEXT,
214
                 VIDEO_OUT_LONGTEXT, VLC_TRUE );
215 216

    add_integer( "dshow-audio-output", -1, NULL, AUDIO_OUT_TEXT,
217
                 AUDIO_OUT_LONGTEXT, VLC_TRUE );
218

219
    add_integer( "dshow-amtuner-mode", AMTUNER_MODE_TV, NULL,
220 221 222
                AMTUNER_MODE_TEXT, AMTUNER_MODE_LONGTEXT, VLC_FALSE);
        change_integer_list( pi_amtuner_mode, ppsz_amtuner_mode_text, 0 );

Gildas Bazin's avatar
 
Gildas Bazin committed
223
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
224 225
    set_capability( "access_demux", 0 );
    set_callbacks( DemuxOpen, DemuxClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
226 227

    add_submodule();
Gildas Bazin's avatar
Gildas Bazin committed
228 229 230
    set_description( _("DirectShow input") );
    set_capability( "access2", 0 );
    set_callbacks( AccessOpen, AccessClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
231 232 233

vlc_module_end();

Gildas Bazin's avatar
Gildas Bazin committed
234
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
235
 * DirectShow elementary stream descriptor
Gildas Bazin's avatar
Gildas Bazin committed
236
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250
typedef struct dshow_stream_t
{
    string          devicename;
    IBaseFilter     *p_device_filter;
    CaptureFilter   *p_capture_filter;
    AM_MEDIA_TYPE   mt;

    union
    {
      VIDEOINFOHEADER video;
      WAVEFORMATEX    audio;

    } header;

Gildas Bazin's avatar
Gildas Bazin committed
251 252 253
    int             i_fourcc;
    es_out_id_t     *p_es;

254
    vlc_bool_t      b_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
255 256
} dshow_stream_t;

Gildas Bazin's avatar
Gildas Bazin committed
257
/*****************************************************************************
258
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
259
 *****************************************************************************/
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
static void CreateDirectShowGraph( access_sys_t *p_sys )
{
    p_sys->i_crossbar_route_depth = 0;

    /* Create directshow filter graph */
    if( SUCCEEDED( CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
                       (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph) ) )
    {
        /* Create directshow capture graph builder if available */
        if( SUCCEEDED( CoCreateInstance( CLSID_CaptureGraphBuilder2, 0,
                         CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder2,
                         (void **)&p_sys->p_capture_graph_builder2 ) ) )
        {
            p_sys->p_capture_graph_builder2->
                SetFiltergraph((IGraphBuilder *)p_sys->p_graph);
        }

        p_sys->p_graph->QueryInterface( IID_IMediaControl,
                                        (void **)&p_sys->p_control );
    }
}

static void DeleteDirectShowGraph( access_sys_t *p_sys )
{
    DeleteCrossbarRoutes( p_sys );

    /* Remove filters from graph */
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
        p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );
        p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );
        p_sys->pp_streams[i]->p_capture_filter->Release();
        p_sys->pp_streams[i]->p_device_filter->Release();
    }

    /* Release directshow objects */
    if( p_sys->p_control )
    {
        p_sys->p_control->Release();
        p_sys->p_control = NULL;
    }
    if( p_sys->p_capture_graph_builder2 )
    {
        p_sys->p_capture_graph_builder2->Release();
        p_sys->p_capture_graph_builder2 = NULL;
    }

    if( p_sys->p_graph )
    {
        p_sys->p_graph->Release();
        p_sys->p_graph = NULL;
    }
}

Gildas Bazin's avatar
 
Gildas Bazin committed
314
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
315
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
316
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
317 318
static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
                       vlc_bool_t b_access_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
319
{
320
    vlc_value_t  val;
Gildas Bazin's avatar
Gildas Bazin committed
321
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
322

323
    /* Get/parse options and open device(s) */
Gildas Bazin's avatar
 
Gildas Bazin committed
324
    string vdevname, adevname;
325
    int i_width = 0, i_height = 0, i_chroma = 0;
Gildas Bazin's avatar
Gildas Bazin committed
326
    vlc_bool_t b_audio = VLC_TRUE;
Gildas Bazin's avatar
 
Gildas Bazin committed
327

328 329
    var_Create( p_this, "dshow-config", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-tuner", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
Gildas Bazin committed
330 331
    var_Create( p_this, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-vdev", &val );
332 333
    if( val.psz_string ) vdevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
334

Gildas Bazin's avatar
Gildas Bazin committed
335 336
    var_Create( p_this, "dshow-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-adev", &val );
337 338 339
    if( val.psz_string ) adevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );

Gildas Bazin's avatar
Gildas Bazin committed
340 341
    static struct {char *psz_size; int  i_width; int  i_height;} size_table[] =
    { { "subqcif", 128, 96 }, { "qsif", 160, 120 }, { "qcif", 176, 144 },
342
      { "sif", 320, 240 }, { "cif", 352, 288 }, { "d1", 640, 480 },
Gildas Bazin's avatar
Gildas Bazin committed
343 344 345 346 347
      { 0, 0, 0 },
    };

    var_Create( p_this, "dshow-size", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-size", &val );
348
    if( val.psz_string && *val.psz_string )
Gildas Bazin's avatar
 
Gildas Bazin committed
349
    {
Gildas Bazin's avatar
Gildas Bazin committed
350
        for( i = 0; size_table[i].psz_size; i++ )
351
        {
Gildas Bazin's avatar
Gildas Bazin committed
352 353 354 355 356 357
            if( !strcmp( val.psz_string, size_table[i].psz_size ) )
            {
                i_width = size_table[i].i_width;
                i_height = size_table[i].i_height;
                break;
            }
358
        }
Gildas Bazin's avatar
Gildas Bazin committed
359
        if( !size_table[i].psz_size ) /* Try to parse "WidthxHeight" */
360 361 362 363
        {
            char *psz_parser;
            i_width = strtol( val.psz_string, &psz_parser, 0 );
            if( *psz_parser == 'x' || *psz_parser == 'X')
Gildas Bazin's avatar
 
Gildas Bazin committed
364
            {
365
                i_height = strtol( psz_parser + 1, &psz_parser, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
366
            }
Clément Stenac's avatar
Clément Stenac committed
367
            msg_Dbg( p_this, "width x height %dx%d", i_width, i_height );
Gildas Bazin's avatar
 
Gildas Bazin committed
368 369
        }
    }
370
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
371

372
    p_sys->b_chroma = VLC_FALSE;
Gildas Bazin's avatar
Gildas Bazin committed
373 374
    var_Create( p_this, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-chroma", &val );
375 376 377 378
    if( val.psz_string && strlen( val.psz_string ) >= 4 )
    {
        i_chroma = VLC_FOURCC( val.psz_string[0], val.psz_string[1],
                               val.psz_string[2], val.psz_string[3] );
379
        p_sys->b_chroma = VLC_TRUE;
380 381
    }
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
382

383
    var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
384 385 386 387 388 389 390
    var_Create( p_this, "dshow-tuner-channel",
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-tuner-country",
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-tuner-input",
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

391 392 393
    var_Create( p_this, "dshow-amtuner-mode",
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

Gildas Bazin's avatar
Gildas Bazin committed
394
    var_Create( p_this, "dshow-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
395

396 397 398 399 400
    var_Create( p_this, "dshow-video-input", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-audio-input", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-video-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-audio-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

Gildas Bazin's avatar
 
Gildas Bazin committed
401
    /* Initialize OLE/COM */
402
    CoInitialize( 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
403

Gildas Bazin's avatar
 
Gildas Bazin committed
404 405
    /* Initialize some data */
    p_sys->i_streams = 0;
406
    p_sys->pp_streams = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
407 408 409
    p_sys->i_width = i_width;
    p_sys->i_height = i_height;
    p_sys->i_chroma = i_chroma;
Gildas Bazin's avatar
 
Gildas Bazin committed
410

411 412 413
    p_sys->p_graph = NULL;
    p_sys->p_capture_graph_builder2 = NULL;
    p_sys->p_control = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
414

415 416 417
    vlc_mutex_init( p_this, &p_sys->lock );
    vlc_cond_init( p_this, &p_sys->wait );

418 419
    /* Build directshow graph */
    CreateDirectShowGraph( p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
420

Gildas Bazin's avatar
Gildas Bazin committed
421
    if( OpenDevice( p_this, p_sys, vdevname, 0 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
422
    {
Gildas Bazin's avatar
Gildas Bazin committed
423
        msg_Err( p_this, "can't open video");
Gildas Bazin's avatar
 
Gildas Bazin committed
424
    }
Gildas Bazin's avatar
Gildas Bazin committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
    else
    {
        /* Check if we can handle the demuxing ourselves or need to spawn
         * a demuxer module */
        dshow_stream_t *p_stream = p_sys->pp_streams[p_sys->i_streams-1];

        if( p_stream->mt.majortype == MEDIATYPE_Video )
        {
            if( /* Raw DV stream */
                p_stream->i_fourcc == VLC_FOURCC('d','v','s','l') ||
                p_stream->i_fourcc == VLC_FOURCC('d','v','s','d') ||
                p_stream->i_fourcc == VLC_FOURCC('d','v','h','d') ||
                /* Raw MPEG video stream */
                p_stream->i_fourcc == VLC_FOURCC('m','p','2','v') )
            {
                b_audio = VLC_FALSE;
441 442 443 444

                if( b_access_demux )
                {
                    /* Let the access (only) take care of that */
445
                    return VLC_EGENERIC;
446
                }
Gildas Bazin's avatar
Gildas Bazin committed
447 448
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
449

450 451 452 453 454 455 456 457 458
        if( p_stream->mt.majortype == MEDIATYPE_Stream )
        {
            b_audio = VLC_FALSE;

            if( b_access_demux )
            {
                /* Let the access (only) take care of that */
                return VLC_EGENERIC;
            }
459 460 461 462 463 464 465 466 467

            var_Get( p_this, "dshow-tuner", &val );
            if( val.b_bool )
            {
                /* FIXME: we do MEDIATYPE_Stream here so we don't do
                 * it twice. */
                ShowTunerProperties( p_this, p_sys->p_capture_graph_builder2,
                                     p_stream->p_device_filter, 0 );
            }
468
        }
Gildas Bazin's avatar
Gildas Bazin committed
469 470 471
    }

    if( b_audio && OpenDevice( p_this, p_sys, adevname, 1 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
472
    {
Gildas Bazin's avatar
Gildas Bazin committed
473
        msg_Err( p_this, "can't open audio");
Gildas Bazin's avatar
 
Gildas Bazin committed
474
    }
Gildas Bazin's avatar
Gildas Bazin committed
475

476
    for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
Gildas Bazin's avatar
 
Gildas Bazin committed
477
    {
478
            var_Get( p_this, "dshow-video-input", &val );
479
            if( val.i_int >= 0 )
480 481
                    p_sys->crossbar_routes[i].VideoInputIndex=val.i_int;
            var_Get( p_this, "dshow-video-output", &val );
482
            if( val.i_int >= 0 )
483 484
                    p_sys->crossbar_routes[i].VideoOutputIndex=val.i_int;
            var_Get( p_this, "dshow-audio-input", &val );
485
            if( val.i_int >= 0 )
486 487
                    p_sys->crossbar_routes[i].AudioInputIndex=val.i_int;
            var_Get( p_this, "dshow-audio-output", &val );
488
            if( val.i_int >= 0 )
489 490
                    p_sys->crossbar_routes[i].AudioOutputIndex=val.i_int;

491 492 493 494 495
        IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
        LONG VideoInputIndex = p_sys->crossbar_routes[i].VideoInputIndex;
        LONG VideoOutputIndex = p_sys->crossbar_routes[i].VideoOutputIndex;
        LONG AudioInputIndex = p_sys->crossbar_routes[i].AudioInputIndex;
        LONG AudioOutputIndex = p_sys->crossbar_routes[i].AudioOutputIndex;
Gildas Bazin's avatar
 
Gildas Bazin committed
496

497 498
        if( SUCCEEDED(pXbar->Route(VideoOutputIndex, VideoInputIndex)) )
        {
Clément Stenac's avatar
Clément Stenac committed
499 500
            msg_Dbg( p_this, "crossbar at depth %d, routed video "
                     "output %ld to video input %ld", i, VideoOutputIndex,
501
                     VideoInputIndex );
Gildas Bazin's avatar
 
Gildas Bazin committed
502

503 504 505 506 507
            if( AudioOutputIndex != -1 && AudioInputIndex != -1 )
            {
                if( SUCCEEDED( pXbar->Route(AudioOutputIndex,
                                            AudioInputIndex)) )
                {
Clément Stenac's avatar
Clément Stenac committed
508 509
                    msg_Dbg(p_this, "crossbar at depth %d, routed audio "
                            "output %ld to audio input %ld", i,
510 511 512 513 514 515
                            AudioOutputIndex, AudioInputIndex );
                }
            }
        }
    }

516 517 518 519
    /*
    ** Show properties pages from other filters in graph
    */
    var_Get( p_this, "dshow-config", &val );
520
    if( val.b_bool )
521 522 523 524 525
    {
        for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
        {
            IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
            IBaseFilter *p_XF;
526 527 528

            if( SUCCEEDED( pXbar->QueryInterface( IID_IBaseFilter,
                                                  (void **)&p_XF ) ) )
529 530 531 532
            {
                ShowPropertyPage( p_XF );
                p_XF->Release();
            }
533
        }
534 535
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
536 537
    /* Initialize some data */
    p_sys->i_current_stream = 0;
538

Gildas Bazin's avatar
Gildas Bazin committed
539
    if( !p_sys->i_streams ) return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
540

Gildas Bazin's avatar
 
Gildas Bazin committed
541 542 543 544
    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
545
 * DemuxOpen: open direct show device as an access_demux module
Gildas Bazin's avatar
 
Gildas Bazin committed
546
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
547
static int DemuxOpen( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
548
{
Gildas Bazin's avatar
Gildas Bazin committed
549 550 551
    demux_t      *p_demux = (demux_t *)p_this;
    access_sys_t *p_sys;
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
552

Gildas Bazin's avatar
Gildas Bazin committed
553 554 555
    p_sys = (access_sys_t *)malloc( sizeof( access_sys_t ) );
    memset( p_sys, 0, sizeof( access_sys_t ) );
    p_demux->p_sys = (demux_sys_t *)p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
556

Gildas Bazin's avatar
Gildas Bazin committed
557 558 559 560 561
    if( CommonOpen( p_this, p_sys, VLC_TRUE ) != VLC_SUCCESS )
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
562

Gildas Bazin's avatar
Gildas Bazin committed
563 564 565
    /* Everything is ready. Let's rock baby */
    msg_Dbg( p_this, "Playing...");
    p_sys->p_control->Run();
566

Gildas Bazin's avatar
Gildas Bazin committed
567 568 569 570 571 572 573
    p_demux->pf_demux   = Demux;
    p_demux->pf_control = DemuxControl;
    p_demux->info.i_update = 0;
    p_demux->info.i_title = 0;
    p_demux->info.i_seekpoint = 0;

    for( i = 0; i < p_sys->i_streams; i++ )
574
    {
Gildas Bazin's avatar
Gildas Bazin committed
575 576
        dshow_stream_t *p_stream = p_sys->pp_streams[i];
        es_format_t fmt;
577

Gildas Bazin's avatar
Gildas Bazin committed
578 579 580
        if( p_stream->mt.majortype == MEDIATYPE_Video )
        {
            es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
581

Gildas Bazin's avatar
Gildas Bazin committed
582 583 584
            fmt.video.i_width  = p_stream->header.video.bmiHeader.biWidth;
            fmt.video.i_height = p_stream->header.video.bmiHeader.biHeight;
            fmt.video.i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
585

Gildas Bazin's avatar
Gildas Bazin committed
586 587 588 589 590
            if( !p_stream->header.video.bmiHeader.biCompression )
            {
                /* RGB DIB are coded from bottom to top */
                fmt.video.i_height = (unsigned int)(-(int)fmt.video.i_height);
            }
591

Gildas Bazin's avatar
Gildas Bazin committed
592 593 594 595
            /* Setup rgb mask for RGB formats */
            if( p_stream->i_fourcc == VLC_FOURCC('R','V','2','4') )
            {
                /* This is in BGR format */
596 597 598
                fmt.video.i_bmask = 0x00ff0000;
                fmt.video.i_gmask = 0x0000ff00;
                fmt.video.i_rmask = 0x000000ff;
Gildas Bazin's avatar
Gildas Bazin committed
599
            }
600 601 602 603 604 605 606

            if( p_stream->header.video.AvgTimePerFrame )
            {
                fmt.video.i_frame_rate = 10000000;
                fmt.video.i_frame_rate_base =
                    p_stream->header.video.AvgTimePerFrame;
            }
Gildas Bazin's avatar
Gildas Bazin committed
607 608 609 610
        }
        else if( p_stream->mt.majortype == MEDIATYPE_Audio )
        {
            es_format_Init( &fmt, AUDIO_ES, p_stream->i_fourcc );
611

Gildas Bazin's avatar
Gildas Bazin committed
612 613 614 615 616 617 618 619 620 621
            fmt.audio.i_channels = p_stream->header.audio.nChannels;
            fmt.audio.i_rate = p_stream->header.audio.nSamplesPerSec;
            fmt.audio.i_bitspersample = p_stream->header.audio.wBitsPerSample;
            fmt.audio.i_blockalign = fmt.audio.i_channels *
                fmt.audio.i_bitspersample / 8;
            fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate *
                fmt.audio.i_bitspersample;
        }

        p_stream->p_es = es_out_Add( p_demux->out, &fmt );
622
    }
Gildas Bazin's avatar
Gildas Bazin committed
623

624
    return VLC_SUCCESS;
625 626
}

Gildas Bazin's avatar
Gildas Bazin committed
627 628 629 630
/*****************************************************************************
 * AccessOpen: open direct show device as an access module
 *****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
631
{
Gildas Bazin's avatar
Gildas Bazin committed
632 633
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;
634

Gildas Bazin's avatar
Gildas Bazin committed
635 636
    p_access->p_sys = p_sys = (access_sys_t *)malloc( sizeof( access_sys_t ) );
    memset( p_sys, 0, sizeof( access_sys_t ) );
637

638
    if( CommonOpen( p_this, p_sys, VLC_FALSE ) != VLC_SUCCESS )
Gildas Bazin's avatar
Gildas Bazin committed
639 640 641 642
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
643

Gildas Bazin's avatar
Gildas Bazin committed
644
    dshow_stream_t *p_stream = p_sys->pp_streams[0];
645

Gildas Bazin's avatar
Gildas Bazin committed
646 647
    /* Check if we need to force demuxers */
    if( !p_access->psz_demux || !*p_access->psz_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
648
    {
Gildas Bazin's avatar
Gildas Bazin committed
649 650 651
        if( p_stream->i_fourcc == VLC_FOURCC('d','v','s','l') ||
            p_stream->i_fourcc == VLC_FOURCC('d','v','s','d') ||
            p_stream->i_fourcc == VLC_FOURCC('d','v','h','d') )
652
        {
Gildas Bazin's avatar
Gildas Bazin committed
653 654 655 656 657
            p_access->psz_demux = strdup( "rawdv" );
        }
        else if( p_stream->i_fourcc == VLC_FOURCC('m','p','2','v') )
        {
            p_access->psz_demux = "mpgv";
658
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
659
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
660

Gildas Bazin's avatar
Gildas Bazin committed
661
    /* Setup Access */
662 663
    p_access->pf_read = NULL;
    p_access->pf_block = ReadCompressed;
Gildas Bazin's avatar
Gildas Bazin committed
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    p_access->pf_control = AccessControl;
    p_access->pf_seek = NULL;
    p_access->info.i_update = 0;
    p_access->info.i_size = 0;
    p_access->info.i_pos = 0;
    p_access->info.b_eof = VLC_FALSE;
    p_access->info.i_title = 0;
    p_access->info.i_seekpoint = 0;
    p_access->p_sys = p_sys;

    /* Everything is ready. Let's rock baby */
    msg_Dbg( p_this, "Playing...");
    p_sys->p_control->Run();

    return VLC_SUCCESS;
679
}
Gildas Bazin's avatar
 
Gildas Bazin committed
680

Gildas Bazin's avatar
Gildas Bazin committed
681 682 683 684
/*****************************************************************************
 * CommonClose: close device
 *****************************************************************************/
static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
685
{
Clément Stenac's avatar
Clément Stenac committed
686
    msg_Dbg( p_this, "releasing DirectShow");
687

Gildas Bazin's avatar
Gildas Bazin committed
688
    DeleteDirectShowGraph( p_sys );
689

Gildas Bazin's avatar
Gildas Bazin committed
690 691
    /* Uninitialize OLE/COM */
    CoUninitialize();
692

693 694
    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 );
Gildas Bazin's avatar
Gildas Bazin committed
695 696 697

    vlc_mutex_destroy( &p_sys->lock );
    vlc_cond_destroy( &p_sys->wait );
698

Gildas Bazin's avatar
Gildas Bazin committed
699
    free( p_sys );
700 701
}

Gildas Bazin's avatar
Gildas Bazin committed
702 703 704 705
/*****************************************************************************
 * AccessClose: close device
 *****************************************************************************/
static void AccessClose( vlc_object_t *p_this )
706
{
Gildas Bazin's avatar
Gildas Bazin committed
707 708
    access_t     *p_access = (access_t *)p_this;
    access_sys_t *p_sys    = p_access->p_sys;
709

Gildas Bazin's avatar
Gildas Bazin committed
710 711
    /* Stop capturing stuff */
    p_sys->p_control->Stop();
712

Gildas Bazin's avatar
Gildas Bazin committed
713 714
    CommonClose( p_this, p_sys );
}
715

Gildas Bazin's avatar
Gildas Bazin committed
716 717 718 719 720 721 722
/*****************************************************************************
 * 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;
723

Gildas Bazin's avatar
Gildas Bazin committed
724 725
    /* Stop capturing stuff */
    p_sys->p_control->Stop();
726

Gildas Bazin's avatar
Gildas Bazin committed
727
    CommonClose( p_this, p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
728 729 730 731 732
}

/****************************************************************************
 * ConnectFilters
 ****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
733 734
static bool ConnectFilters( vlc_object_t *p_this, access_sys_t *p_sys,
                            IBaseFilter *p_filter,
735
                            CaptureFilter *p_capture_filter )
Gildas Bazin's avatar
 
Gildas Bazin committed
736
{
737
    CapturePin *p_input_pin = p_capture_filter->CustomGetPin();
Gildas Bazin's avatar
 
Gildas Bazin committed
738

739
    AM_MEDIA_TYPE mediaType = p_input_pin->CustomGetMediaType();
Gildas Bazin's avatar
 
Gildas Bazin committed
740

741
    if( p_sys->p_capture_graph_builder2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
742
    {
743
        if( FAILED(p_sys->p_capture_graph_builder2->
Gildas Bazin's avatar
Gildas Bazin committed
744 745
                RenderStream( &PIN_CATEGORY_CAPTURE, &mediaType.majortype,
                              p_filter, 0, (IBaseFilter *)p_capture_filter )) )
746 747 748
        {
            return false;
        }
749

750 751 752
        // Sort out all the possible video inputs
        // The class needs to be given the capture filters ANALOGVIDEO input pin
        IEnumPins *pins = 0;
753 754
        if( ( mediaType.majortype == MEDIATYPE_Video ||
              mediaType.majortype == MEDIATYPE_Stream ) &&
755
            SUCCEEDED(p_filter->EnumPins(&pins)) )
Gildas Bazin's avatar
 
Gildas Bazin committed
756
        {
757 758 759 760 761 762 763 764
            IPin        *pP = 0;
            ULONG        n;
            PIN_INFO     pinInfo;
            BOOL         Found = FALSE;
            IKsPropertySet *pKs=0;
            GUID guid;
            DWORD dw;

Gildas Bazin's avatar
Gildas Bazin committed
765
            while( !Found && ( S_OK == pins->Next(1, &pP, &n) ) )
766
            {
Gildas Bazin's avatar
Gildas Bazin committed
767
                if( S_OK == pP->QueryPinInfo(&pinInfo) )
768
                {
Gildas Bazin's avatar
Gildas Bazin committed
769 770 771 772
                    // is this pin an ANALOGVIDEOIN input pin?
                    if( pinInfo.dir == PINDIR_INPUT &&
                        pP->QueryInterface( IID_IKsPropertySet,
                                            (void **)&pKs ) == S_OK )
773
                    {
Gildas Bazin's avatar
Gildas Bazin committed
774 775 776
                        if( pKs->Get( AMPROPSETID_Pin,
                                      AMPROPERTY_PIN_CATEGORY, NULL, 0,
                                      &guid, sizeof(GUID), &dw ) == S_OK )
777
                        {
Gildas Bazin's avatar
Gildas Bazin committed
778
                            if( guid == PIN_CATEGORY_ANALOGVIDEOIN )
779
                            {
Gildas Bazin's avatar
Gildas Bazin committed
780
                                // recursively search crossbar routes
781
                                FindCrossbarRoutes( p_this, p_sys, pP, 0 );
Gildas Bazin's avatar
Gildas Bazin committed
782 783
                                // found it
                                Found = TRUE;
784 785
                            }
                        }
Gildas Bazin's avatar
Gildas Bazin committed
786
                        pKs->Release();
787 788 789 790 791 792
                    }
                    pinInfo.pFilter->Release();
                }
                pP->Release();
            }
            pins->Release();
Gildas Bazin's avatar
 
Gildas Bazin committed
793
        }
794
        return true;
Gildas Bazin's avatar
 
Gildas Bazin committed
795
    }
796 797 798 799
    else
    {
        IEnumPins *p_enumpins;
        IPin *p_pin;
Gildas Bazin's avatar
 
Gildas Bazin committed
800

801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
        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;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
822 823
}

824
/*
Gildas Bazin's avatar
Gildas Bazin committed
825 826 827
 * get fourcc priority from arbritary preference, the higher the better
 */
static int GetFourCCPriority( int i_fourcc )
828 829 830
{
    switch( i_fourcc )
    {
Gildas Bazin's avatar
Gildas Bazin committed
831 832 833 834 835 836 837 838 839 840 841 842
    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;
843
    }
Gildas Bazin's avatar
Gildas Bazin committed
844

845 846 847 848 849
    return 0;
}

#define MAX_MEDIA_TYPES 32

Gildas Bazin's avatar
Gildas Bazin committed
850 851
static int OpenDevice( vlc_object_t *p_this, access_sys_t *p_sys,
                       string devicename, vlc_bool_t b_audio )
Gildas Bazin's avatar
 
Gildas Bazin committed
852
{
853 854 855
    /* See if device is already opened */
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
Gildas Bazin's avatar
Gildas Bazin committed
856 857
        if( devicename.size() &&
            p_sys->pp_streams[i]->devicename == devicename )
858 859 860 861 862 863
        {
            /* Already opened */
            return VLC_SUCCESS;
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
864 865
    list<string> list_devices;

866
    /* Enumerate devices and display their names */
Gildas Bazin's avatar
Gildas Bazin committed
867
    FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
Gildas Bazin's avatar
 
Gildas Bazin committed
868

869 870 871
    if( !list_devices.size() )
        return VLC_EGENERIC;

Gildas Bazin's avatar
 
Gildas Bazin committed
872 873
    list<string>::iterator iter;
    for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
Gildas Bazin's avatar
Gildas Bazin committed
874
        msg_Dbg( p_this, "found device: %s", iter->c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
875 876 877 878 879 880 881 882

    /* 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
Gildas Bazin's avatar
 
Gildas Bazin committed
883 884
    // a capture/preview device, such as a desktop USB video camera.
    IBaseFilter *p_device_filter =
Gildas Bazin's avatar
Gildas Bazin committed
885
        FindCaptureDevice( p_this, &devicename, 0, b_audio );
Gildas Bazin's avatar
 
Gildas Bazin committed
886
    if( p_device_filter )
Gildas Bazin's avatar
Gildas Bazin committed
887
        msg_Dbg( p_this, "using device: %s", devicename.c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
888 889
    else
    {
Gildas Bazin's avatar
Gildas Bazin committed
890
        msg_Err( p_this, "can't use device: %s, unsupported device type",
891
                 devicename.c_str() );
Felix Paul Kühne's avatar
Felix Paul Kühne committed
892
        intf_UserFatal( p_this, VLC_FALSE, _("Capturing failed"), 
893 894
                        _("VLC cannot use the device \"%s\", because its device "
                          "type is not supported.") );
Gildas Bazin's avatar
 
Gildas Bazin committed
895 896
        return VLC_EGENERIC;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed