dshow.cpp 89 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1
/*****************************************************************************
2
 * dshow.cpp : DirectShow access and access_demux module for vlc
Gildas Bazin's avatar
 
Gildas Bazin committed
3
 *****************************************************************************
4
 * Copyright (C) 2002-2004, 2006, 2008, 2010 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
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#define __STDC_CONSTANT_MACROS 1
34
#define __STDC_FORMAT_MACROS 1
35
#define CFG_PREFIX "dshow-"
36 37
#include <inttypes.h>

38
#include <vlc_common.h>
39
#include <vlc_plugin.h>
Clément Stenac's avatar
Clément Stenac committed
40
#include <vlc_access.h>
41
#include <vlc_demux.h>
42 43 44

#include <vlc_dialog.h>      /* dialog_Fatal */
#include <vlc_charset.h>     /* FromWide */
Gildas Bazin's avatar
 
Gildas Bazin committed
45

Gildas Bazin's avatar
Gildas Bazin committed
46
#include "common.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
47 48
#include "filter.h"

Gildas Bazin's avatar
 
Gildas Bazin committed
49 50 51
/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/
52
static block_t *ReadCompressed( access_t * );
53
static int AccessControl ( access_t *, int, va_list );
Gildas Bazin's avatar
 
Gildas Bazin committed
54

Gildas Bazin's avatar
Gildas Bazin committed
55 56 57
static int Demux       ( demux_t * );
static int DemuxControl( demux_t *, int, va_list );

58
static int OpenDevice( vlc_object_t *, access_sys_t *, string, bool );
Gildas Bazin's avatar
 
Gildas Bazin committed
59
static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
60
                                       list<string> *, bool );
61
static size_t EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
62 63
                              int, int, int, int, int, int,
                              AM_MEDIA_TYPE *mt, size_t );
Gildas Bazin's avatar
Gildas Bazin committed
64 65
static bool ConnectFilters( vlc_object_t *, access_sys_t *,
                            IBaseFilter *, CaptureFilter * );
Gildas Bazin's avatar
 
Gildas Bazin committed
66 67
static int FindDevicesCallback( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );
68 69
static int ConfigDevicesCallback( vlc_object_t *, char const *,
                                  vlc_value_t, vlc_value_t, void * );
Gildas Bazin's avatar
 
Gildas Bazin committed
70

71
static void ShowPropertyPage( IUnknown * );
72
static void ShowDeviceProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
73
                                  IBaseFilter *, bool );
74
static void ShowTunerProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
75
                                 IBaseFilter *, bool );
76 77
static void ConfigTuner( vlc_object_t *, ICaptureGraphBuilder2 *,
                         IBaseFilter * );
Gildas Bazin's avatar
 
Gildas Bazin committed
78

Gildas Bazin's avatar
 
Gildas Bazin committed
79
/*****************************************************************************
80
 * Module descriptor
Gildas Bazin's avatar
 
Gildas Bazin committed
81
 *****************************************************************************/
82 83
static const char *const ppsz_vdev[] = { "", "none" };
static const char *const ppsz_vdev_text[] = { N_("Default"), N_("None") };
84

85 86
static const char *const ppsz_adev[] = { "", "none" };
static const char *const ppsz_adev_text[] = { N_("Default"), N_("None") };
87

88 89
static const int pi_tuner_input[] = { 0, 1, 2 };
static const char *const ppsz_tuner_input_text[] =
90
    {N_("Default"), N_("Cable"), N_("Antenna")};
91

92
static const int pi_amtuner_mode[]  = { AMTUNER_MODE_DEFAULT,
93 94 95 96
                                        AMTUNER_MODE_TV,
                                        AMTUNER_MODE_FM_RADIO,
                                        AMTUNER_MODE_AM_RADIO,
                                        AMTUNER_MODE_DSS };
