dshow.cpp 75.1 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 35
 *****************************************************************************/

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

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/vout.h>

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

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

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
69
/*****************************************************************************
70
 * Module descriptor
Gildas Bazin's avatar
 
Gildas Bazin committed
71
 *****************************************************************************/
72 73 74 75
static 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") };
76 77 78
static int  pi_tuner_input[] = { 0, 1, 2 };
static char *ppsz_tuner_input_text[] =
    {N_("Default"), N_("Cable"), N_("Antenna")};
79

Gildas Bazin's avatar
 
Gildas Bazin committed
80 81
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
82
    "Caching value for DirectShow streams. " \
Clément Stenac's avatar
Clément Stenac committed
83
    "This value should be set in millisecondss." )
84 85
#define VDEV_TEXT N_("Video device name")
#define VDEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
86
    "Name of the video device that will be used by the " \
87 88
    "DirectShow plugin. If you don't specify anything, the default device " \
    "will be used.")
Clément Stenac's avatar
Clément Stenac committed
89
/// \bug [String] size stuff should be on video !
90 91
#define ADEV_TEXT N_("Audio device name")
#define ADEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
92
    "Name of the audio device that will be used by the " \
93
    "DirectShow plugin. If you don't specify anything, the default device " \
94
    "will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>")
95 96
#define SIZE_TEXT N_("Video size")
#define SIZE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
97
    "Size of the video that will be displayed by the " \
98 99 100 101 102
    "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 " \
103
    "(eg. I420 (default), RV24, etc.)")
104 105 106
#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
107
    "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
108
#define CONFIG_TEXT N_("Device properties")
Gildas Bazin's avatar
 
Gildas Bazin committed
109
#define CONFIG_LONGTEXT N_( \
110 111
    "Show the properties dialog of the selected device before starting the " \
    "stream.")
112 113 114
#define TUNER_TEXT N_("Tuner properties")
#define TUNER_LONGTEXT N_( \
    "Show the tuner properties [channel selection] page." )
115 116
#define CHANNEL_TEXT N_("Tuner TV Channel")
#define CHANNEL_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
117
    "Set the TV channel the tuner will set to " \
118 119 120
    "(0 means default)." )
#define COUNTRY_TEXT N_("Tuner country code")
#define COUNTRY_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
121
    "Set the tuner country code that establishes the current " \
122 123 124
    "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
125
    "Select the tuner input type (Cable/Antenna)." )
126 127
#define VIDEO_IN_TEXT N_("Video input pin")
#define VIDEO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
128 129 130 131
  "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.")
132 133
#define AUDIO_IN_TEXT N_("Audio input pin")
#define AUDIO_IN_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
134
  "Select the audio input source. See the \"video input\" option." )
135 136
#define VIDEO_OUT_TEXT N_("Video output pin")
#define VIDEO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
137
  "Select the video output type. See the \"video input\" option." )
138 139
#define AUDIO_OUT_TEXT N_("Audio output pin")
#define AUDIO_OUT_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
140
  "Select the audio output type. See the \"video input\" option." )
Gildas Bazin's avatar
 
Gildas Bazin committed
141

Gildas Bazin's avatar
Gildas Bazin committed
142 143 144
static int  CommonOpen ( vlc_object_t *, access_sys_t *, vlc_bool_t );
static void CommonClose( vlc_object_t *, access_sys_t * );

145 146 147 148 149 150
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
151
vlc_module_begin();
152
    set_shortname( _("DirectShow") );
Gildas Bazin's avatar
 
Gildas Bazin committed
153
    set_description( _("DirectShow input") );
Clément Stenac's avatar
Clément Stenac committed
154 155
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACCESS );
156
    add_integer( "dshow-caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
Gildas Bazin's avatar
 
Gildas Bazin committed
157
                 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
158

159
    add_string( "dshow-vdev", NULL, NULL, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE);
160
        change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback );
161 162
        change_action_add( FindDevicesCallback, N_("Refresh list") );
        change_action_add( ConfigDevicesCallback, N_("Configure") );
