dshow.cpp 85.8 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 CFG_PREFIX "dshow-"
34
#include <inttypes.h>
35 36
#include <list>
#include <string>
37
#include <assert.h>
38

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

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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
48 49 50
#include <initguid.h>
#include "vlc_dshow.h"

51
#include "access.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
52 53
#include "filter.h"

54 55 56
#define INSTANCEDATA_OF_PROPERTY_PTR(x) ((PKSPROPERTY((x))) + 1)
#define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))

Gildas Bazin's avatar
 
Gildas Bazin committed
57 58 59
/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/
60
static block_t *ReadCompressed( access_t * );
61
static int AccessControl ( access_t *, int, va_list );
Gildas Bazin's avatar
 
Gildas Bazin committed
62

Gildas Bazin's avatar
Gildas Bazin committed
63 64 65
static int Demux       ( demux_t * );
static int DemuxControl( demux_t *, int, va_list );

66
static int OpenDevice( vlc_object_t *, access_sys_t *, string, bool );
Gildas Bazin's avatar
 
Gildas Bazin committed
67
static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
68
                                       list<string> *, bool );
69
static size_t EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
70 71
                              int, int, int, int, int, int,
                              AM_MEDIA_TYPE *mt, size_t );
Gildas Bazin's avatar
Gildas Bazin committed
72 73
static bool ConnectFilters( vlc_object_t *, access_sys_t *,
                            IBaseFilter *, CaptureFilter * );
74
static int FindDevices( vlc_object_t *, const char *, char ***, char *** );
Gildas Bazin's avatar
 
Gildas Bazin committed
75

76
static void ShowPropertyPage( IUnknown * );
77
static void ShowDeviceProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
78
                                  IBaseFilter *, bool );
79
static void ShowTunerProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
80
                                 IBaseFilter *, bool );
81 82
static void ConfigTuner( vlc_object_t *, ICaptureGraphBuilder2 *,
                         IBaseFilter * );
Gildas Bazin's avatar
 
Gildas Bazin committed
83

Gildas Bazin's avatar
 
Gildas Bazin committed
84
/*****************************************************************************
85
 * Module descriptor
Gildas Bazin's avatar
 
Gildas Bazin committed
86
 *****************************************************************************/
87 88
static const int pi_tuner_input[] = { 0, 1, 2 };
static const char *const ppsz_tuner_input_text[] =
89
    {N_("Default"), N_("Cable"), N_("Antenna")};
90

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

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
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"
    };

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

189
#define AMTUNER_MODE_TEXT N_("AM Tuner mode")
190
#define AMTUNER_MODE_LONGTEXT N_( \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
191
    "AM Tuner mode. Can be one of Default (0), TV (1), " \
192
     "AM Radio (2), FM Radio (3) or DSS (4).")
193

194 195
#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
196
    "Select audio input format with the given number of audio channels (if non 0)" )
197 198 199 200 201 202 203 204 205

#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)" )

206
static int  CommonOpen ( vlc_object_t *, access_sys_t *, bool );
Gildas Bazin's avatar
Gildas Bazin committed
207 208
static void CommonClose( vlc_object_t *, access_sys_t * );

209 210 211 212 213 214
static int  AccessOpen ( vlc_object_t * );
static void AccessClose( vlc_object_t * );

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

215 216 217 218 219
vlc_module_begin ()
    set_shortname( N_("DirectShow") )
    set_description( N_("DirectShow input") )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACCESS )
220

221
    add_string( CFG_PREFIX "vdev", NULL, VDEV_TEXT, VDEV_LONGTEXT, false)
222
        change_string_cb( FindDevices )
223

224
    add_string( CFG_PREFIX "adev", NULL, ADEV_TEXT, ADEV_LONGTEXT, false)
225
        change_string_cb( FindDevices )
226

227
    add_string( CFG_PREFIX "size", NULL, SIZE_TEXT, SIZE_LONGTEXT, false)
228
        change_safe()
229

230
    add_string( CFG_PREFIX "aspect-ratio", "4:3", ASPECT_TEXT, ASPECT_LONGTEXT, false)
231
        change_safe()
232

