dshow.cpp 61.7 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
 *****************************************************************************
Rocky Bernstein's avatar
Rocky Bernstein committed
4
 * Copyright (C) 2002, 2003 VideoLAN
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 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * 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 102
    "(eg. I420 (default), RV24, etc.)")
#define CONFIG_TEXT N_("Device properties")
Gildas Bazin's avatar
 
Gildas Bazin committed
103
#define CONFIG_LONGTEXT N_( \
104 105
    "Show the properties dialog of the selected device before starting the " \
    "stream.")
106 107 108
#define TUNER_TEXT N_("Tuner properties")
#define TUNER_LONGTEXT N_( \
    "Show the tuner properties [channel selection] page." )
109 110 111 112 113 114 115 116 117 118 119
#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)." )
Gildas Bazin's avatar
 
Gildas Bazin committed
120

Gildas Bazin's avatar
Gildas Bazin committed
121 122 123
static int  CommonOpen ( vlc_object_t *, access_sys_t *, vlc_bool_t );
static void CommonClose( vlc_object_t *, access_sys_t * );

124 125 126 127 128 129
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
130
vlc_module_begin();
131
    set_shortname( _("DirectShow") );
Gildas Bazin's avatar
 
Gildas Bazin committed
132
    set_description( _("DirectShow input") );
Clément Stenac's avatar
Clément Stenac committed
133 134
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACCESS );
135
    add_integer( "dshow-caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
Gildas Bazin's avatar
 
Gildas Bazin committed
136
                 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
137

138
    add_string( "dshow-vdev", NULL, NULL, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE);
139
        change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback );
140 141
        change_action_add( FindDevicesCallback, N_("Refresh list") );
        change_action_add( ConfigDevicesCallback, N_("Configure") );
142

143
    add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE);
144
        change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback );
145 146
        change_action_add( FindDevicesCallback, N_("Refresh list") );
        change_action_add( ConfigDevicesCallback, N_("Configure") );
147

148
    add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE);
149

150 151
    add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
                VLC_TRUE );
Gildas Bazin's avatar
 
Gildas Bazin committed
152 153

    add_bool( "dshow-config", VLC_FALSE, NULL, CONFIG_TEXT, CONFIG_LONGTEXT,
154
              VLC_FALSE );
Gildas Bazin's avatar
 
Gildas Bazin committed
155

156 157 158
    add_bool( "dshow-tuner", VLC_FALSE, NULL, TUNER_TEXT, TUNER_LONGTEXT,
              VLC_FALSE );

159 160 161 162 163 164 165 166 167 168
    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 );

Gildas Bazin's avatar
 
Gildas Bazin committed
169
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
170 171
    set_capability( "access_demux", 0 );
    set_callbacks( DemuxOpen, DemuxClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
172 173

    add_submodule();
Gildas Bazin's avatar
Gildas Bazin committed
174
    set_description( _("DirectShow input") );
Gildas Bazin's avatar
 
Gildas Bazin committed
175
    add_shortcut( "dshow" );
Gildas Bazin's avatar
Gildas Bazin committed
176 177
    set_capability( "access2", 0 );
    set_callbacks( AccessOpen, AccessClose );
Gildas Bazin's avatar
 
Gildas Bazin committed
178 179 180

vlc_module_end();

Gildas Bazin's avatar
Gildas Bazin committed
181
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
182
 * DirectShow elementary stream descriptor
Gildas Bazin's avatar
Gildas Bazin committed
183
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197
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
198 199 200
    int             i_fourcc;
    es_out_id_t     *p_es;

201
    vlc_bool_t      b_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
202 203 204

} dshow_stream_t;

Gildas Bazin's avatar
Gildas Bazin committed
205
/*****************************************************************************
206
 * DirectShow utility functions
Gildas Bazin's avatar
Gildas Bazin committed
207
 *****************************************************************************/
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
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
262
/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
263
 * CommonOpen: open direct show device
Gildas Bazin's avatar
 