163

164
    add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE);
165
        change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback );
166 167
        change_action_add( FindDevicesCallback, N_("Refresh list") );
        change_action_add( ConfigDevicesCallback, N_("Configure") );
168

169
    add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE);
170

171 172
    add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
                VLC_TRUE );
Gildas Bazin's avatar
 
Gildas Bazin committed
173

174 175 176
    add_float( "dshow-fps", 0.0f, NULL, FPS_TEXT, FPS_LONGTEXT,
                VLC_TRUE );

Gildas Bazin's avatar
 
Gildas Bazin committed
177
    add_bool( "dshow-config", VLC_FALSE, NULL, CONFIG_TEXT, CONFIG_LONGTEXT,
178
              VLC_TRUE );
Gildas Bazin's avatar
 
Gildas Bazin committed
179

180
    add_bool( "dshow-tuner", VLC_FALSE, NULL, TUNER_TEXT, TUNER_LONGTEXT,
181
              VLC_TRUE );
182

183 184 185 186 187 188 189 190 191 192
    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 );

193
    add_integer( "dshow-video-input",  -1, NULL, VIDEO_IN_TEXT,
194
                 VIDEO_IN_LONGTEXT, VLC_TRUE );
195 196

    add_integer( "dshow-audio-input",  -1, NULL, AUDIO_IN_TEXT,
197
                 AUDIO_IN_LONGTEXT, VLC_TRUE );
198 199

    add_integer( "dshow-video-output", -1, NULL, VIDEO_OUT_TEXT,
200
                 VIDEO_OUT_LONGTEXT, VLC_TRUE );
201 202

    add_integer( "dshow-audio-output", -1, NULL, AUDIO_OUT_TEXT,
203
                 AUDIO_OUT_LONGTEXT, VLC_TRUE );
204

Gildas Bazin's avatar
 
Gildas Bazin committed
205
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
206 207
    set_capability( "access_demux", 0 );
    set_callbacks( DemuxOpen, DemuxClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
208 209

    add_submodule();
Gildas Bazin's avatar
Gildas Bazin committed
210
    set_description( _("DirectShow input") );
Gildas Bazin's avatar
 
Gildas Bazin committed
211
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
212 213
    set_capability( "access2", 0 );
    set_callbacks( AccessOpen, AccessClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
214 215 216

vlc_module_end();

Gildas Bazin's avatar
Gildas Bazin committed
217
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
218
 * DirectShow elementary stream descriptor
Gildas Bazin's avatar
Gildas Bazin committed
219
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233
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
234 235 236
    int             i_fourcc;
    es_out_id_t     *p_es;

237
    vlc_bool_t      b_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
238 239
} dshow_stream_t;

Gildas Bazin's avatar
Gildas Bazin committed
240
/*****************************************************************************
241
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
242
 *****************************************************************************/
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
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
297
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
298
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
299
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
300 301
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
302
{
303
    vlc_value_t  val;
Gildas Bazin's avatar
Gildas Bazin committed
304
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
305

306
    /* Get/parse options and open device(s) */
Gildas Bazin's avatar
 
Gildas Bazin committed
307
    string vdevname, adevname;
308
    int i_width = 0, i_height = 0, i_chroma = 0;
Gildas Bazin's avatar
Gildas Bazin committed
309
    vlc_bool_t b_audio = VLC_TRUE;
Gildas Bazin's avatar
 
Gildas Bazin committed
310

311 312
    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
313 314
    var_Create( p_this, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-vdev", &val );
315 316
    if( val.psz_string ) vdevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
317

Gildas Bazin's avatar
Gildas Bazin committed
318 319
    var_Create( p_this, "dshow-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-adev", &val );
320 321 322
    if( val.psz_string ) adevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );

Gildas Bazin's avatar
Gildas Bazin committed
323 324
    static struct {char *psz_size; int  i_width; int  i_height;} size_table[] =
    { { "subqcif", 128, 96 }, { "qsif", 160, 120 }, { "qcif", 176, 144 },
325
      { "sif", 320, 240 }, { "cif", 352, 288 }, { "d1", 640, 480 },
Gildas Bazin's avatar
Gildas Bazin committed
326 327 328 329 330
      { 0, 0, 0 },
    };

    var_Create( p_this, "dshow-size", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-size", &val );
331
    if( val.psz_string && *val.psz_string )
Gildas Bazin's avatar
 
Gildas Bazin committed
332
    {
Gildas Bazin's avatar
Gildas Bazin committed
333
        for( i = 0; size_table[i].psz_size; i++ )
334
        {
Gildas Bazin's avatar
Gildas Bazin committed
335 336 337 338 339 340
            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;
            }
341
        }
Gildas Bazin's avatar
Gildas Bazin committed
342
        if( !size_table[i].psz_size ) /* Try to parse "WidthxHeight" */
343 344 345 346
        {
            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
347
            {
348
                i_height = strtol( psz_parser + 1, &psz_parser, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
349
            }
Clément Stenac's avatar
Clément Stenac committed
350
            msg_Dbg( p_this, "width x height %dx%d", i_width, i_height );
Gildas Bazin's avatar
 
Gildas Bazin committed
351 352
        }
    }
353
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
354

355
    p_sys->b_chroma = VLC_FALSE;
Gildas Bazin's avatar
Gildas Bazin committed
356 357
    var_Create( p_this, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-chroma", &val );
358 359 360 361
    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] );
362
        p_sys->b_chroma = VLC_TRUE;
363 364
    }
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
365

366
    var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
367 368 369 370 371 372 373
    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 );

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