97
static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
98 99 100 101
                                          N_("TV"),
                                          N_("FM radio"),
                                          N_("AM radio"),
                                          N_("DSS") };
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
static const int i_standards_list[] =
    {
        KS_AnalogVideo_None,
        KS_AnalogVideo_NTSC_M, KS_AnalogVideo_NTSC_M_J, KS_AnalogVideo_NTSC_433,
        KS_AnalogVideo_PAL_B, KS_AnalogVideo_PAL_D, KS_AnalogVideo_PAL_G,
        KS_AnalogVideo_PAL_H, KS_AnalogVideo_PAL_I, KS_AnalogVideo_PAL_M,
        KS_AnalogVideo_PAL_N, KS_AnalogVideo_PAL_60,
        KS_AnalogVideo_SECAM_B, KS_AnalogVideo_SECAM_D, KS_AnalogVideo_SECAM_G,
        KS_AnalogVideo_SECAM_H, KS_AnalogVideo_SECAM_K, KS_AnalogVideo_SECAM_K1,
        KS_AnalogVideo_SECAM_L, KS_AnalogVideo_SECAM_L1,
        KS_AnalogVideo_PAL_N_COMBO
    };
static const char *const ppsz_standards_list_text[] =
    {
        N_("Default"),
        "NTSC_M", "NTSC_M_J", "NTSC_443",
        "PAL_B", "PAL_D", "PAL_G",
        "PAL_H", "PAL_I", "PAL_M",
        "PAL_N", "PAL_60",
        "SECAM_B", "SECAM_D", "SECAM_G",
        "SECAM_H", "SECAM_K", "SECAM_K1",
        "SECAM_L", "SECAM_L1",
        "PAL_N_COMBO"
    };

Gildas Bazin's avatar
 
Gildas Bazin committed
128 129
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
130
    "Caching value for DirectShow streams. " \
131
    "This value should be set in milliseconds." )
132 133
#define VDEV_TEXT N_("Video device name")
#define VDEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
134
    "Name of the video device that will be used by the " \
135 136 137 138
    "DirectShow plugin. If you don't specify anything, the default device " \
    "will be used.")
#define ADEV_TEXT N_("Audio device name")
#define ADEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
139
    "Name of the audio device that will be used by the " \
140
    "DirectShow plugin. If you don't specify anything, the default device " \
Christophe Mutricy's avatar
Christophe Mutricy committed
141
    "will be used. ")
142 143
#define SIZE_TEXT N_("Video size")
#define SIZE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
144
    "Size of the video that will be displayed by the " \
145
    "DirectShow plugin. If you don't specify anything the default size for " \
Christophe Mutricy's avatar
Christophe Mutricy committed
146
    "your device will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>.")
147 148
#define ASPECT_TEXT N_("Picture aspect-ratio n:m")
#define ASPECT_LONGTEXT N_("Define input picture aspect-ratio to use. Default is 4:3" )
149 150 151
#define CHROMA_TEXT N_("Video input chroma format")
#define CHROMA_LONGTEXT N_( \
    "Force the DirectShow video input to use a specific chroma format " \
152
    "(eg. I420 (default), RV24, etc.)")
153 154 155
#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
156
    "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
157
#define CONFIG_TEXT N_("Device properties")
Gildas Bazin's avatar
 
Gildas Bazin committed
158
#define CONFIG_LONGTEXT N_( \
159 160
    "Show the properties dialog of the selected device before starting the " \
    "stream.")
161 162 163
#define TUNER_TEXT N_("Tuner properties")
#define TUNER_LONGTEXT N_( \
    "Show the tuner properties [channel selection] page." )
164 165
#define CHANNEL_TEXT N_("Tuner TV Channel")
#define CHANNEL_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
166
    "Set the TV channel the tuner will set to " \
167
    "(0 means default)." )
168 169 170 171
#define TVFREQ_TEXT N_("Tuner Frequency")
#define TVFREQ_LONGTEXT N_(  "This overrides the channel. Measured in Hz." )
#define STANDARD_TEXT N_( "Standard" )
#define STANDARD_LONGTEXT N_( "Video standard (Default, SECAM_D, PAL_B, NTSC_M, etc...)." )
172 173
#define COUNTRY_TEXT N_("Tuner country code")
#define COUNTRY_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
174
    "Set the tuner country code that establishes the current " \
175 176 177
    "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
178
    "Select the tuner input type (Cable/Antenna)." )
179 180
#define VIDEO_IN_TEXT N_("Video input pin")
#define VIDEO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
181
  "Select the video input source, such as composite, s-video, " \
182
  "or tuner. Since these settings are hardware-specific, you should find good " \
Clément Stenac's avatar
Clément Stenac committed
183 184
  "settings in the \"Device config\" area, and use those numbers here. -1 " \
  "means that settings will not be changed.")