Gildas Bazin committed
264
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
265 266
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
267
{
268
    vlc_value_t  val;
Gildas Bazin's avatar
Gildas Bazin committed
269
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
270

271
    /* Get/parse options and open device(s) */
Gildas Bazin's avatar
 
Gildas Bazin committed
272
    string vdevname, adevname;
273
    int i_width = 0, i_height = 0, i_chroma = 0;
Gildas Bazin's avatar
Gildas Bazin committed
274
    vlc_bool_t b_audio = VLC_TRUE;
Gildas Bazin's avatar
 
Gildas Bazin committed
275

276 277
    var_Create( p_this, "dshow-config", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_this, "dshow-tuner", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
278

Gildas Bazin's avatar
Gildas Bazin committed
279 280
    var_Create( p_this, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-vdev", &val );
281 282
    if( val.psz_string ) vdevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
283

Gildas Bazin's avatar
Gildas Bazin committed
284 285
    var_Create( p_this, "dshow-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-adev", &val );
286 287 288
    if( val.psz_string ) adevname = string( val.psz_string );
    if( val.psz_string ) free( val.psz_string );

Gildas Bazin's avatar
Gildas Bazin committed
289 290 291 292 293 294 295 296
    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 );
297
    if( val.psz_string && *val.psz_string )
Gildas Bazin's avatar
 
Gildas Bazin committed
298
    {
Gildas Bazin's avatar
Gildas Bazin committed
299
        for( i = 0; size_table[i].psz_size; i++ )
300
        {
Gildas Bazin's avatar
Gildas Bazin committed
301 302 303 304 305 306
            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;
            }
307
        }
Gildas Bazin's avatar
Gildas Bazin committed
308
        if( !size_table[i].psz_size ) /* Try to parse "WidthxHeight" */
309 310 311 312
        {
            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
313
            {
314
                i_height = strtol( psz_parser + 1, &psz_parser, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
315
            }
Gildas Bazin's avatar
Gildas Bazin committed
316
            msg_Dbg( p_this, "Width x Height %dx%d", i_width, i_height );
Gildas Bazin's avatar
 
Gildas Bazin committed
317 318
        }
    }
319
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
320

Gildas Bazin's avatar
Gildas Bazin committed
321 322
    var_Create( p_this, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_this, "dshow-chroma", &val );
323 324 325 326 327 328
    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] );
    }
    if( val.psz_string ) free( val.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
329

330 331 332 333 334 335 336
    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
337
    var_Create( p_this, "dshow-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
338 339

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

Gildas Bazin's avatar
 
Gildas Bazin committed
342 343
    /* Initialize some data */
    p_sys->i_streams = 0;
344
    p_sys->pp_streams = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
345 346 347
    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
348

349 350 351
    p_sys->p_graph = NULL;
    p_sys->p_capture_graph_builder2 = NULL;
    p_sys->p_control = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
352

353 354 355
    vlc_mutex_init( p_this, &p_sys->lock );
    vlc_cond_init( p_this, &p_sys->wait );

356 357
    /* Build directshow graph */
    CreateDirectShowGraph( p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
358

Gildas Bazin's avatar
Gildas Bazin committed
359
    if( OpenDevice( p_this, p_sys, vdevname, 0 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
360
    {
Gildas Bazin's avatar
Gildas Bazin committed
361
        msg_Err( p_this, "can't open video");
Gildas Bazin's avatar
 
Gildas Bazin committed
362
    }
Gildas Bazin's avatar
Gildas Bazin committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    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;
379 380 381 382

                if( b_access_demux )
                {
                    /* Let the access (only) take care of that */
383
                    return VLC_EGENERIC;
384
                }
Gildas Bazin's avatar
Gildas Bazin committed
385 386
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
387

388 389 390 391 392 393 394 395 396
        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;
            }
397 398 399 400 401 402 403 404 405

            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 );
            }
406
        }
Gildas Bazin's avatar
Gildas Bazin committed
407 408 409
    }

    if( b_audio && OpenDevice( p_this, p_sys, adevname, 1 ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
410
    {
Gildas Bazin's avatar
Gildas Bazin committed
411
        msg_Err( p_this, "can't open audio");
Gildas Bazin's avatar
 
Gildas Bazin committed
412
    }
Gildas Bazin's avatar
Gildas Bazin committed
413

414
    for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
Gildas Bazin's avatar
 
Gildas Bazin committed
415
    {
416 417 418 419 420
        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
421

422 423
        if( SUCCEEDED(pXbar->Route(VideoOutputIndex, VideoInputIndex)) )
        {
Gildas Bazin's avatar
Gildas Bazin committed
424
            msg_Dbg( p_this, "Crossbar at depth %d, Routed video "
425
                     "ouput %ld to video input %ld", i, VideoOutputIndex,
426
                     VideoInputIndex );
Gildas Bazin's avatar
 
Gildas Bazin committed
427

428 429 430 431 432
            if( AudioOutputIndex != -1 && AudioInputIndex != -1 )
            {
                if( SUCCEEDED( pXbar->Route(AudioOutputIndex,
                                            AudioInputIndex)) )
                {
Gildas Bazin's avatar
Gildas Bazin committed
433
                    msg_Dbg(p_this, "Crossbar at depth %d, Routed audio "
434
                            "ouput %ld to audio input %ld", i,
435 436 437 438 439 440
                            AudioOutputIndex, AudioInputIndex );
                }
            }
        }
    }

441 442 443 444
    /*
    ** Show properties pages from other filters in graph
    */
    var_Get( p_this, "dshow-config", &val );
445
    if( val.b_bool )
446 447 448 449 450
    {
        for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
        {
            IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
            IBaseFilter *p_XF;
451 452 453

            if( SUCCEEDED( pXbar->QueryInterface( IID_IBaseFilter,
                                                  (void **)&p_XF ) ) )
454 455 456 457
            {
                ShowPropertyPage( p_XF );
                p_XF->Release();
            }
458
        }
459 460
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
461 462
    /* Initialize some data */
    p_sys->i_current_stream = 0;
463

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

Gildas Bazin's avatar
 
Gildas Bazin committed
466 467 468 469
    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
Gildas Bazin committed
470
 * DemuxOpen: open direct show device as an access_demux module
Gildas Bazin's avatar
 
Gildas Bazin committed
471
 *****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
472
static int DemuxOpen( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
473
{
Gildas Bazin's avatar
Gildas Bazin committed
474 475 476
    demux_t      *p_demux = (demux_t *)p_this;
    access_sys_t *p_sys;
    int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
477

Gildas Bazin's avatar
Gildas Bazin committed
478 479 480
    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
481

Gildas Bazin's avatar
Gildas Bazin committed
482 483 484 485 486
    if( CommonOpen( p_this, p_sys, VLC_TRUE ) != VLC_SUCCESS )
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
487

Gildas Bazin's avatar
Gildas Bazin committed
488 489 490
    /* Everything is ready. Let's rock baby */
    msg_Dbg( p_this, "Playing...");
    p_sys->p_control->Run();
491

Gildas Bazin's avatar
Gildas Bazin committed
492 493 494 495 496 497 498
    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++ )
499
    {
Gildas Bazin's avatar
Gildas Bazin committed
500 501
        dshow_stream_t *p_stream = p_sys->pp_streams[i];
        es_format_t fmt;
502

Gildas Bazin's avatar
Gildas Bazin committed
503 504 505
        if( p_stream->mt.majortype == MEDIATYPE_Video )
        {
            es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
506

Gildas Bazin's avatar
Gildas Bazin committed
507 508 509
            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;
510

Gildas Bazin's avatar
Gildas Bazin committed
511 512 513 514 515
            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);
            }
516

Gildas Bazin's avatar
Gildas Bazin committed
517 518 519 520
            /* Setup rgb mask for RGB formats */
            if( p_stream->i_fourcc == VLC_FOURCC('R','V','2','4') )
            {
                /* This is in BGR format */
521 522 523
                fmt.video.i_bmask = 0x00ff0000;
                fmt.video.i_gmask = 0x0000ff00;
                fmt.video.i_rmask = 0x000000ff;
Gildas Bazin's avatar
Gildas Bazin committed
524 525 526 527 528
            }
        }
        else if( p_stream->mt.majortype == MEDIATYPE_Audio )
        {
            es_format_Init( &fmt, AUDIO_ES, p_stream->i_fourcc );
529

Gildas Bazin's avatar
Gildas Bazin committed
530 531 532 533 534 535 536 537 538 539
            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 );
540
    }
Gildas Bazin's avatar
Gildas Bazin committed
541

542
    return VLC_SUCCESS;
543 544
}

Gildas Bazin's avatar
Gildas Bazin committed
545 546 547 548
/*****************************************************************************
 * AccessOpen: open direct show device as an access module
 *****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
549
{
Gildas Bazin's avatar
Gildas Bazin committed
550 551
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;
552

Gildas Bazin's avatar
Gildas Bazin committed
553 554
    p_access->p_sys = p_sys = (access_sys_t *)malloc( sizeof( access_sys_t ) );
    memset( p_sys, 0, sizeof( access_sys_t ) );
555

556
    if( CommonOpen( p_this, p_sys, VLC_FALSE ) != VLC_SUCCESS )
Gildas Bazin's avatar
Gildas Bazin committed
557 558 559 560
    {
        CommonClose( p_this, p_sys );
        return VLC_EGENERIC;
    }
561

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

Gildas Bazin's avatar
Gildas Bazin committed
564 565
    /* Check if we need to force demuxers */
    if( !p_access->psz_demux || !*p_access->psz_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
566
    {
Gildas Bazin's avatar
Gildas Bazin committed
567 568 569
        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') )
570
        {
Gildas Bazin's avatar
Gildas Bazin committed
571 572 573 574 575
            p_access->psz_demux = strdup( "rawdv" );
        }
        else if( p_stream->i_fourcc == VLC_FOURCC('m','p','2','v') )
        {
            p_access->psz_demux = "mpgv";
576
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
577
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
578

Gildas Bazin's avatar
Gildas Bazin committed
579
    /* Setup Access */
580 581
    p_access->pf_read = NULL;
    p_access->pf_block = ReadCompressed;
Gildas Bazin's avatar
Gildas Bazin committed
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
    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;
597
}
Gildas Bazin's avatar
 
Gildas Bazin committed
598

Gildas Bazin's avatar
Gildas Bazin committed
599 600 601 602
/*****************************************************************************
 * CommonClose: close device
 *****************************************************************************/
static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
603
{
Gildas Bazin's avatar
Gildas Bazin committed
604
    msg_Dbg( p_this, "Releasing DirectShow");
605

Gildas Bazin's avatar
Gildas Bazin committed
606
    DeleteDirectShowGraph( p_sys );
607

Gildas Bazin's avatar
Gildas Bazin committed
608 609
    /* Uninitialize OLE/COM */
    CoUninitialize();
610

611 612
    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
613 614 615

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

Gildas Bazin's avatar
Gildas Bazin committed
617
    free( p_sys );
618 619
}

Gildas Bazin's avatar
Gildas Bazin committed
620 621 622 623
/*****************************************************************************
 * AccessClose: close device
 *****************************************************************************/
static void AccessClose( vlc_object_t *p_this )
624
{
Gildas Bazin's avatar
Gildas Bazin committed
625 626
    access_t     *p_access = (access_t *)p_this;
    access_sys_t *p_sys    = p_access->p_sys;
627

Gildas Bazin's avatar
Gildas Bazin committed
628 629
    /* Stop capturing stuff */
    p_sys->p_control->Stop();
630

Gildas Bazin's avatar
Gildas Bazin committed
631 632
    CommonClose( p_this, p_sys );
}
633

Gildas Bazin's avatar
Gildas Bazin committed
634 635 636 637 638 639 640
/*****************************************************************************
 * 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;
641

Gildas Bazin's avatar
Gildas Bazin committed
642 643
    /* Stop capturing stuff */
    p_sys->p_control->Stop();
644

Gildas Bazin's avatar
Gildas Bazin committed
645
    CommonClose( p_this, p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
646 647 648 649 650
}

/****************************************************************************
 * ConnectFilters
 ****************************************************************************/
Gildas Bazin's avatar
Gildas Bazin committed
651 652
static bool ConnectFilters( vlc_object_t *p_this, access_sys_t *p_sys,
                            IBaseFilter *p_filter,
653
                            CaptureFilter *p_capture_filter )
Gildas Bazin's avatar
 
Gildas Bazin committed
654
{
655
    CapturePin *p_input_pin = p_capture_filter->CustomGetPin();
Gildas Bazin's avatar
 
Gildas Bazin committed
656

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

659
    if( p_sys->p_capture_graph_builder2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
660
    {
661
        if( FAILED(p_sys->p_capture_graph_builder2->
Gildas Bazin's avatar
Gildas Bazin committed
662 663
                RenderStream( &PIN_CATEGORY_CAPTURE, &mediaType.majortype,
                              p_filter, 0, (IBaseFilter *)p_capture_filter )) )
664 665 666
        {
            return false;
        }
667

668 669 670
        // Sort out all the possible video inputs
        // The class needs to be given the capture filters ANALOGVIDEO input pin
        IEnumPins *pins = 0;
671 672
        if( ( mediaType.majortype == MEDIATYPE_Video ||
              mediaType.majortype == MEDIATYPE_Stream ) &&
673
            SUCCEEDED(p_filter->EnumPins(&pins)) )
Gildas Bazin's avatar
 
Gildas Bazin committed
674
        {
675 676 677 678 679 680 681 682
            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
683
            while( !Found && ( S_OK == pins->Next(1, &pP, &n) ) )
684
            {
Gildas Bazin's avatar
Gildas Bazin committed
685
                if( S_OK == pP->QueryPinInfo(&pinInfo) )
686
                {
Gildas Bazin's avatar
Gildas Bazin committed
687 688 689 690
                    // is this pin an ANALOGVIDEOIN input pin?
                    if( pinInfo.dir == PINDIR_INPUT &&
                        pP->QueryInterface( IID_IKsPropertySet,
                                            (void **)&pKs ) == S_OK )
691
                    {
Gildas Bazin's avatar
Gildas Bazin committed
692 693 694
                        if( pKs->Get( AMPROPSETID_Pin,
                                      AMPROPERTY_PIN_CATEGORY, NULL, 0,
                                      &guid, sizeof(GUID), &dw ) == S_OK )
695
                        {
Gildas Bazin's avatar
Gildas Bazin committed
696
                            if( guid == PIN_CATEGORY_ANALOGVIDEOIN )
697
                            {
Gildas Bazin's avatar
Gildas Bazin committed
698
                                // recursively search crossbar routes
699
                                FindCrossbarRoutes( p_this, p_sys, pP, 0 );
Gildas Bazin's avatar
Gildas Bazin committed
700 701
                                // found it
                                Found = TRUE;
702 703
                            }
                        }
Gildas Bazin's avatar
Gildas Bazin committed
704
                        pKs->Release();
705 706 707 708 709 710
                    }
                    pinInfo.pFilter->Release();
                }
                pP->Release();
            }
            pins->Release();
Gildas Bazin's avatar
 
Gildas Bazin committed
711
        }
712
        return true;
Gildas Bazin's avatar
 
Gildas Bazin committed
713
    }
714 715 716 717
    else
    {
        IEnumPins *p_enumpins;
        IPin *p_pin;
Gildas Bazin's avatar
 
Gildas Bazin committed
718

719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
        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
740 741
}

742
/*
Gildas Bazin's avatar
Gildas Bazin committed
743 744 745
 * get fourcc priority from arbritary preference, the higher the better
 */
static int GetFourCCPriority( int i_fourcc )
746 747 748
{
    switch( i_fourcc )
    {
Gildas Bazin's avatar
Gildas Bazin committed
749 750 751 752 753 754 755 756 757 758 759 760
    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;
761
    }
Gildas Bazin's avatar
Gildas Bazin committed
762

763 764 765 766 767
    return 0;
}

#define MAX_MEDIA_TYPES 32

Gildas Bazin's avatar
Gildas Bazin committed
768 769
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
770
{
771 772 773
    /* See if device is already opened */
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
Gildas Bazin's avatar
Gildas Bazin committed
774 775
        if( devicename.size() &&
            p_sys->pp_streams[i]->devicename == devicename )
776 777 778 779 780 781
        {
            /* Already opened */
            return VLC_SUCCESS;
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
782 783
    list<string> list_devices;

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

787 788 789
    if( !list_devices.size() )
        return VLC_EGENERIC;

Gildas Bazin's avatar
 
Gildas Bazin committed
790 791
    list<string>::iterator iter;
    for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
Gildas Bazin's avatar
Gildas Bazin committed
792
        msg_Dbg( p_this, "found device: %s", iter->c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
793 794 795 796 797 798 799 800

    /* 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
801 802
    // a capture/preview device, such as a desktop USB video camera.
    IBaseFilter *p_device_filter =
Gildas Bazin's avatar
Gildas Bazin committed
803
        FindCaptureDevice( p_this, &devicename, 0, b_audio );
Gildas Bazin's avatar
 
Gildas Bazin committed
804
    if( p_device_filter )
Gildas Bazin's avatar
Gildas Bazin committed
805
        msg_Dbg( p_this, "using device: %s", devicename.c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
806 807
    else
    {
Gildas Bazin's avatar
Gildas Bazin committed
808
        msg_Err( p_this, "can't use device: %s, unsupported device type",
809
                 devicename.c_str() );
Gildas Bazin's avatar
 
Gildas Bazin committed
810 811
        return VLC_EGENERIC;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
812

813 814 815 816 817 818 819 820 821 822 823
    // 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 );

    /* Find out if the pin handles MEDIATYPE_Stream, in which case we
     * won't add a prefered media type as this doesn't seem to work well
     * -- to investigate. */
    vlc_bool_t b_stream_type = VLC_FALSE;
824
    for( size_t i = 0; i < media_count; i++ )
825 826 827 828 829 830 831 832
    {
        if( media_types[i].majortype == MEDIATYPE_Stream )
        {
            b_stream_type = VLC_TRUE;
            break;
        }
    }

833 834
    size_t mt_count = 0;
    AM_MEDIA_TYPE *mt = NULL;
Gildas Bazin's avatar
Gildas Bazin committed
835

836
    if( !b_stream_type && !b_audio )
Gildas Bazin's avatar
Gildas Bazin committed
837
    {
838
        // Insert prefered video media type
839
        AM_MEDIA_TYPE mtr;
Gildas Bazin's avatar
Gildas Bazin committed
840 841 842 843 844 845 846 847 848 849
        VIDEOINFOHEADER vh;

        mtr.majortype            = MEDIATYPE_Video;
        mtr.subtype              = MEDIASUBTYPE_I420;
        mtr.bFixedSizeSamples    = TRUE;
        mtr.bTemporalCompression = FALSE;
        mtr.pUnk                 = NULL;
        mtr.formattype           = FORMAT_VideoInfo;
        mtr.cbFormat             = sizeof(vh);
        mtr.pbFormat             = (BYTE *)&vh;
850 851 852

        memset(&vh, 0, sizeof(vh));

Gildas Bazin's avatar
Gildas Bazin committed
853
        vh.bmiHeader.biSize   = sizeof(vh.bmiHeader);
854
        vh.bmiHeader.biWidth  = p_sys->i_width > 0 ? p_sys->i_width : 320;
Gildas Bazin's avatar
Gildas Bazin committed
855
        vh.bmiHeader.biHeight = p_sys->i_height > 0 ? p_sys->i_height : 240;
856
        vh.bmiHeader.biPlanes      = 3;
Gildas Bazin's avatar
Gildas Bazin committed
857 858
        vh.bmiHeader.biBitCount    = 12;
        vh.bmiHeader.biCompression = VLC_FOURCC('I','4','2','0');
859 860 861
        vh.bmiHeader.biSizeImage   = vh.bmiHeader.biWidth * 12 *
            vh.bmiHeader.biHeight / 8;
        mtr.lSampleSize            = vh.bmiHeader.biSizeImage;
862

Gildas Bazin's avatar
Gildas Bazin committed
863 864 865
        mt_count = 1;
        mt = (AM_MEDIA_TYPE *)malloc( sizeof(AM_MEDIA_TYPE)*mt_count );
        CopyMediaType(mt, &mtr);
866
    }
867
    else if( !b_stream_type )
Gildas Bazin's avatar
Gildas Bazin committed
868
    {
869
        // Insert prefered audio media type
870
        AM_MEDIA_TYPE mtr;
Gildas Bazin's avatar
Gildas Bazin committed
871 872 873 874 875 876 877 878 879 880 881
        WAVEFORMATEX wf;

        mtr.majortype            = MEDIATYPE_Audio;
        mtr.subtype              = MEDIASUBTYPE_PCM;
        mtr.bFixedSizeSamples    = TRUE;
        mtr.bTemporalCompression = FALSE;
        mtr.lSampleSize          = 0;
        mtr.pUnk                 = NULL;
        mtr.formattype           = FORMAT_WaveFormatEx;
        mtr.cbFormat             = sizeof(wf);
        mtr.pbFormat             = (BYTE *)&wf;
882 883 884

        memset(&wf, 0, sizeof(wf));

Gildas Bazin's avatar
Gildas Bazin committed
885 886 887 888 889 890 891
        wf.wFormatTag = WAVE_FORMAT_PCM;
        wf.nChannels = 2;
        wf.nSamplesPerSec = 44100;
        wf.wBitsPerSample = 16;
        wf.nBlockAlign = wf.nSamplesPerSec * wf.wBitsPerSample / 8;
        wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
        wf.cbSize = 0;
892

Gildas Bazin's avatar
Gildas Bazin committed
893 894 895
        mt_count = 1;
        mt = (AM_MEDIA_TYPE *)malloc( sizeof(AM_MEDIA_TYPE)*mt_count );
        CopyMediaType(mt, &mtr);
896
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
897

898 899
    if( media_count > 0 )
    {
900 901
        mt = (AM_MEDIA_TYPE *)realloc( mt, sizeof(AM_MEDIA_TYPE) *
                                       (mt_count + media_count) );
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932

        // 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 )
            {
                mt[c+mt_count] = media_types[slot_copy];
                media_types[slot_copy] = media_types[c];
            }
            else
            {
                mt[c+mt_count] = media_types[c];
            }
        }
        mt_count += media_count;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
933
    /* Create and add our capture filter */
934
    CaptureFilter *p_capture_filter =
Gildas Bazin's avatar
Gildas Bazin committed
935
        new CaptureFilter( p_this, p_sys, mt, mt_count );
Gildas Bazin's avatar
 
Gildas Bazin committed
936
    p_sys->p_graph->AddFilter( p_capture_filter, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
937 938 939

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

Gildas Bazin's avatar
 
Gildas Bazin committed
942
    /* Attempt to connect one of this device's capture output pins */
Gildas Bazin's avatar
Gildas Bazin committed
943 944
    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
945 946
    {
        /* Success */
Gildas Bazin's avatar
Gildas Bazin committed
947
        msg_Dbg( p_this, "filters connected successfully !" );
948

Gildas Bazin's avatar
 
Gildas Bazin committed
949
        dshow_stream_t dshow_stream;
950
        dshow_stream.b_pts = VLC_FALSE;
Gildas Bazin's avatar
Gildas Bazin committed
951
        dshow_stream.p_es = 0;
952 953 954
        dshow_stream.mt =
            p_capture_filter->CustomGetPin()->CustomGetMediaType();

955 956
        /* Show Device properties. Done here so the VLC stream is setup with
         * the proper parameters. */
957
        vlc_value_t val;
Gildas Bazin's avatar
Gildas Bazin committed
958
        var_Get( p_this, "dshow-config", &val );
959
        if( val.b_bool )
960
        {
961 962
            ShowDeviceProperties( p_this, p_sys->p_capture_graph_builder2,
                                  p_device_filter, b_audio );
963
        }
964

965 966 967
        ConfigTuner( p_this,