376 377 378 379 380
    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
381
    /* Initialize OLE/COM */
382
    CoInitialize( 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
383

Gildas Bazin's avatar
 
Gildas Bazin committed
384 385
    /* Initialize some data */
    p_sys->i_streams = 0;
386
    p_sys->pp_streams = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
387 388 389
    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
390

391 392 393
    p_sys->p_graph = NULL;
    p_sys->p_capture_graph_builder2 = NULL;
    p_sys->p_control = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
394

395 396 397
    vlc_mutex_init( p_this, &p_sys->lock );
    vlc_cond_init( p_this, &p_sys->wait );

398 399
    /* Build directshow graph */
    CreateDirectShowGraph( p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
400

Gildas Bazin's avatar
Gildas Bazin committed
401
    if( OpenDevice( p_this, p_sys, vdevname, 0 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
402
    {
Gildas Bazin's avatar
Gildas Bazin committed
403
        msg_Err( p_this, "can't open video");
Gildas Bazin's avatar
 
Gildas Bazin committed
404
    }
Gildas Bazin's avatar
Gildas Bazin committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
    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;
421 422 423 424

                if( b_access_demux )
                {
                    /* Let the access (only) take care of that */
425
                    return VLC_EGENERIC;
426
                }
Gildas Bazin's avatar
Gildas Bazin committed
427 428
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
429

430 431 432 433 434 435 436 437 438
        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;
            }
439 440 441 442 443 444 445 446 447

            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 );
            }
448
        }