185 186
#define AUDIO_IN_TEXT N_("Audio input pin")
#define AUDIO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
187
  "Select the audio input source. See the \"video input\" option." )
188 189
#define VIDEO_OUT_TEXT N_("Video output pin")
#define VIDEO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
190
  "Select the video output type. See the \"video input\" option." )
191 192
#define AUDIO_OUT_TEXT N_("Audio output pin")
#define AUDIO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
193
  "Select the audio output type. See the \"video input\" option." )
Gildas Bazin's avatar
 
Gildas Bazin committed
194

195
#define AMTUNER_MODE_TEXT N_("AM Tuner mode")
196
#define AMTUNER_MODE_LONGTEXT N_( \
197 198
    "AM Tuner mode. Can be one of Default (0), TV (1)," \
     "AM Radio (2), FM Radio (3) or DSS (4).")
199

200 201
#define AUDIO_CHANNELS_TEXT N_("Number of audio channels")
#define AUDIO_CHANNELS_LONGTEXT N_( \
Felix Paul Kühne's avatar
Felix Paul Kühne committed
202
    "Select audio input format with the given number of audio channels (if non 0)" )
203 204 205 206 207 208 209 210 211

#define AUDIO_SAMPLERATE_TEXT N_("Audio sample rate")
#define AUDIO_SAMPLERATE_LONGTEXT N_( \
    "Select audio input format with the given sample rate (if non 0)" )

#define AUDIO_BITSPERSAMPLE_TEXT N_("Audio bits per sample")
#define AUDIO_BITSPERSAMPLE_LONGTEXT N_( \
    "Select audio input format with the given bits/sample (if non 0)" )

212
static int  CommonOpen ( vlc_object_t *, access_sys_t *, bool );
Gildas Bazin's avatar
Gildas Bazin committed
213 214
static void CommonClose( vlc_object_t *, access_sys_t * );

215 216 217 218 219 220
static int  AccessOpen ( vlc_object_t * );
static void AccessClose( vlc_object_t * );

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

221 222 223 224 225
vlc_module_begin ()
    set_shortname( N_("DirectShow") )
    set_description( N_("DirectShow input") )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACCESS )
226
    add_integer( CFG_PREFIX "caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
227
                 CACHING_TEXT, CACHING_LONGTEXT, true )
228

229
    add_string( CFG_PREFIX "vdev", NULL, VDEV_TEXT, VDEV_LONGTEXT, false)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
230
        change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback )
231 232
        change_action_add( FindDevicesCallback, N_("Refresh list") )
        change_action_add( ConfigDevicesCallback, N_("Configure") )
233

234
    add_string( CFG_PREFIX "adev", NULL, ADEV_TEXT, ADEV_LONGTEXT, false)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
235
        change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback )
236 237
        change_action_add( FindDevicesCallback, N_("Refresh list") )
        change_action_add( ConfigDevicesCallback, N_("Configure") )
238

239
    add_string( CFG_PREFIX "size", NULL, SIZE_TEXT, SIZE_LONGTEXT, false)
240

241
    add_string( CFG_PREFIX "aspect-ratio", "4:3", ASPECT_TEXT, ASPECT_LONGTEXT, false)
242

