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 29 30 31 32
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <vlc/vlc.h>
Clément Stenac's avatar
Clément Stenac committed
33
#include <vlc_vout.h>
Clément Stenac's avatar
Round 2  
Clément Stenac committed
34
#include <vlc_interface.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
35

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

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

Gildas Bazin's avatar
Gildas Bazin committed
45 46 47 48
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
49 50
static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
                                       list<string> *, vlc_bool_t );
51
static size_t EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
52 53
                              int, int, int, int, int, int,
                              AM_MEDIA_TYPE *mt, size_t );
Gildas Bazin's avatar
Gildas Bazin committed
54 55
static bool ConnectFilters( vlc_object_t *, access_sys_t *,
                            IBaseFilter *, CaptureFilter * );
Gildas Bazin's avatar
 
Gildas Bazin committed
56 57
static int FindDevicesCallback( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );
58 59
static int ConfigDevicesCallback( vlc_object_t *, char const *,
                                  vlc_value_t, vlc_value_t, void * );
Gildas Bazin's avatar
 
Gildas Bazin committed
60

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
90 91
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
92
    "Caching value for DirectShow streams. " \
Clément Stenac's avatar
Clément Stenac committed
93
    "This value should be set in millisecondss." )
94 95
#define VDEV_TEXT N_("Video device name")
#define VDEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
96
    "Name of the video device that will be used by the " \
97 98
    "DirectShow plugin. If you don't specify anything, the default device " \
    "will be used.")
Clément Stenac's avatar
Clément Stenac committed
99
/// \bug [String] size stuff should be on video !
100 101
#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 " \
104
    "will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>")
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 109 110 111 112
    "DirectShow plugin. If you don't specify anything the default size for " \
    "your device will be used.")
#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 139 140 141
  "Select the video input source, such as composite, s-video, " \
  "or tuner. Since these settings are hardware-specfic, you should find good " \
  "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
    set_description( _("DirectShow input") );
Gildas Bazin's avatar
 
Gildas Bazin committed
229
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
230 231
    set_capability( "access2", 0 );
    set_callbacks( AccessOpen, AccessClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
232 233 234

vlc_module_end();

Gildas Bazin's avatar
Gildas Bazin committed
235
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
236
 * DirectShow elementary stream descriptor
Gildas Bazin's avatar
Gildas Bazin committed
237
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251
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
252 253 254
    int             i_fourcc;
    es_out_id_t     *p_es;

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

Gildas Bazin's avatar
Gildas Bazin committed
258
/*****************************************************************************
259
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
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 314
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
315
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
316
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
317
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
318 319
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
320
{
321
    vlc_value_t  val;
Gildas Bazin's avatar
Gildas Bazin committed
322
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
323

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

329 330
    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
331 332
    var_Create( p_this, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-vdev", &val );
333 334
    if( val.psz_string ) vdevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
335

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

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

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

373
    p_sys->b_chroma = VLC_FALSE;
Gildas Bazin's avatar
Gildas Bazin committed
374 375
    var_Create( p_this, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-chroma", &val );
376 377 378 379
    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] );
380
        p_sys->b_chroma = VLC_TRUE;
381 382
    }
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
383

384
    var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
385 386 387 388 389 390 391
    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 );

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

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

397 398 399 400 401
    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
402
    /* Initialize OLE/COM */
403
    CoInitialize( 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
404

Gildas Bazin's avatar
 
Gildas Bazin committed
405 406
    /* Initialize some data */
    p_sys->i_streams = 0;
407
    p_sys->pp_streams = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
408 409 410
    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
411

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
422
    if( OpenDevice( p_this, p_sys, vdevname, 0 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
423
    {
Gildas Bazin's avatar
Gildas Bazin committed
424
        msg_Err( p_this, "can't open video");
Gildas Bazin's avatar
 
Gildas Bazin committed
425
    }
Gildas Bazin's avatar
Gildas Bazin committed
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    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;
442 443 444 445

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

451 452 453 454 455 456 457 458 459
        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;
            }
460 461 462 463 464 465 466 467 468

            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 );
            }
469
        }
Gildas Bazin's avatar
Gildas Bazin committed
470 471 472
    }

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

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

492 493 494 495 496
        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
497

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

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

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

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

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

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
554 555 556
    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
557

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

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

Gildas Bazin's avatar
Gildas Bazin committed
568 569 570 571 572 573 574
    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++ )