Gildas Bazin's avatar
Gildas Bazin committed
449 450 451
    }

    if( b_audio && OpenDevice( p_this, p_sys, adevname, 1 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
452
    {
Gildas Bazin's avatar
Gildas Bazin committed
453
        msg_Err( p_this, "can't open audio");
Gildas Bazin's avatar
 
Gildas Bazin committed
454
    }
Gildas Bazin's avatar
Gildas Bazin committed
455

456
    for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
Gildas Bazin's avatar
 
Gildas Bazin committed
457
    {
458 459 460 461 462 463 464 465 466 467 468 469 470
            var_Get( p_this, "dshow-video-input", &val );
            if( val.i_int > 0 )
                    p_sys->crossbar_routes[i].VideoInputIndex=val.i_int;
            var_Get( p_this, "dshow-video-output", &val );
            if( val.i_int > 0 )
                    p_sys->crossbar_routes[i].VideoOutputIndex=val.i_int;
            var_Get( p_this, "dshow-audio-input", &val );
            if( val.i_int > 0 )
                    p_sys->crossbar_routes[i].AudioInputIndex=val.i_int;
            var_Get( p_this, "dshow-audio-output", &val );
            if( val.i_int > 0 )
                    p_sys->crossbar_routes[i].AudioOutputIndex=val.i_int;

471 472 473 474 475
        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
476

477 478
        if( SUCCEEDED(pXbar->Route(VideoOutputIndex, VideoInputIndex)) )
        {
Clément Stenac's avatar
Clément Stenac committed
479 480
            msg_Dbg( p_this, "crossbar at depth %d, routed video "
                     "output %ld to video input %ld", i, VideoOutputIndex,
481
                     VideoInputIndex );
Gildas Bazin's avatar
 
Gildas Bazin committed
482

483 484 485 486 487
            if( AudioOutputIndex != -1 && AudioInputIndex != -1 )
            {
                if( SUCCEEDED( pXbar->Route(AudioOutputIndex,
                                            AudioInputIndex)) )
                {
Clément Stenac's avatar
Clément Stenac committed
488 489
                    msg_Dbg(p_this, "crossbar at depth %d, routed audio "
                            "output %ld to audio input %ld", i,
490 491 492 493 494 495
                            AudioOutputIndex, AudioInputIndex );
                }
            }
        }
    }

496 497 498 499
    /*
    ** Show properties pages from other filters in graph
    */
    var_Get( p_this, "dshow-config", &val );
500
    if( val.b_bool )
501 502 503 504 505
    {
        for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
        {
            IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
            IBaseFilter *p_XF;
506 507 508

            if( SUCCEEDED( pXbar->QueryInterface( IID_IBaseFilter,
                                                  (void **)&p_XF ) ) )
509 510 511 512
            {
                ShowPropertyPage( p_XF );
                p_XF->Release();
            }
513
        }
514 515
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
516 517
    /* Initialize some data */
    p_sys->i_current_stream = 0;
518

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

Gildas Bazin's avatar
 
Gildas Bazin committed
521 522 523 524
    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
525
 * DemuxOpen: open direct show device as an access_demux module
Gildas Bazin's avatar
 
Gildas Bazin committed
526
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
527
static int DemuxOpen( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
528
{
Gildas Bazin's avatar
Gildas Bazin committed
529 530 531
    demux_t      *p_demux = (demux_t *)p_this;
    access_sys_t *p_sys;
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
532

Gildas Bazin's avatar
Gildas Bazin committed
533 534 535
    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
536

Gildas Bazin's avatar
Gildas Bazin committed
537 538 539 540 541
    if( CommonOpen( p_this, p_sys, VLC_TRUE ) != VLC_SUCCESS )
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
542

Gildas Bazin's avatar
Gildas Bazin committed
543 544 545
    /* Everything is ready. Let's rock baby */
    msg_Dbg( p_this, "Playing...");
    p_sys->p_control->Run();
546

Gildas Bazin's avatar
Gildas Bazin committed
547 548 549 550 551 552 553
    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++ )
554
    {
Gildas Bazin's avatar
Gildas Bazin committed
555 556
        dshow_stream_t *p_stream = p_sys->pp_streams[i];
        es_format_t fmt;
557

Gildas Bazin's avatar
Gildas Bazin committed
558 559 560
        if( p_stream->mt.majortype == MEDIATYPE_Video )
        {
            es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
561

Gildas Bazin's avatar
Gildas Bazin committed
562 563 564
            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;
565

Gildas Bazin's avatar
Gildas Bazin committed
566 567 568 569 570
            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);
            }
571

Gildas Bazin's avatar
Gildas Bazin committed
572 573 574 575
            /* Setup rgb mask for RGB formats */
            if( p_stream->i_fourcc == VLC_FOURCC('R','V','2','4') )
            {
                /* This is in BGR format */
576 577 578
                fmt.video.i_bmask = 0x00ff0000;
                fmt.video.i_gmask = 0x0000ff00;
                fmt.video.i_rmask = 0x000000ff;
Gildas Bazin's avatar
Gildas Bazin committed
579
            }
580 581 582 583 584 585 586

            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
587 588 589 590
        }
        else if( p_stream->mt.majortype == MEDIATYPE_Audio )
        {
            es_format_Init( &fmt, AUDIO_ES, p_stream->i_fourcc );
591

Gildas Bazin's avatar
Gildas Bazin committed
592 593 594 595 596 597 598 599 600 601
            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 );
602
    }
Gildas Bazin's avatar
Gildas Bazin committed
603

604
    return VLC_SUCCESS;
605 606
}

Gildas Bazin's avatar
Gildas Bazin committed
607 608 609 610
/*****************************************************************************
 * AccessOpen: open direct show device as an access module
 *****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
611
{
Gildas Bazin's avatar
Gildas Bazin committed
612 613
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;
614

Gildas Bazin's avatar
Gildas Bazin committed
615 616
    p_access->p_sys = p_sys = (access_sys_t *)malloc( sizeof( access_sys_t ) );
    memset( p_sys, 0, sizeof( access_sys_t ) );
617

618
    if( CommonOpen( p_this, p_sys, VLC_FALSE ) != VLC_SUCCESS )
Gildas Bazin's avatar
Gildas Bazin committed
619 620 621 622
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
623

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

Gildas Bazin's avatar
Gildas Bazin committed
626 627
    /* Check if we need to force demuxers */
    if( !p_access->psz_demux || !*p_access->psz_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
628
    {
Gildas Bazin's avatar
Gildas Bazin committed
629 630 631
        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') )
632
        {
Gildas Bazin's avatar
Gildas Bazin committed
633 634 635 636 637
            p_access->psz_demux = strdup( "rawdv" );
        }
        else if( p_stream->i_fourcc == VLC_FOURCC('m','p','2','v') )
        {
            p_access->psz_demux = "mpgv";
638
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
639
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
640

Gildas Bazin's avatar
Gildas Bazin committed
641
    /* Setup Access */
642 643
    p_access->pf_read = NULL;
    p_access->pf_block = ReadCompressed;
Gildas Bazin's avatar
Gildas Bazin committed
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
    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;
659
}
Gildas Bazin's avatar
 
Gildas Bazin committed
660

Gildas Bazin's avatar
Gildas Bazin committed
661 662 663 664
/*****************************************************************************
 * CommonClose: close device
 *****************************************************************************/
static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
665
{
Clément Stenac's avatar
Clément Stenac committed
666
    msg_Dbg( p_this, "releasing DirectShow");
667

Gildas Bazin's avatar
Gildas Bazin committed
668
    DeleteDirectShowGraph( p_sys );
669

Gildas Bazin's avatar
Gildas Bazin committed
670 671
    /* Uninitialize OLE/COM */
    CoUninitialize();
672

673 674
    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
675 676 677

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

Gildas Bazin's avatar
Gildas Bazin committed
679
    free( p_sys );
680 681
}

Gildas Bazin's avatar
Gildas Bazin committed
682 683 684 685
/*****************************************************************************
 * AccessClose: close device
 *****************************************************************************/
static void AccessClose( vlc_object_t *p_this )
686
{
Gildas Bazin's avatar
Gildas Bazin committed
687 688
    access_t     *p_access = (access_t *)p_this;
    access_sys_t *p_sys    = p_access->p_sys;
689

Gildas Bazin's avatar
Gildas Bazin committed
690 691
    /* Stop capturing stuff */
    p_sys->p_control->Stop();
692

Gildas Bazin's avatar
Gildas Bazin committed
693 694
    CommonClose( p_this, p_sys );
}
695

Gildas Bazin's avatar
Gildas Bazin committed
696 697 698 699 700 701 702
/*****************************************************************************
 * 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;
703

Gildas Bazin's avatar
Gildas Bazin committed
704 705
    /* Stop capturing stuff */
    p_sys->p_control->Stop();
706

Gildas Bazin's avatar
Gildas Bazin committed
707
    CommonClose( p_this, p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
708 709 710 711 712
}

/****************************************************************************
 * ConnectFilters
 ****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
713 714
static bool ConnectFilters( vlc_object_t *p_this, access_sys_t *p_sys,
                            IBaseFilter *p_filter,
715
                            CaptureFilter *p_capture_filter )
Gildas Bazin's avatar
 
Gildas Bazin committed
716
{
717
    CapturePin *p_input_pin = p_capture_filter->CustomGetPin();
Gildas Bazin's avatar
 
Gildas Bazin committed
718

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

721
    if( p_sys->p_capture_graph_builder2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
722
    {
723
        if( FAILED(p_sys->p_capture_graph_builder2->
Gildas Bazin's avatar
Gildas Bazin committed
724 725
                RenderStream( &PIN_CATEGORY_CAPTURE, &mediaType.majortype,
                              p_filter, 0, (IBaseFilter *)p_capture_filter )) )
726 727 728
        {
            return false;
        }
729

730 731 732
        // Sort out all the possible video inputs
        // The class needs to be given the capture filters ANALOGVIDEO input pin
        IEnumPins *pins = 0;
733 734
        if( ( mediaType.majortype == MEDIATYPE_Video ||
              mediaType.majortype == MEDIATYPE_Stream ) &&
735
            SUCCEEDED(p_filter->EnumPins(&pins)) )
Gildas Bazin's avatar
 
Gildas Bazin committed
736
        {
737 738 739 740 741 742 743 744
            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
745
            while( !Found && ( S_OK == pins->Next(1, &pP, &n) ) )
746
            {
Gildas Bazin's avatar
Gildas Bazin committed
747
                if( S_OK == pP->QueryPinInfo(&pinInfo) )
748
                {
Gildas Bazin's avatar
Gildas Bazin committed
749 750 751 752
                    // is this pin an ANALOGVIDEOIN input pin?
                    if( pinInfo.dir == PINDIR_INPUT &&
                        pP->QueryInterface( IID_IKsPropertySet,
                                            (void **)&pKs ) == S_OK )
753
                    {
Gildas Bazin's avatar
Gildas Bazin committed
754 755 756
                        if( pKs->Get( AMPROPSETID_Pin,
                                      AMPROPERTY_PIN_CATEGORY, NULL, 0,
                                      &guid, sizeof(GUID), &dw ) == S_OK )
757
                        {
Gildas Bazin's avatar
Gildas Bazin committed
758
                            if( guid == PIN_CATEGORY_ANALOGVIDEOIN )
759
                            {
Gildas Bazin's avatar
Gildas Bazin committed
760
                                // recursively search crossbar routes
761
                                FindCrossbarRoutes( p_this, p_sys, pP, 0 );
Gildas Bazin's avatar
Gildas Bazin committed
762 763
                                // found it
                                Found = TRUE;
764 765
                            }
                        }
Gildas Bazin's avatar
Gildas Bazin committed
766
                        pKs->Release();
767 768 769 770 771 772
                    }
                    pinInfo.pFilter->Release();
                }
                pP->Release();
            }
            pins->Release();
Gildas Bazin's avatar
 
Gildas Bazin committed
773
        }
774
        return true;
Gildas Bazin's avatar
 
Gildas Bazin committed
775
    }
776 777 778 779
    else
    {
        IEnumPins *p_enumpins;
        IPin *p_pin;
Gildas Bazin's avatar
 
Gildas Bazin committed
780

781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
        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
802 803
}

804
/*
Gildas Bazin's avatar
Gildas Bazin committed
805 806 807
 * get fourcc priority from arbritary preference, the higher the better
 */
static int GetFourCCPriority( int i_fourcc )
808 809 810
{
    switch( i_fourcc )
    {
Gildas Bazin's avatar
Gildas Bazin committed
811 812 813 814 815 816 817 818 819 820 821 822
    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;
823
    }
Gildas Bazin's avatar
Gildas Bazin committed
824

825 826 827 828 829
    return 0;
}

#define MAX_MEDIA_TYPES 32

Gildas Bazin's avatar
Gildas Bazin committed
830 831
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
832
{
833 834 835
    /* See if device is already opened */
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
Gildas Bazin's avatar
Gildas Bazin committed
836 837
        if( devicename.size() &&
            p_sys->pp_streams[i]->devicename == devicename )
838 839 840 841 842 843
        {
            /* Already opened */
            return VLC_SUCCESS;
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
844 845
    list<string> list_devices;

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

849 850 851
    if( !list_devices.size() )
        return VLC_EGENERIC;

Gildas Bazin's avatar
 
Gildas Bazin committed
852 853
    list<string>::iterator iter;
    for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
Gildas Bazin's avatar
Gildas Bazin committed
854
        msg_Dbg( p_this, "found device: %s", iter->c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
855 856 857 858 859 860 861 862

    /* 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
863 864
    // a capture/preview device, such as a desktop USB video camera.
    IBaseFilter *p_device_filter =
Gildas Bazin's avatar
Gildas Bazin committed
865
        FindCaptureDevice( p_this, &devicename, 0, b_audio );
Gildas Bazin's avatar
 
Gildas Bazin committed
866
    if( p_device_filter )
Gildas Bazin's avatar
Gildas Bazin committed
867
        msg_Dbg( p_this, "using device: %s", devicename.c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
868 869
    else
    {
Gildas Bazin's avatar
Gildas Bazin committed
870
        msg_Err( p_this, "can't use device: %s, unsupported device type",
871
                 devicename.c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
872 873
        return VLC_EGENERIC;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
874

875 876 877
    // Retreive acceptable media types supported by device
    AM_MEDIA_TYPE media_types[MAX_MEDIA_TYPES];
    size_t media_count =
878
        EnumDeviceCaps( p_this, p_device_filter, b_audio ? 0 : p_sys->i_chroma,
879 880 881
                        p_sys->i_width, p_sys->i_height,
                        0, 0, 0, media_types, MAX_MEDIA_TYPES );

882
    AM_MEDIA_TYPE *mt = NULL;
Gildas Bazin's avatar
Gildas Bazin committed
883

884 885
    if( media_count > 0 )
    {
886
        mt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * media_count);
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906

        // Order and copy returned media types according to arbitrary
        // fourcc priority
        for( size_t c = 0; c < media_count; c++ )
        {
            int slot_priority =
                GetFourCCPriority(GetFourCCFromMediaType(media_types[c]));
            size_t slot_copy = c;
            for( size_t d = c+1; d < media_count; d++ )
            {
                int priority =
                    GetFourCCPriority(GetFourCCFromMediaType(media_types[d]));
                if( priority > slot_priority )
                {
                    slot_priority = priority;
                    slot_copy = d;
                }
            }
            if( slot_copy != c )
            {
907
                mt[c] = media_types[slot_copy];
908 909 910 911
                media_types[slot_copy] = media_types[c];
            }
            else
            {
912
                mt[c] = media_types[c];
913 914
            }
        }
915 916 917 918 919 920
    }
    else {
        /* capture device */
        msg_Err( p_this, "capture device '%s' does not support required parameters !", devicename.c_str() );
        p_device_filter->Release();
        return VLC_EGENERIC;
921 922
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
923
    /* Create and add our capture filter */
924
    CaptureFilter *p_capture_filter =
925
        new CaptureFilter( p_this, p_sys, mt, media_count );
Gildas Bazin's avatar
 
Gildas Bazin committed
926
    p_sys->p_graph->AddFilter( p_capture_filter, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
927 928 929

    /* Add the device filter to the graph (seems necessary with VfW before
     * accessing pin attributes). */
Gildas Bazin's avatar