243
    add_string( CFG_PREFIX "chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
244

245
    add_float( CFG_PREFIX "fps", 0.0f, FPS_TEXT, FPS_LONGTEXT, true )
246

247
    add_bool( CFG_PREFIX "config", false, NULL, CONFIG_TEXT, CONFIG_LONGTEXT, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
248

249
    add_bool( CFG_PREFIX "tuner", false, NULL, TUNER_TEXT, TUNER_LONGTEXT, true )
250

251
    add_integer( CFG_PREFIX "tuner-channel", 0, NULL, CHANNEL_TEXT, CHANNEL_LONGTEXT,
252
                true )
253

254
    add_integer( CFG_PREFIX "tuner-frequency", 0, NULL, TVFREQ_TEXT, TVFREQ_LONGTEXT,
255 256
                true )

257
    add_integer( CFG_PREFIX "tuner-country", 0, NULL, COUNTRY_TEXT, COUNTRY_LONGTEXT,
258
                true )
259

260
    add_integer( CFG_PREFIX "tuner-standard", 0, NULL, STANDARD_TEXT, STANDARD_LONGTEXT,
261
                false )
262
        change_integer_list( i_standards_list, ppsz_standards_list_text )
263

264
    add_integer( CFG_PREFIX "tuner-input", 0, NULL, TUNER_INPUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
265
                 TUNER_INPUT_LONGTEXT, true )
266
        change_integer_list( pi_tuner_input, ppsz_tuner_input_text )
267

268
    add_integer( CFG_PREFIX "video-input",  -1, NULL, VIDEO_IN_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
269
                 VIDEO_IN_LONGTEXT, true )
270

271
    add_integer( CFG_PREFIX "video-output", -1, NULL, VIDEO_OUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
272
                 VIDEO_OUT_LONGTEXT, true )
273

274
    add_integer( CFG_PREFIX "audio-input",  -1, NULL, AUDIO_IN_TEXT,
275 276
                 AUDIO_IN_LONGTEXT, true )

277
    add_integer( CFG_PREFIX "audio-output", -1, NULL, AUDIO_OUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
278
                 AUDIO_OUT_LONGTEXT, true )
279

280
    add_integer( CFG_PREFIX "amtuner-mode", AMTUNER_MODE_TV, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
281
                AMTUNER_MODE_TEXT, AMTUNER_MODE_LONGTEXT, false)
282
        change_integer_list( pi_amtuner_mode, ppsz_amtuner_mode_text )
283

284
    add_integer( CFG_PREFIX "audio-channels", 0, NULL, AUDIO_CHANNELS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
285
                 AUDIO_CHANNELS_LONGTEXT, true )
286
    add_integer( CFG_PREFIX "audio-samplerate", 0, NULL, AUDIO_SAMPLERATE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
287
                 AUDIO_SAMPLERATE_LONGTEXT, true )
288
    add_integer( CFG_PREFIX "audio-bitspersample", 0, NULL, AUDIO_BITSPERSAMPLE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
289
                 AUDIO_BITSPERSAMPLE_LONGTEXT, true )
290

291 292 293
    add_shortcut( "dshow" )
    set_capability( "access_demux", 0 )
    set_callbacks( DemuxOpen, DemuxClose )
Gildas Bazin's avatar
 
Gildas Bazin committed
294

295 296
    add_submodule ()
    set_description( N_("DirectShow input") )
297
    add_shortcut( "dshow" )
298 299
    set_capability( "access", 0 )
    set_callbacks( AccessOpen, AccessClose )
Gildas Bazin's avatar
 
Gildas Bazin committed
300

301
vlc_module_end ()
Gildas Bazin's avatar
 
Gildas Bazin committed
302

303

Gildas Bazin's avatar
Gildas Bazin committed
304
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
305
 * DirectShow elementary stream descriptor
Gildas Bazin's avatar
Gildas Bazin committed
306
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320
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
321 322 323
    int             i_fourcc;
    es_out_id_t     *p_es;

324
    bool      b_pts;
325 326

    deque<VLCMediaSample> samples_queue;
Gildas Bazin's avatar
 
Gildas Bazin committed
327 328
} dshow_stream_t;

Gildas Bazin's avatar
Gildas Bazin committed
329
/*****************************************************************************
330
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
331
 *****************************************************************************/
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
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
386
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
387
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
388
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
389
static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
390
                       bool b_access_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
391
{
392
    char *psz_val;
Gildas Bazin's avatar
 
Gildas Bazin committed
393

394
    /* Get/parse options and open device(s) */
Gildas Bazin's avatar
 
Gildas Bazin committed
395
    string vdevname, adevname;
396 397
    int i_width = 0, i_height = 0;
    vlc_fourcc_t i_chroma = 0;
398 399 400 401 402
    bool b_use_audio = true;
    bool b_use_video = true;

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

404 405 406
    var_Create( p_this,  CFG_PREFIX "config", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_this,  CFG_PREFIX "tuner", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    psz_val = var_CreateGetString( p_this, CFG_PREFIX "vdev" );
407
    if( psz_val )
408
    {
409
        msg_Dbg( p_this, "dshow-vdev: %s", psz_val ) ;
410
        /* skip none device */
411 412
        if ( strncasecmp( psz_val, "none", 4 ) != 0 )
            vdevname = string( psz_val );
413 414 415
        else
            b_use_video = false ;
    }
416
    free( psz_val );
Gildas Bazin's avatar
 
Gildas Bazin committed
417

418
    psz_val = var_CreateGetString( p_this, CFG_PREFIX "adev" );
419
    if( psz_val )
420
    {
421
        msg_Dbg( p_this, "dshow-adev: %s", psz_val ) ;
422
        /* skip none device */
423 424
        if ( strncasecmp( psz_val, "none", 4 ) != 0 )
            adevname = string( psz_val );
425 426 427
        else
            b_use_audio = false ;
    }
428
    free( psz_val );
429

430 431 432 433 434 435 436 437 438 439 440 441
    /* DShow Size */
    static struct {
        const char *psz_size;
        int  i_width;
        int  i_height;
    } size_table[] =
    { { "subqcif", 128, 96  },
      {    "qsif", 160, 120 },
      {    "qcif", 176, 144 },
      {     "sif", 320, 240 },
      {     "cif", 352, 288 },
      {      "d1", 640, 480 },
Gildas Bazin's avatar
Gildas Bazin committed
442 443 444
      { 0, 0, 0 },
    };

445
    psz_val = var_CreateGetString( p_this, CFG_PREFIX "size" );
446
    if( !EMPTY_STR(psz_val) )
Gildas Bazin's avatar
 
Gildas Bazin committed
447
    {
448
        int i;
Gildas Bazin's avatar
Gildas Bazin committed
449
        for( i = 0; size_table[i].psz_size; i++ )
450
        {
451
            if( !strcmp( psz_val, size_table[i].psz_size ) )
Gildas Bazin's avatar
Gildas Bazin committed
452 453 454 455 456
            {
                i_width = size_table[i].i_width;
                i_height = size_table[i].i_height;
                break;
            }
457
        }
Gildas Bazin's avatar
Gildas Bazin committed
458
        if( !size_table[i].psz_size ) /* Try to parse "WidthxHeight" */
459 460
        {
            char *psz_parser;
461
            i_width = strtol( psz_val, &psz_parser, 0 );
462
            if( *psz_parser == 'x' || *psz_parser == 'X')
Gildas Bazin's avatar
 
Gildas Bazin committed
463
            {
464
                i_height = strtol( psz_parser + 1, &psz_parser, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
465
            }
Clément Stenac's avatar
Clément Stenac committed
466
            msg_Dbg( p_this, "width x height %dx%d", i_width, i_height );
Gildas Bazin's avatar
 
Gildas Bazin committed
467 468
        }
    }
469
    free( psz_val );
Gildas Bazin's avatar
 
Gildas Bazin committed
470

471
    /* Chroma */
472
    psz_val = var_CreateGetString( p_this, CFG_PREFIX "chroma" );
473
    i_chroma = vlc_fourcc_GetCodecFromString( UNKNOWN_ES, psz_val );
474
    p_sys->b_chroma = i_chroma != 0;
475
    free( psz_val );
Gildas Bazin's avatar
 
Gildas Bazin committed
476

477 478
    var_Create( p_this, CFG_PREFIX "fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
    var_Create( p_this, CFG_PREFIX "tuner-channel",
479
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
480
    var_Create( p_this, CFG_PREFIX "tuner-frequency",
481
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
482
    var_Create( p_this, CFG_PREFIX "tuner-standard",
483
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
484
    var_Create( p_this, CFG_PREFIX "tuner-country",
485
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
486
    var_Create( p_this, CFG_PREFIX "tuner-input",
487 488
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

489
    var_Create( p_this, CFG_PREFIX "amtuner-mode",
490 491
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

492
    var_Create( p_this, CFG_PREFIX "caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
493

494 495 496 497
    var_Create( p_this, CFG_PREFIX "video-input", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, CFG_PREFIX "audio-input", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, CFG_PREFIX "video-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, CFG_PREFIX "audio-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
498

499

Gildas Bazin's avatar
 
Gildas Bazin committed
500 501
    /* Initialize some data */
    p_sys->i_streams = 0;
Rémi Duraffort's avatar
Rémi Duraffort committed
502
    p_sys->pp_streams = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
503 504 505
    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
506

507 508 509
    p_sys->p_graph = NULL;
    p_sys->p_capture_graph_builder2 = NULL;
    p_sys->p_control = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
510

511 512 513
    /* Build directshow graph */
    CreateDirectShowGraph( p_sys );

514
    vlc_mutex_init( &p_sys->lock );
515
    vlc_cond_init( &p_sys->wait );
516

517 518
    if( !b_use_video && !b_use_audio )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
519
        dialog_Fatal( p_this, _("Capture failed"),
basos g's avatar
basos g committed
520
                        _("No video or audio device selected.") );
521 522
        return VLC_EGENERIC ;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
523

524 525 526 527 528
    if( !b_use_video )
        msg_Dbg( p_this, "skipping video device" ) ;
    bool b_err_video = false ;

    if( b_use_video && OpenDevice( p_this, p_sys, vdevname, 0 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
529
    {
530 531
        msg_Err( p_this, "can't open video device");
        b_err_video = true ;
Gildas Bazin's avatar
 
Gildas Bazin committed
532
    }
533 534

    if ( b_use_video && !b_err_video )
Gildas Bazin's avatar
Gildas Bazin committed
535 536 537 538 539 540 541 542
    {
        /* 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 */
543
                p_stream->i_fourcc == VLC_CODEC_DV ||
Gildas Bazin's avatar
Gildas Bazin committed
544
                /* Raw MPEG video stream */
Laurent Aimar's avatar
Laurent Aimar committed
545
                p_stream->i_fourcc == VLC_CODEC_MPGV )
Gildas Bazin's avatar
Gildas Bazin committed
546
            {
547
                b_use_audio = false;
548 549 550 551

                if( b_access_demux )
                {
                    /* Let the access (only) take care of that */
552
                    return VLC_EGENERIC;
553
                }
Gildas Bazin's avatar
Gildas Bazin committed
554 555
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
556

557 558
        if( p_stream->mt.majortype == MEDIATYPE_Stream )
        {
559
            b_use_audio = false;
560 561 562 563 564 565

            if( b_access_demux )
            {
                /* Let the access (only) take care of that */
                return VLC_EGENERIC;
            }
566

567
            if( var_GetBool( p_this, CFG_PREFIX "tuner" ) )
568 569 570 571 572 573
            {
                /* 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 );
            }
574
        }
Gildas Bazin's avatar
Gildas Bazin committed
575 576
    }

577 578 579 580 581 582
    if( !b_use_audio )
        msg_Dbg( p_this, "skipping audio device") ;

    bool b_err_audio = false ;

    if( b_use_audio && OpenDevice( p_this, p_sys, adevname, 1 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
583
    {
584 585 586 587 588 589 590 591 592
        msg_Err( p_this, "can't open audio device");
        b_err_audio = true ;
    }

    if( ( b_use_video && b_err_video && b_use_audio && b_err_audio ) ||
        ( !b_use_video && b_use_audio && b_err_audio ) ||
        ( b_use_video && !b_use_audio && b_err_video ) )
    {
        msg_Err( p_this, "FATAL: could not open ANY device" ) ;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
593
        dialog_Fatal( p_this,  _("Capture failed"),
594 595 596
                        _("VLC cannot open ANY capture device."
                          "Check the error log for details.") );
        return VLC_EGENERIC ;
Gildas Bazin's avatar
 
Gildas Bazin committed
597
    }
Gildas Bazin's avatar
Gildas Bazin committed
598

599
    for( int i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
Gildas Bazin's avatar
 
Gildas Bazin committed
600
    {
601
        int i_val = var_GetInteger( p_this, CFG_PREFIX "video-input" );
602 603
        if( i_val >= 0 )
            p_sys->crossbar_routes[i].VideoInputIndex = i_val;
604
        i_val = var_GetInteger( p_this, CFG_PREFIX "video-output" );
605 606
        if( i_val >= 0 )
            p_sys->crossbar_routes[i].VideoOutputIndex = i_val;
607
        i_val = var_GetInteger( p_this, CFG_PREFIX "audio-input" );
608 609
        if( i_val >= 0 )
            p_sys->crossbar_routes[i].AudioInputIndex = i_val;
610
        i_val = var_GetInteger( p_this, CFG_PREFIX "audio-output" );
611 612
        if( i_val >= 0 )
            p_sys->crossbar_routes[i].AudioOutputIndex = i_val;
613

614 615 616 617 618
        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
619

620 621
        if( SUCCEEDED(pXbar->Route(VideoOutputIndex, VideoInputIndex)) )
        {
Clément Stenac's avatar
Clément Stenac committed
622 623
            msg_Dbg( p_this, "crossbar at depth %d, routed video "
                     "output %ld to video input %ld", i, VideoOutputIndex,
624
                     VideoInputIndex );
Gildas Bazin's avatar
 
Gildas Bazin committed
625

626 627 628 629 630
            if( AudioOutputIndex != -1 && AudioInputIndex != -1 )
            {
                if( SUCCEEDED( pXbar->Route(AudioOutputIndex,
                                            AudioInputIndex)) )
                {
Clément Stenac's avatar
Clément Stenac committed
631 632
                    msg_Dbg(p_this, "crossbar at depth %d, routed audio "
                            "output %ld to audio input %ld", i,
633 634 635 636
                            AudioOutputIndex, AudioInputIndex );
                }
            }
        }
637 638 639
        else
            msg_Err( p_this, "crossbar at depth %d could not route video "
                     "output %ld to input %ld", i, VideoOutputIndex, VideoInputIndex );
640 641
    }

642 643 644
    /*
    ** Show properties pages from other filters in graph
    */
645
    if( var_GetBool( p_this, CFG_PREFIX "config" ) )
646
    {
647
        for( int i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
648 649 650
        {
            IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
            IBaseFilter *p_XF;
651 652 653

            if( SUCCEEDED( pXbar->QueryInterface( IID_IBaseFilter,
                                                  (void **)&p_XF ) ) )
654 655 656 657
            {
                ShowPropertyPage( p_XF );
                p_XF->Release();
            }
658
        }
659 660
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
661 662
    /* Initialize some data */
    p_sys->i_current_stream = 0;
663

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

Gildas Bazin's avatar
 
Gildas Bazin committed
666 667 668 669
    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
670
 * DemuxOpen: open direct show device as an access_demux module
Gildas Bazin's avatar
 
Gildas Bazin committed
671
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
672
static int DemuxOpen( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
673
{
Gildas Bazin's avatar
Gildas Bazin committed
674 675
    demux_t      *p_demux = (demux_t *)p_this;
    access_sys_t *p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
676

Rémi Duraffort's avatar
Rémi Duraffort committed
677
    p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t ) );
Rémi Duraffort's avatar
Rémi Duraffort committed
678 679
    if( !p_sys )
        return VLC_ENOMEM;
Gildas Bazin's avatar
Gildas Bazin committed
680
    p_demux->p_sys = (demux_sys_t *)p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
681

682
    if( CommonOpen( p_this, p_sys, true ) != VLC_SUCCESS )
Gildas Bazin's avatar
Gildas Bazin committed
683 684 685 686
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
687

Gildas Bazin's avatar
Gildas Bazin committed
688 689 690
    /* Everything is ready. Let's rock baby */
    msg_Dbg( p_this, "Playing...");
    p_sys->p_control->Run();
691

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

698
    for( int i = 0; i < p_sys->i_streams; i++ )
699
    {
Gildas Bazin's avatar
Gildas Bazin committed
700 701
        dshow_stream_t *p_stream = p_sys->pp_streams[i];
        es_format_t fmt;
702

Gildas Bazin's avatar
Gildas Bazin committed
703 704
        if( p_stream->mt.majortype == MEDIATYPE_Video )
        {
705
            char *psz_aspect = var_CreateGetString( p_this, CFG_PREFIX "aspect-ratio" );
706 707
            char *psz_delim = !EMPTY_STR( psz_aspect ) ? strchr( psz_aspect, ':' ) : NULL;

Gildas Bazin's avatar
Gildas Bazin committed
708
            es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
709

Gildas Bazin's avatar
Gildas Bazin committed
710 711
            fmt.video.i_width  = p_stream->header.video.bmiHeader.biWidth;
            fmt.video.i_height = p_stream->header.video.bmiHeader.biHeight;
712 713 714 715 716 717 718 719 720 721 722 723

            if( psz_delim )
            {
                fmt.video.i_sar_num = atoi( psz_aspect ) * fmt.video.i_height;
                fmt.video.i_sar_den = atoi( psz_delim + 1 ) * fmt.video.i_width;
            }
            else
            {
                fmt.video.i_sar_num = 4 * fmt.video.i_height;
                fmt.video.i_sar_den = 3 * fmt.video.i_width;
            }
            free( psz_aspect );
724

Gildas Bazin's avatar
Gildas Bazin committed
725 726 727 728 729
            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);
            }
730

Gildas Bazin's avatar
Gildas Bazin committed
731
            /* Setup rgb mask for RGB formats */
732
            if( p_stream->i_fourcc == VLC_CODEC_RGB24 )
Gildas Bazin's avatar
Gildas Bazin committed
733
            {
734 735 736 737
                /* This is in RGB format
            http://msdn.microsoft.com/en-us/library/dd407253%28VS.85%29.aspx?ppud=4
                 */
                fmt.video.i_rmask = 0x00ff0000;
738
                fmt.video.i_gmask = 0x0000ff00;
739
                fmt.video.i_bmask = 0x000000ff;
Gildas Bazin's avatar
Gildas Bazin committed
740
            }
741 742 743 744 745 746 747

            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
748 749 750 751
        }
        else if( p_stream->mt.majortype == MEDIATYPE_Audio )
        {
            es_format_Init( &fmt, AUDIO_ES, p_stream->i_fourcc );
752

Gildas Bazin's avatar
Gildas Bazin committed
753 754 755 756 757 758 759 760 761 762
            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 );
763
    }
Gildas Bazin's avatar
Gildas Bazin committed
764

765
    return VLC_SUCCESS;
766 767
}

Gildas Bazin's avatar
Gildas Bazin committed
768 769 770 771
/*****************************************************************************
 * AccessOpen: open direct show device as an access module
 *****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
772
{
Gildas Bazin's avatar
Gildas Bazin committed
773 774
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;
775

Rémi Duraffort's avatar
Rémi Duraffort committed
776
    p_access->p_sys = p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t ) );
Rémi Duraffort's avatar
Rémi Duraffort committed
777 778
    if( !p_sys )
        return VLC_ENOMEM;
779

780
    if( CommonOpen( p_this, p_sys, false ) != VLC_SUCCESS )
Gildas Bazin's avatar
Gildas Bazin committed
781 782 783 784
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
785

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

Gildas Bazin's avatar
Gildas Bazin committed
788 789
    /* Check if we need to force demuxers */
    if( !p_access->psz_demux || !*p_access->psz_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
790
    {
791
        if( p_stream->i_fourcc == VLC_CODEC_DV )
792
        {
Rafaël Carré's avatar
Rafaël Carré committed
793
            free( p_access->psz_demux );
Gildas Bazin's avatar
Gildas Bazin committed
794 795
            p_access->psz_demux = strdup( "rawdv" );
        }
Laurent Aimar's avatar
Laurent Aimar committed
796
        else if( p_stream->i_fourcc == VLC_CODEC_MPGV )
Gildas Bazin's avatar
Gildas Bazin committed
797
        {
Rafaël Carré's avatar
Rafaël Carré committed
798 799
            free( p_access->psz_demux );
            p_access->psz_demux = strdup( "mpgv" );
800
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
801
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
802

Gildas Bazin's avatar
Gildas Bazin committed
803
    /* Setup Access */
804 805
    p_access->pf_read = NULL;
    p_access->pf_block = ReadCompressed;
Gildas Bazin's avatar
Gildas Bazin committed
806 807 808 809 810
    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;
811
    p_access->info.b_eof = false;
Gildas Bazin's avatar
Gildas Bazin committed
812 813 814 815 816 817 818 819 820
    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;
821
}
Gildas Bazin's avatar
 
Gildas Bazin committed
822

Gildas Bazin's avatar
Gildas Bazin committed
823 824 825 826
/*****************************************************************************
 * CommonClose: close device
 *****************************************************************************/
static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
827
{
Clément Stenac's avatar
Clément Stenac committed
828
    msg_Dbg( p_this, "releasing DirectShow");
829

Gildas Bazin's avatar
Gildas Bazin committed
830
    DeleteDirectShowGraph( p_sys );
831

Gildas Bazin's avatar
Gildas Bazin committed
832 833
    /* Uninitialize OLE/COM */
    CoUninitialize();
834

835 836
    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 );