233
    add_string( CFG_PREFIX "chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
234
        change_safe()
Gildas Bazin's avatar
 
Gildas Bazin committed
235

236
    add_float( CFG_PREFIX "fps", 0.0f, FPS_TEXT, FPS_LONGTEXT, true )
237
        change_safe()
238

239
    add_bool( CFG_PREFIX "config", false, CONFIG_TEXT, CONFIG_LONGTEXT, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
240

241
    add_bool( CFG_PREFIX "tuner", false, TUNER_TEXT, TUNER_LONGTEXT, true )
242

243
    add_integer( CFG_PREFIX "tuner-channel", 0, CHANNEL_TEXT, CHANNEL_LONGTEXT,
244
                true )
245
        change_safe()
246

247
    add_integer( CFG_PREFIX "tuner-frequency", 0, TVFREQ_TEXT, TVFREQ_LONGTEXT,
248
                true )
249
        change_safe()
250

251
    add_integer( CFG_PREFIX "tuner-country", 0, COUNTRY_TEXT, COUNTRY_LONGTEXT,
252
                true )
253

254
    add_integer( CFG_PREFIX "tuner-standard", 0, STANDARD_TEXT, STANDARD_TEXT,
255
                false )
256
        change_integer_list( i_standards_list, ppsz_standards_list_text )
257
        change_safe()
258

259
    add_integer( CFG_PREFIX "tuner-input", 0, TUNER_INPUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
260
                 TUNER_INPUT_LONGTEXT, true )
261
        change_integer_list( pi_tuner_input, ppsz_tuner_input_text )
262
        change_safe()
263

264
    add_integer( CFG_PREFIX "video-input",  -1, VIDEO_IN_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
265
                 VIDEO_IN_LONGTEXT, true )
266
        change_safe()
267

268
    add_integer( CFG_PREFIX "video-output", -1, VIDEO_OUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
269
                 VIDEO_OUT_LONGTEXT, true )
270

271
    add_integer( CFG_PREFIX "audio-input",  -1, AUDIO_IN_TEXT,
272
                 AUDIO_IN_LONGTEXT, true )
273
        change_safe()
274

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

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

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

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

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

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

302

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

323
    bool      b_pts;
324 325

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

Gildas Bazin's avatar
Gildas Bazin committed
328
/*****************************************************************************
329
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
330
 *****************************************************************************/
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
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 );
    }
}

353
static void DeleteDirectShowGraph( vlc_object_t *p_this, access_sys_t *p_sys )
354 355 356 357
{
    DeleteCrossbarRoutes( p_sys );

    /* Remove filters from graph */
358
    msg_Dbg( p_this, "DeleteDirectShowGraph: Removing filters" );
359 360
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
361 362 363
        /* RemoveFilter does an undocumented Release()
         * but does not set item to NULL */
        msg_Dbg( p_this, "DeleteDirectShowGraph: Removing capture filter" );
364
        p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );
365 366 367
        p_sys->pp_streams[i]->p_capture_filter = NULL;

        msg_Dbg( p_this, "DeleteDirectShowGraph: Removing device filter" );
368
        p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );
369
        p_sys->pp_streams[i]->p_device_filter = NULL;
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
    }

    /* 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
391
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
392
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
393
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
394
static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
395
                       bool b_access_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
396
{
397
    char *psz_val;
Gildas Bazin's avatar
 
Gildas Bazin committed
398

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

    /* Initialize OLE/COM */
407 408
    if( FAILED(CoInitializeEx( NULL, COINIT_APARTMENTTHREADED )) )
        vlc_assert_unreachable();
Gildas Bazin's avatar
 
Gildas Bazin committed
409

410 411 412
    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" );
413
    if( psz_val )
414
    {
415
        msg_Dbg( p_this, "dshow-vdev: %s", psz_val ) ;
416
        /* skip none device */
417 418
        if ( strncasecmp( psz_val, "none", 4 ) != 0 )
            vdevname = string( psz_val );
419 420 421
        else
            b_use_video = false ;
    }
422
    free( psz_val );
Gildas Bazin's avatar
 
Gildas Bazin committed
423

424
    psz_val = var_CreateGetString( p_this, CFG_PREFIX "adev" );
425
    if( psz_val )
426
    {
427
        msg_Dbg( p_this, "dshow-adev: %s", psz_val ) ;
428
        /* skip none device */
429 430
        if ( strncasecmp( psz_val, "none", 4 ) != 0 )
            adevname = string( psz_val );
431 432 433
        else
            b_use_audio = false ;
    }
434
    free( psz_val );
435

436 437 438 439 440 441 442 443 444 445 446 447
    /* 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
448 449 450
      { 0, 0, 0 },
    };

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

477
    /* Chroma */
478
    psz_val = var_CreateGetString( p_this, CFG_PREFIX "chroma" );
479
    i_chroma = vlc_fourcc_GetCodecFromString( UNKNOWN_ES, psz_val );
480
    p_sys->b_chroma = i_chroma != 0;
481
    free( psz_val );
Gildas Bazin's avatar
 
Gildas Bazin committed
482

