dshow.cpp 71.6 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1
/*****************************************************************************
2
 * dshow.cpp : DirectShow access module for vlc
Gildas Bazin's avatar
 
Gildas Bazin committed
3
 *****************************************************************************
4
 * Copyright (C) 2002, 2003 the VideoLAN team
5
 * $Id$
Gildas Bazin's avatar
 
Gildas Bazin committed
6
 *
7
 * Author: Gildas Bazin <gbazin@videolan.org>
Gildas Bazin's avatar
 
Gildas Bazin committed
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Gildas Bazin's avatar
 
Gildas Bazin committed
22 23 24 25 26 27 28 29 30 31 32 33 34
 *****************************************************************************/

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

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

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

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

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
79 80
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
81
    "Allows you to modify the default caching value for DirectShow streams. " \
Rocky Bernstein's avatar
Rocky Bernstein committed
82
    "This value should be set in milliseconds units." )
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
#define VDEV_TEXT N_("Video device name")
#define VDEV_LONGTEXT N_( \
    "You can specify the name of the video device that will be used by the " \
    "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_( \
    "You can specify the name of the audio device that will be used by the " \
    "DirectShow plugin. If you don't specify anything, the default device " \
    "will be used.")
#define SIZE_TEXT N_("Video size")
#define SIZE_LONGTEXT N_( \
    "You can specify the size of the video that will be displayed by the " \
    "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 " \
101
    "(eg. I420 (default), RV24, etc.)")
102 103 104 105
#define FPS_TEXT N_("Video input frame rate")
#define FPS_LONGTEXT N_( \
    "Force the DirectShow video input to use a specific frame rate" \
    "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
106
#define CONFIG_TEXT N_("Device properties")
Gildas Bazin's avatar
 
Gildas Bazin committed
107
#define CONFIG_LONGTEXT N_( \
108 109
    "Show the properties dialog of the selected device before starting the " \
    "stream.")
110 111 112
#define TUNER_TEXT N_("Tuner properties")
#define TUNER_LONGTEXT N_( \
    "Show the tuner properties [channel selection] page." )
113 114 115 116 117 118 119 120 121 122 123
#define CHANNEL_TEXT N_("Tuner TV Channel")
#define CHANNEL_LONGTEXT N_( \
    "Allows you to set the TV channel the tuner will set to " \
    "(0 means default)." )
#define COUNTRY_TEXT N_("Tuner country code")
#define COUNTRY_LONGTEXT N_( \
    "Allows you to set the tuner country code that establishes the current " \
    "channel-to-frequency mapping (0 means default)." )
#define TUNER_INPUT_TEXT N_("Tuner input type")
#define TUNER_INPUT_LONGTEXT N_( \
    "Allows you to select the tuner input type (Cable/Antenna)." )
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
#define VIDEO_IN_TEXT N_("Video input pin")
#define VIDEO_IN_LONGTEXT N_( \
    "Allows you to 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.")
#define AUDIO_IN_TEXT N_("Audio input pin")
#define AUDIO_IN_LONGTEXT N_( \
    "Allows you to select the audio input source. See the \"video input\" option." )
#define VIDEO_OUT_TEXT N_("Video output pin")
#define VIDEO_OUT_LONGTEXT N_( \
    "Allows you to select the video output type. See the \"video input\" option." )
#define AUDIO_OUT_TEXT N_("Audio output pin")
#define AUDIO_OUT_LONGTEXT N_( \
    "Allows you to select the audio output type. See the \"video input\" option." )
Gildas Bazin's avatar
 
Gildas Bazin committed
139

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

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

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

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

167
    add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE);
168

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

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

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

178
    add_bool( "dshow-tuner", VLC_FALSE, NULL, TUNER_TEXT, TUNER_LONGTEXT,
179
              VLC_TRUE );
180

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

191 192 193 194 195 196 197 198 199 200 201 202
    add_integer( "dshow-video-input",  -1, NULL, VIDEO_IN_TEXT,
		VIDEO_IN_LONGTEXT, VLC_TRUE );

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

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

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

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

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

vlc_module_end();

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

235
    vlc_bool_t      b_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
236 237
} dshow_stream_t;

Gildas Bazin's avatar
Gildas Bazin committed
238
/*****************************************************************************
239
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
240
 *****************************************************************************/
241 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
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
295
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
296
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
297
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
298 299
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
300
{
301
    vlc_value_t  val;
Gildas Bazin's avatar
Gildas Bazin committed
302
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
303

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
321 322 323 324 325 326 327 328
    static struct {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 }, { "cif", 640, 480 },
      { 0, 0, 0 },
    };

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

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

364
    var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
365 366 367 368 369 370 371
    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
