dshow.cpp 76.6 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 33 34
 *****************************************************************************/

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

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/vout.h>
35
#include <vlc_interaction.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 char *ppsz_vdev[] = { "", "none" };
static char *ppsz_vdev_text[] = { N_("Default"), N_("None") };
static char *ppsz_adev[] = { "", "none" };
static char *ppsz_adev_text[] = { N_("Default"), N_("None") };
77 78 79
static int  pi_tuner_input[] = { 0, 1, 2 };
static char *ppsz_tuner_input_text[] =
    {N_("Default"), N_("Cable"), N_("Antenna")};
80 81 82 83 84 85 86 87 88 89
static int pi_amtuner_mode[] = { AMTUNER_MODE_DEFAULT,
                                 AMTUNER_MODE_TV,
                                 AMTUNER_MODE_FM_RADIO,
                                 AMTUNER_MODE_AM_RADIO,
                                 AMTUNER_MODE_DSS };
static char *ppsz_amtuner_mode_text[] = { N_("Default"),
                                          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
    "DirectShow plugin. If you don't specify anything, the default device " \
    "will be used.")
Clément Stenac's avatar
Clément Stenac committed
100
/// \bug [String] size stuff should be on video !
101 102
#define ADEV_TEXT N_("Audio device name")
#define ADEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
103
    "Name of the audio device that will be used by the " \
104
    "DirectShow plugin. If you don't specify anything, the default device " \
105
    "will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>")
106 107
#define SIZE_TEXT N_("Video size")
#define SIZE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
108
    "Size of the video that will be displayed by the " \
109 110 111 112 113
    "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 " \
114
    "(eg. I420 (default), RV24, etc.)")
115 116 117
#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
118
    "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
119
#define CONFIG_TEXT N_("Device properties")
Gildas Bazin's avatar
 
Gildas Bazin committed
120
#define CONFIG_LONGTEXT N_( \
121 122
    "Show the properties dialog of the selected device before starting the " \
    "stream.")
123 124 125
#define TUNER_TEXT N_("Tuner properties")
#define TUNER_LONGTEXT N_( \
    "Show the tuner properties [channel selection] page." )
126 127
#define CHANNEL_TEXT N_("Tuner TV Channel")
#define CHANNEL_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
128
    "Set the TV channel the tuner will set to " \
129 130 131
    "(0 means default)." )
#define COUNTRY_TEXT N_("Tuner country code")
#define COUNTRY_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
132
    "Set the tuner country code that establishes the current " \
133 134 135
    "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
136
    "Select the tuner input type (Cable/Antenna)." )
137 138
#define VIDEO_IN_TEXT N_("Video input pin")
#define VIDEO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
139 140 141 142
  "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.")
143 144
#define AUDIO_IN_TEXT N_("Audio input pin")
#define AUDIO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
145
  "Select the audio input source. See the \"video input\" option." )
146 147
#define VIDEO_OUT_TEXT N_("Video output pin")
#define VIDEO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
148
  "Select the video output type. See the \"video input\" option." )
149 150
#define AUDIO_OUT_TEXT N_("Audio output pin")
#define AUDIO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
151
  "Select the audio output type. See the \"video input\" option." )
Gildas Bazin's avatar
 
Gildas Bazin committed
152

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

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

160 161 162 163 164 165
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
166
vlc_module_begin();
167
    set_shortname( _("DirectShow") );
Gildas Bazin's avatar
 
Gildas Bazin committed
168
    set_description( _("DirectShow input") );
Clément Stenac's avatar
Clément Stenac committed
169 170
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACCESS );
171
    add_integer( "dshow-caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
Gildas Bazin's avatar
 
Gildas Bazin committed
172
                 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
173

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

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

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

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

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

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

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

198 199 200 201 202 203 204 205 206 207
    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 );

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

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

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

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

220
    add_integer( "dshow-amtuner-mode", AMTUNER_MODE_TV, NULL,
221 222 223
                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
224
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
225 226
    set_capability( "access_demux", 0 );
    set_callbacks( DemuxOpen, DemuxClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
227 228

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

vlc_module_end();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

626
    return VLC_SUCCESS;
627 628
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

847 848 849 850 851
    return 0;
}

#define MAX_MEDIA_TYPES 32

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

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

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

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

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

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

900 901 902
    // Retreive acceptable media types supported by device
    AM_MEDIA_TYPE media_types[MAX_MEDIA_TYPES];
    size_t media_count =
903
        EnumDeviceCaps( p_this, p_device_filter, b_audio ? 0 : p_sys->i_chroma,
904 905 906
                        p_sys->i_width, p_sys->i_height,
                        0, 0, 0, media_types, MAX_MEDIA_TYPES );

907
    AM_MEDIA_TYPE *mt = NULL;
Gildas Bazin's avatar
Gildas Bazin committed
908

909 910
    if( media_count