483 484
    var_Create( p_this, CFG_PREFIX "fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
    var_Create( p_this, CFG_PREFIX "tuner-channel",
485
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
486
    var_Create( p_this, CFG_PREFIX "tuner-frequency",
487
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
488
    var_Create( p_this, CFG_PREFIX "tuner-standard",
489
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
490
    var_Create( p_this, CFG_PREFIX "tuner-country",
491
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
492
    var_Create( p_this, CFG_PREFIX "tuner-input",
493 494
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

495
    var_Create( p_this, CFG_PREFIX "amtuner-mode",
496 497
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

498 499 500 501
    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 );
502

503

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

511 512 513
    p_sys->p_graph = NULL;
    p_sys->p_capture_graph_builder2 = NULL;
    p_sys->p_control = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
514

515 516 517
    /* Build directshow graph */
    CreateDirectShowGraph( p_sys );

518
    vlc_mutex_init( &p_sys->lock );
519
    vlc_cond_init( &p_sys->wait );
520

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

528 529 530 531 532
    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
533
    {
534 535
        msg_Err( p_this, "can't open video device");
        b_err_video = true ;
Gildas Bazin's avatar
 
Gildas Bazin committed
536
    }
537 538

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

                if( b_access_demux )
                {
                    /* Let the access (only) take care of that */
556
                    return VLC_EGENERIC;
557
                }
Gildas Bazin's avatar
Gildas Bazin committed
558 559
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
560

561 562
        if( p_stream->mt.majortype == MEDIATYPE_Stream )
        {
563
            b_use_audio = false;
564 565 566 567 568 569

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

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

581 582 583 584 585 586
    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
587
    {
588 589 590 591 592 593 594 595 596
        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
597
        dialog_Fatal( p_this,  _("Capture failed"),
598
                        _("VLC cannot open ANY capture device. "
599 600
                          "Check the error log for details.") );
        return VLC_EGENERIC ;
Gildas Bazin's avatar
 
Gildas Bazin committed
601
    }
Gildas Bazin's avatar
Gildas Bazin committed
602

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

618 619 620 621 622
        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
623

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

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

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

            if( SUCCEEDED( pXbar->QueryInterface( IID_IBaseFilter,
                                                  (void **)&p_XF ) ) )
658 659 660 661
            {
                ShowPropertyPage( p_XF );
                p_XF->Release();
            }
662
        }
663 664
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
665 666
    /* Initialize some data */
    p_sys->i_current_stream = 0;
667

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

Gildas Bazin's avatar
 
Gildas Bazin committed
670 671 672 673
    return VLC_SUCCESS;
}

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

Rémi Duraffort's avatar
Rémi Duraffort committed
681
    p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t ) );
Rémi Duraffort's avatar
Rémi Duraffort committed
682 683
    if( !p_sys )
        return VLC_ENOMEM;
Gildas Bazin's avatar
Gildas Bazin committed
684
    p_demux->p_sys = (demux_sys_t *)p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
685

686
    if( CommonOpen( p_this, p_sys, true ) != VLC_SUCCESS )
Gildas Bazin's avatar
Gildas Bazin committed
687 688 689 690
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
691

Gildas Bazin's avatar
Gildas Bazin committed
692 693 694
    /* Everything is ready. Let's rock baby */
    msg_Dbg( p_this, "Playing...");
    p_sys->p_control->Run();
695

Gildas Bazin's avatar
Gildas Bazin committed
696 697 698 699 700
    p_demux->pf_demux   = Demux;
    p_demux->pf_control = DemuxControl;
    p_demux->info.i_title = 0;
    p_demux->info.i_seekpoint = 0;

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

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

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

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

            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 );
727

Gildas Bazin's avatar
Gildas Bazin committed
728 729 730
            if( !p_stream->header.video.bmiHeader.biCompression )
            {
                /* RGB DIB are coded from bottom to top */
731
                fmt.video.orientation = ORIENT_BOTTOM_LEFT;
Gildas Bazin's avatar
Gildas Bazin committed
732
            }
733

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

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

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

768
    return VLC_SUCCESS;
769 770
}

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

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
791
    /* Check if we need to force demuxers */
792
    if( p_stream->i_fourcc == VLC_CODEC_DV )
Gildas Bazin's avatar
 
Gildas Bazin committed
793
    {
794 795 796 797 798 799 800
        free( p_access->psz_demux );
        p_access->psz_demux = strdup( "rawdv" );
    }
    else if( p_stream->i_fourcc == VLC_CODEC_MPGV )
    {
        free( p_access->psz_demux );
        p_access->psz_demux = strdup( "mpgv" );
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
    p_access->pf_control = AccessControl;
    p_access->pf_seek = NULL;
    p_access->info.i_pos = 0;
809
    p_access->info.b_eof = false;
Gildas Bazin's avatar
Gildas Bazin committed
810 811 812 813 814 815 816
    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;
817
}
Gildas Bazin's avatar
 
Gildas Bazin committed
818

Gildas Bazin's avatar
Gildas Bazin committed
819 820 821 822
/*****************************************************************************
 * CommonClose: close device
 *****************************************************************************/
static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
823
{
Clément Stenac's avatar
Clément Stenac committed