575
    {
Gildas Bazin's avatar
Gildas Bazin committed
576 577
        dshow_stream_t *p_stream = p_sys->pp_streams[i];
        es_format_t fmt;
578

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

Gildas Bazin's avatar
Gildas Bazin committed
583 584 585
            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;
586

Gildas Bazin's avatar
Gildas Bazin committed
587 588 589 590 591
            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);
            }
592

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

            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
608 609 610 611
        }
        else if( p_stream->mt.majortype == MEDIATYPE_Audio )
        {
            es_format_Init( &fmt, AUDIO_ES, p_stream->i_fourcc );
612

Gildas Bazin's avatar
Gildas Bazin committed
613 614 615 616 617 618 619 620 621 622
            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 );
623
    }
Gildas Bazin's avatar
Gildas Bazin committed
624

625
    return VLC_SUCCESS;
626 627
}

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

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

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
662
    /* Setup Access */
663 664
    p_access->pf_read = NULL;
    p_access->pf_block = ReadCompressed;
Gildas Bazin's avatar
Gildas Bazin committed
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
    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;
680
}
Gildas Bazin's avatar
 
Gildas Bazin committed
681

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

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

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

694 695
    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
696 697 698

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

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

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

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

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

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

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

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

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

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

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

751 752 753
        // Sort out all the possible video inputs
        // The class needs to be given the capture filters ANALOGVIDEO input pin
        IEnumPins *pins = 0;
754 755
        if( ( mediaType.majortype == MEDIATYPE_Video ||
              mediaType.majortype == MEDIATYPE_Stream ) &&
756
            SUCCEEDED(p_filter->EnumPins(&pins)) )
Gildas Bazin's avatar
 
Gildas Bazin committed
757
        {
758 759 760 761 762 763 764 765
            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
766
            while( !Found && ( S_OK == pins->Next(1, &pP, &n) ) )
767
            {
Gildas Bazin's avatar
Gildas Bazin committed
768
                if( S_OK == pP->QueryPinInfo(&pinInfo) )
769
                {
Gildas Bazin's avatar
Gildas Bazin committed
770 771 772 773
                    // is this pin an ANALOGVIDEOIN input pin?
                    if( pinInfo.dir == PINDIR_INPUT &&
                        pP->QueryInterface( IID_IKsPropertySet,
                                            (void **)&pKs ) == S_OK )
774
                    {
Gildas Bazin's avatar
Gildas Bazin committed
775 776 777
                        if( pKs->Get( AMPROPSETID_Pin,
                                      AMPROPERTY_PIN_CATEGORY, NULL, 0,
                                      &guid, sizeof(GUID), &dw ) == S_OK )
778
                        {
Gildas Bazin's avatar
Gildas Bazin committed
779
                            if( guid == PIN_CATEGORY_ANALOGVIDEOIN )
780
                            {
Gildas Bazin's avatar
Gildas Bazin committed
781
                                // recursively search crossbar routes
782
                                FindCrossbarRoutes( p_this, p_sys, pP, 0 );
Gildas Bazin's avatar
Gildas Bazin committed
783 784
                                // found it
                                Found = TRUE;
785 786
                            }
                        }
Gildas Bazin's avatar
Gildas Bazin committed
787
                        pKs->Release();
788 789 790 791 792 793
                    }
                    pinInfo.pFilter->Release();
                }
                pP->Release();
            }
            pins->Release();
Gildas Bazin's avatar
 
Gildas Bazin committed
794
        }
795
        return true;
Gildas Bazin's avatar
 
Gildas Bazin committed
796
    }
797 798 799 800
    else
    {
        IEnumPins *p_enumpins;
        IPin *p_pin;
Gildas Bazin's avatar
 
Gildas Bazin committed
801

802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
        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
823 824
}

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

846 847 848 849 850
    return 0;
}

#define MAX_MEDIA_TYPES 32

Gildas Bazin's avatar
Gildas Bazin committed
851 852
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
853
{
854 855 856
    /* See if device is already opened */
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
Gildas Bazin's avatar
Gildas Bazin committed
857 858
        if( devicename.size() &&
            p_sys->pp_streams[i]->devicename == devicename )
859 860 861 862 863 864
        {
            /* Already opened */
            return VLC_SUCCESS;
        }
    }

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

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

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

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

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

899 900 901
    // Retreive acceptable media types supported by device
    AM_MEDIA_TYPE media_types[MAX_MEDIA_TYPES];
    size_t media_count =