372
    var_Create( p_this, "dshow-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
373

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

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

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

393 394 395
    vlc_mutex_init( p_this, &p_sys->lock );
    vlc_cond_init( p_this, &p_sys->wait );

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

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

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

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

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

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

454
    for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
Gildas Bazin's avatar
 
Gildas Bazin committed
455
    {
456 457 458 459 460 461 462 463 464 465 466 467 468
            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;

469 470 471 472 473
        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
474

475 476
        if( SUCCEEDED(pXbar->Route(VideoOutputIndex, VideoInputIndex)) )
        {
Gildas Bazin's avatar
Gildas Bazin committed
477
            msg_Dbg( p_this, "Crossbar at depth %d, Routed video "
478
                     "ouput %ld to video input %ld", i, VideoOutputIndex,
479
                     VideoInputIndex );
Gildas Bazin's avatar
 
Gildas Bazin committed
480

481 482 483 484 485
            if( AudioOutputIndex != -1 && AudioInputIndex != -1 )
            {
                if( SUCCEEDED( pXbar->Route(AudioOutputIndex,
                                            AudioInputIndex)) )
                {
Gildas Bazin's avatar
Gildas Bazin committed
486
                    msg_Dbg(p_this, "Crossbar at depth %d, Routed audio "
487
                            "ouput %ld to audio input %ld", i,
488 489 490 491 492 493
                            AudioOutputIndex, AudioInputIndex );
                }
            }
        }
    }

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

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
519 520 521 522
    return VLC_SUCCESS;
}

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

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

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

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

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

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

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

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

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

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

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

602
    return VLC_SUCCESS;
603 604
}

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

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

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

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
659 660 661 662
/*****************************************************************************
 * CommonClose: close device
 *****************************************************************************/
static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
663
{
Gildas Bazin's avatar
Gildas Bazin committed
664
    msg_Dbg( p_this, "Releasing DirectShow");
665

Gildas Bazin's avatar
Gildas Bazin committed
666
    DeleteDirectShowGraph( p_sys );
667

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

671 672
    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
673 674 675

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

Gildas Bazin's avatar
Gildas Bazin committed
677
    free( p_sys );
678 679
}

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

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

Gildas Bazin's avatar
Gildas Bazin committed
691 692
    CommonClose( p_this, p_sys );
}
693

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

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

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

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

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

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

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

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

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

823 824 825 826 827
    return 0;
}

#define MAX_MEDIA_TYPES 32

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

Gildas Bazin's avatar
 
Gildas Bazin committed
842 843
    list<string> list_devices;

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

847 848 849
    if( !list_devices.size() )
        return VLC_EGENERIC;

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

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

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

880
    AM_MEDIA_TYPE *mt = NULL;
Gildas Bazin's avatar
Gildas Bazin committed
881

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

        // 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 )
            {
905
                mt[c] = media_types[slot_copy];
906 907 908 909
                media_types[slot_copy] = media_types[c];
            }
            else
            {
910
                mt[c] = media_types[c];
911 912
            }
        }
913 914 915 916 917 918
    }
    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;
919 920
    }

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

    /* Add the device filter to the graph (seems necessary with VfW before
     * accessing pin attributes). */
Gildas Bazin's avatar
 
Gildas Bazin committed
928
    p_sys->p_graph->AddFilter( p_device_filter, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
929

Gildas Bazin's avatar
 
Gildas Bazin committed
930
    /* Attempt to connect one of this device's capture output pins */
Gildas Bazin's avatar
Gildas Bazin committed
931 932
    msg_Dbg( p_this, "connecting filters" );
    if( ConnectFilters( p_this, p_sys, p_device_filter, p_capture_filter ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
933 934
    {
        /* Success */
Gildas Bazin's avatar
Gildas Bazin committed
935
        msg_Dbg( p_this, "filters connected successfully !" );
936

Gildas Bazin's avatar
 
Gildas Bazin committed
937
        dshow_stream_t dshow_stream;
938
        dshow_stream.b_pts = VLC_FALSE;
Gildas Bazin's avatar
Gildas Bazin committed
939
        dshow_stream.p_es = 0;
940 941 942
        dshow_stream.mt =
            p_capture_filter->CustomGetPin()->CustomGetMediaType();

943 944
        /* Show Device properties. Done here so the VLC stream is setup with
         * the proper parameters. */
945
        vlc_value_t val;
Gildas Bazin's avatar
Gildas Bazin committed
946
        var_Get( p_this, "dshow-config", &val );
947
        if( val.b_bool )
948
        {
949 950
            ShowDeviceProperties( p_this, p_sys->p_capture_graph_builder2,
                                  p_device_filter, b_audio );
951
        }
952

953 954 955
        ConfigTuner( p_this, p_sys->p_capture_graph_builder2,
                     p_device_filter );

956
        var_Get( p_this, "dshow-tuner", &val );
957
        if( val.b_bool && dshow_stream.mt.majortype != MEDIATYPE_Stream )
958
        {
959
            /* FIXME: we do MEDIATYPE_Stream later so we don't do it twice. */
960 961 962 963
            ShowTunerProperties( p_this, p_sys->p_capture_graph_builder2,
                                 p_device_filter, b_audio );
        }