]> git.sesse.net Git - vlc/blob - modules/access/dshow/dshow.cpp
Trailing ;
[vlc] / modules / access / dshow / dshow.cpp
1 /*****************************************************************************
2  * dshow.cpp : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002, 2003 the VideoLAN team
5  * $Id$
6  *
7  * Author: Gildas Bazin <gbazin@videolan.org>
8  *         Damien Fouilleul <damienf@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #define __STDC_FORMAT_MACROS 1
34 #include <inttypes.h>
35
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_input.h>
39 #include <vlc_access.h>
40 #include <vlc_demux.h>
41 #include <vlc_vout.h>
42 #include <vlc_interface.h>
43
44 #include "common.h"
45 #include "filter.h"
46
47 /*****************************************************************************
48  * Access: local prototypes
49  *****************************************************************************/
50 static block_t *ReadCompressed( access_t * );
51 static int AccessControl ( access_t *, int, va_list );
52
53 static int Demux       ( demux_t * );
54 static int DemuxControl( demux_t *, int, va_list );
55
56 static int OpenDevice( vlc_object_t *, access_sys_t *, string, bool );
57 static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
58                                        list<string> *, bool );
59 static size_t EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
60                               int, int, int, int, int, int,
61                               AM_MEDIA_TYPE *mt, size_t );
62 static bool ConnectFilters( vlc_object_t *, access_sys_t *,
63                             IBaseFilter *, CaptureFilter * );
64 static int FindDevicesCallback( vlc_object_t *, char const *,
65                                 vlc_value_t, vlc_value_t, void * );
66 static int ConfigDevicesCallback( vlc_object_t *, char const *,
67                                   vlc_value_t, vlc_value_t, void * );
68
69 static void ShowPropertyPage( IUnknown * );
70 static void ShowDeviceProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
71                                   IBaseFilter *, bool );
72 static void ShowTunerProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
73                                  IBaseFilter *, bool );
74 static void ConfigTuner( vlc_object_t *, ICaptureGraphBuilder2 *,
75                          IBaseFilter * );
76
77 /*****************************************************************************
78  * Module descriptor
79  *****************************************************************************/
80 static const char *const ppsz_vdev[] = { "", "none" };
81 static const char *const ppsz_vdev_text[] = { N_("Default"), N_("None") };
82 static const char *const ppsz_adev[] = { "", "none" };
83 static const char *const ppsz_adev_text[] = { N_("Default"), N_("None") };
84 static const int pi_tuner_input[] = { 0, 1, 2 };
85 static const char *const ppsz_tuner_input_text[] =
86     {N_("Default"), N_("Cable"), N_("Antenna")};
87 static const int pi_amtuner_mode[]  = { AMTUNER_MODE_DEFAULT,
88                                  AMTUNER_MODE_TV,
89                                  AMTUNER_MODE_FM_RADIO,
90                                  AMTUNER_MODE_AM_RADIO,
91                                  AMTUNER_MODE_DSS };
92 static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
93                                           N_("TV"),
94                                           N_("FM radio"),
95                                           N_("AM radio"),
96                                           N_("DSS") };
97
98 #define CACHING_TEXT N_("Caching value in ms")
99 #define CACHING_LONGTEXT N_( \
100     "Caching value for DirectShow streams. " \
101     "This value should be set in milliseconds." )
102 #define VDEV_TEXT N_("Video device name")
103 #define VDEV_LONGTEXT N_( \
104     "Name of the video device that will be used by the " \
105     "DirectShow plugin. If you don't specify anything, the default device " \
106     "will be used.")
107 #define ADEV_TEXT N_("Audio device name")
108 #define ADEV_LONGTEXT N_( \
109     "Name of the audio device that will be used by the " \
110     "DirectShow plugin. If you don't specify anything, the default device " \
111     "will be used. ")
112 #define SIZE_TEXT N_("Video size")
113 #define SIZE_LONGTEXT N_( \
114     "Size of the video that will be displayed by the " \
115     "DirectShow plugin. If you don't specify anything the default size for " \
116     "your device will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>.")
117 #define CHROMA_TEXT N_("Video input chroma format")
118 #define CHROMA_LONGTEXT N_( \
119     "Force the DirectShow video input to use a specific chroma format " \
120     "(eg. I420 (default), RV24, etc.)")
121 #define FPS_TEXT N_("Video input frame rate")
122 #define FPS_LONGTEXT N_( \
123     "Force the DirectShow video input to use a specific frame rate" \
124     "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
125 #define CONFIG_TEXT N_("Device properties")
126 #define CONFIG_LONGTEXT N_( \
127     "Show the properties dialog of the selected device before starting the " \
128     "stream.")
129 #define TUNER_TEXT N_("Tuner properties")
130 #define TUNER_LONGTEXT N_( \
131     "Show the tuner properties [channel selection] page." )
132 #define CHANNEL_TEXT N_("Tuner TV Channel")
133 #define CHANNEL_LONGTEXT N_( \
134     "Set the TV channel the tuner will set to " \
135     "(0 means default)." )
136 #define COUNTRY_TEXT N_("Tuner country code")
137 #define COUNTRY_LONGTEXT N_( \
138     "Set the tuner country code that establishes the current " \
139     "channel-to-frequency mapping (0 means default)." )
140 #define TUNER_INPUT_TEXT N_("Tuner input type")
141 #define TUNER_INPUT_LONGTEXT N_( \
142     "Select the tuner input type (Cable/Antenna)." )
143 #define VIDEO_IN_TEXT N_("Video input pin")
144 #define VIDEO_IN_LONGTEXT N_( \
145   "Select the video input source, such as composite, s-video, " \
146   "or tuner. Since these settings are hardware-specific, you should find good " \
147   "settings in the \"Device config\" area, and use those numbers here. -1 " \
148   "means that settings will not be changed.")
149 #define AUDIO_IN_TEXT N_("Audio input pin")
150 #define AUDIO_IN_LONGTEXT N_( \
151   "Select the audio input source. See the \"video input\" option." )
152 #define VIDEO_OUT_TEXT N_("Video output pin")
153 #define VIDEO_OUT_LONGTEXT N_( \
154   "Select the video output type. See the \"video input\" option." )
155 #define AUDIO_OUT_TEXT N_("Audio output pin")
156 #define AUDIO_OUT_LONGTEXT N_( \
157   "Select the audio output type. See the \"video input\" option." )
158
159 #define AMTUNER_MODE_TEXT N_("AM Tuner mode")
160 #define AMTUNER_MODE_LONGTEXT N_( \
161     "AM Tuner mode. Can be one of Default (0), TV (1)," \
162      "AM Radio (2), FM Radio (3) or DSS (4).")
163
164 #define AUDIO_CHANNELS_TEXT N_("Number of audio channels")
165 #define AUDIO_CHANNELS_LONGTEXT N_( \
166     "Select audio input format with the given number of audio channels (if non 0)" )
167
168 #define AUDIO_SAMPLERATE_TEXT N_("Audio sample rate")
169 #define AUDIO_SAMPLERATE_LONGTEXT N_( \
170     "Select audio input format with the given sample rate (if non 0)" )
171
172 #define AUDIO_BITSPERSAMPLE_TEXT N_("Audio bits per sample")
173 #define AUDIO_BITSPERSAMPLE_LONGTEXT N_( \
174     "Select audio input format with the given bits/sample (if non 0)" )
175
176 static int  CommonOpen ( vlc_object_t *, access_sys_t *, bool );
177 static void CommonClose( vlc_object_t *, access_sys_t * );
178
179 static int  AccessOpen ( vlc_object_t * );
180 static void AccessClose( vlc_object_t * );
181
182 static int  DemuxOpen  ( vlc_object_t * );
183 static void DemuxClose ( vlc_object_t * );
184
185 vlc_module_begin ()
186     set_shortname( N_("DirectShow") )
187     set_description( N_("DirectShow input") )
188     set_category( CAT_INPUT )
189     set_subcategory( SUBCAT_INPUT_ACCESS )
190     add_integer( "dshow-caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
191                  CACHING_TEXT, CACHING_LONGTEXT, true )
192
193     add_string( "dshow-vdev", NULL, NULL, VDEV_TEXT, VDEV_LONGTEXT, false)
194         change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback )
195         change_action_add( FindDevicesCallback, N_("Refresh list") )
196         change_action_add( ConfigDevicesCallback, N_("Configure") )
197
198     add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, false)
199         change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback )
200         change_action_add( FindDevicesCallback, N_("Refresh list") )
201         change_action_add( ConfigDevicesCallback, N_("Configure") )
202
203     add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, false)
204
205     add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
206                 true )
207
208     add_float( "dshow-fps", 0.0f, NULL, FPS_TEXT, FPS_LONGTEXT,
209                 true )
210
211     add_bool( "dshow-config", false, NULL, CONFIG_TEXT, CONFIG_LONGTEXT,
212               true )
213
214     add_bool( "dshow-tuner", false, NULL, TUNER_TEXT, TUNER_LONGTEXT,
215               true )
216
217     add_integer( "dshow-tuner-channel", 0, NULL, CHANNEL_TEXT,
218                  CHANNEL_LONGTEXT, true )
219
220     add_integer( "dshow-tuner-country", 0, NULL, COUNTRY_TEXT,
221                  COUNTRY_LONGTEXT, true )
222
223     add_integer( "dshow-tuner-input", 0, NULL, TUNER_INPUT_TEXT,
224                  TUNER_INPUT_LONGTEXT, true )
225         change_integer_list( pi_tuner_input, ppsz_tuner_input_text, NULL )
226
227     add_integer( "dshow-video-input",  -1, NULL, VIDEO_IN_TEXT,
228                  VIDEO_IN_LONGTEXT, true )
229
230     add_integer( "dshow-audio-input",  -1, NULL, AUDIO_IN_TEXT,
231                  AUDIO_IN_LONGTEXT, true )
232
233     add_integer( "dshow-video-output", -1, NULL, VIDEO_OUT_TEXT,
234                  VIDEO_OUT_LONGTEXT, true )
235
236     add_integer( "dshow-audio-output", -1, NULL, AUDIO_OUT_TEXT,
237                  AUDIO_OUT_LONGTEXT, true )
238
239     add_integer( "dshow-amtuner-mode", AMTUNER_MODE_TV, NULL,
240                 AMTUNER_MODE_TEXT, AMTUNER_MODE_LONGTEXT, false)
241         change_integer_list( pi_amtuner_mode, ppsz_amtuner_mode_text, NULL )
242
243     add_integer( "dshow-audio-channels", 0, NULL, AUDIO_CHANNELS_TEXT,
244                  AUDIO_CHANNELS_LONGTEXT, true )
245     add_integer( "dshow-audio-samplerate", 0, NULL, AUDIO_SAMPLERATE_TEXT,
246                  AUDIO_SAMPLERATE_LONGTEXT, true )
247     add_integer( "dshow-audio-bitspersample", 0, NULL, AUDIO_BITSPERSAMPLE_TEXT,
248                  AUDIO_BITSPERSAMPLE_LONGTEXT, true )
249
250     add_shortcut( "dshow" )
251     set_capability( "access_demux", 0 )
252     set_callbacks( DemuxOpen, DemuxClose )
253
254     add_submodule ()
255     set_description( N_("DirectShow input") )
256     set_capability( "access", 0 )
257     set_callbacks( AccessOpen, AccessClose )
258
259 vlc_module_end ()
260
261 /*****************************************************************************
262  * DirectShow elementary stream descriptor
263  *****************************************************************************/
264 typedef struct dshow_stream_t
265 {
266     string          devicename;
267     IBaseFilter     *p_device_filter;
268     CaptureFilter   *p_capture_filter;
269     AM_MEDIA_TYPE   mt;
270
271     union
272     {
273       VIDEOINFOHEADER video;
274       WAVEFORMATEX    audio;
275
276     } header;
277
278     int             i_fourcc;
279     es_out_id_t     *p_es;
280
281     bool      b_pts;
282
283     deque<VLCMediaSample> samples_queue;
284 } dshow_stream_t;
285
286 /*****************************************************************************
287  * DirectShow utility functions
288  *****************************************************************************/
289 static void CreateDirectShowGraph( access_sys_t *p_sys )
290 {
291     p_sys->i_crossbar_route_depth = 0;
292
293     /* Create directshow filter graph */
294     if( SUCCEEDED( CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
295                        (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph) ) )
296     {
297         /* Create directshow capture graph builder if available */
298         if( SUCCEEDED( CoCreateInstance( CLSID_CaptureGraphBuilder2, 0,
299                          CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder2,
300                          (void **)&p_sys->p_capture_graph_builder2 ) ) )
301         {
302             p_sys->p_capture_graph_builder2->
303                 SetFiltergraph((IGraphBuilder *)p_sys->p_graph);
304         }
305
306         p_sys->p_graph->QueryInterface( IID_IMediaControl,
307                                         (void **)&p_sys->p_control );
308     }
309 }
310
311 static void DeleteDirectShowGraph( access_sys_t *p_sys )
312 {
313     DeleteCrossbarRoutes( p_sys );
314
315     /* Remove filters from graph */
316     for( int i = 0; i < p_sys->i_streams; i++ )
317     {
318         p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );
319         p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );
320         p_sys->pp_streams[i]->p_capture_filter->Release();
321         p_sys->pp_streams[i]->p_device_filter->Release();
322     }
323
324     /* Release directshow objects */
325     if( p_sys->p_control )
326     {
327         p_sys->p_control->Release();
328         p_sys->p_control = NULL;
329     }
330     if( p_sys->p_capture_graph_builder2 )
331     {
332         p_sys->p_capture_graph_builder2->Release();
333         p_sys->p_capture_graph_builder2 = NULL;
334     }
335
336     if( p_sys->p_graph )
337     {
338         p_sys->p_graph->Release();
339         p_sys->p_graph = NULL;
340     }
341 }
342
343 /*****************************************************************************
344  * CommonOpen: open direct show device
345  *****************************************************************************/
346 static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
347                        bool b_access_demux )
348 {
349     vlc_value_t  val;
350     int i;
351
352     /* Get/parse options and open device(s) */
353     string vdevname, adevname;
354     int i_width = 0, i_height = 0, i_chroma = 0;
355     bool b_audio = true;
356
357     var_Create( p_this, "dshow-config", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
358     var_Create( p_this, "dshow-tuner", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
359     var_Create( p_this, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
360     var_Get( p_this, "dshow-vdev", &val );
361     if( val.psz_string ) vdevname = string( val.psz_string );
362     free( val.psz_string );
363
364     var_Create( p_this, "dshow-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
365     var_Get( p_this, "dshow-adev", &val );
366     if( val.psz_string ) adevname = string( val.psz_string );
367     free( val.psz_string );
368
369     static struct {char *psz_size; int  i_width; int  i_height;} size_table[] =
370     { { "subqcif", 128, 96 }, { "qsif", 160, 120 }, { "qcif", 176, 144 },
371       { "sif", 320, 240 }, { "cif", 352, 288 }, { "d1", 640, 480 },
372       { 0, 0, 0 },
373     };
374
375     var_Create( p_this, "dshow-size", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
376     var_Get( p_this, "dshow-size", &val );
377     if( val.psz_string && *val.psz_string )
378     {
379         for( i = 0; size_table[i].psz_size; i++ )
380         {
381             if( !strcmp( val.psz_string, size_table[i].psz_size ) )
382             {
383                 i_width = size_table[i].i_width;
384                 i_height = size_table[i].i_height;
385                 break;
386             }
387         }
388         if( !size_table[i].psz_size ) /* Try to parse "WidthxHeight" */
389         {
390             char *psz_parser;
391             i_width = strtol( val.psz_string, &psz_parser, 0 );
392             if( *psz_parser == 'x' || *psz_parser == 'X')
393             {
394                 i_height = strtol( psz_parser + 1, &psz_parser, 0 );
395             }
396             msg_Dbg( p_this, "width x height %dx%d", i_width, i_height );
397         }
398     }
399     free( val.psz_string );
400
401     p_sys->b_chroma = false;
402     var_Create( p_this, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
403     var_Get( p_this, "dshow-chroma", &val );
404     if( val.psz_string && strlen( val.psz_string ) >= 4 )
405     {
406         i_chroma = VLC_FOURCC( val.psz_string[0], val.psz_string[1],
407                                val.psz_string[2], val.psz_string[3] );
408         p_sys->b_chroma = true;
409     }
410     free( val.psz_string );
411
412     var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
413     var_Create( p_this, "dshow-tuner-channel",
414                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
415     var_Create( p_this, "dshow-tuner-country",
416                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
417     var_Create( p_this, "dshow-tuner-input",
418                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
419
420     var_Create( p_this, "dshow-amtuner-mode",
421                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
422
423     var_Create( p_this, "dshow-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
424
425     var_Create( p_this, "dshow-video-input", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
426     var_Create( p_this, "dshow-audio-input", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
427     var_Create( p_this, "dshow-video-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
428     var_Create( p_this, "dshow-audio-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
429
430     /* Initialize OLE/COM */
431     CoInitialize( 0 );
432
433     /* Initialize some data */
434     p_sys->i_streams = 0;
435     p_sys->pp_streams = NULL;
436     p_sys->i_width = i_width;
437     p_sys->i_height = i_height;
438     p_sys->i_chroma = i_chroma;
439
440     p_sys->p_graph = NULL;
441     p_sys->p_capture_graph_builder2 = NULL;
442     p_sys->p_control = NULL;
443
444     vlc_mutex_init( &p_sys->lock );
445     vlc_cond_init( &p_sys->wait );
446
447     /* Build directshow graph */
448     CreateDirectShowGraph( p_sys );
449
450     if( OpenDevice( p_this, p_sys, vdevname, 0 ) != VLC_SUCCESS )
451     {
452         msg_Err( p_this, "can't open video");
453     }
454     else
455     {
456         /* Check if we can handle the demuxing ourselves or need to spawn
457          * a demuxer module */
458         dshow_stream_t *p_stream = p_sys->pp_streams[p_sys->i_streams-1];
459
460         if( p_stream->mt.majortype == MEDIATYPE_Video )
461         {
462             if( /* Raw DV stream */
463                 p_stream->i_fourcc == VLC_FOURCC('d','v','s','l') ||
464                 p_stream->i_fourcc == VLC_FOURCC('d','v','s','d') ||
465                 p_stream->i_fourcc == VLC_FOURCC('d','v','h','d') ||
466                 /* Raw MPEG video stream */
467                 p_stream->i_fourcc == VLC_FOURCC('m','p','2','v') )
468             {
469                 b_audio = false;
470
471                 if( b_access_demux )
472                 {
473                     /* Let the access (only) take care of that */
474                     return VLC_EGENERIC;
475                 }
476             }
477         }
478
479         if( p_stream->mt.majortype == MEDIATYPE_Stream )
480         {
481             b_audio = false;
482
483             if( b_access_demux )
484             {
485                 /* Let the access (only) take care of that */
486                 return VLC_EGENERIC;
487             }
488
489             var_Get( p_this, "dshow-tuner", &val );
490             if( val.b_bool )
491             {
492                 /* FIXME: we do MEDIATYPE_Stream here so we don't do
493                  * it twice. */
494                 ShowTunerProperties( p_this, p_sys->p_capture_graph_builder2,
495                                      p_stream->p_device_filter, 0 );
496             }
497         }
498     }
499
500     if( b_audio && OpenDevice( p_this, p_sys, adevname, 1 ) != VLC_SUCCESS )
501     {
502         msg_Err( p_this, "can't open audio");
503     }
504
505     for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
506     {
507             var_Get( p_this, "dshow-video-input", &val );
508             if( val.i_int >= 0 )
509                     p_sys->crossbar_routes[i].VideoInputIndex=val.i_int;
510             var_Get( p_this, "dshow-video-output", &val );
511             if( val.i_int >= 0 )
512                     p_sys->crossbar_routes[i].VideoOutputIndex=val.i_int;
513             var_Get( p_this, "dshow-audio-input", &val );
514             if( val.i_int >= 0 )
515                     p_sys->crossbar_routes[i].AudioInputIndex=val.i_int;
516             var_Get( p_this, "dshow-audio-output", &val );
517             if( val.i_int >= 0 )
518                     p_sys->crossbar_routes[i].AudioOutputIndex=val.i_int;
519
520         IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
521         LONG VideoInputIndex = p_sys->crossbar_routes[i].VideoInputIndex;
522         LONG VideoOutputIndex = p_sys->crossbar_routes[i].VideoOutputIndex;
523         LONG AudioInputIndex = p_sys->crossbar_routes[i].AudioInputIndex;
524         LONG AudioOutputIndex = p_sys->crossbar_routes[i].AudioOutputIndex;
525
526         if( SUCCEEDED(pXbar->Route(VideoOutputIndex, VideoInputIndex)) )
527         {
528             msg_Dbg( p_this, "crossbar at depth %d, routed video "
529                      "output %ld to video input %ld", i, VideoOutputIndex,
530                      VideoInputIndex );
531
532             if( AudioOutputIndex != -1 && AudioInputIndex != -1 )
533             {
534                 if( SUCCEEDED( pXbar->Route(AudioOutputIndex,
535                                             AudioInputIndex)) )
536                 {
537                     msg_Dbg(p_this, "crossbar at depth %d, routed audio "
538                             "output %ld to audio input %ld", i,
539                             AudioOutputIndex, AudioInputIndex );
540                 }
541             }
542         }
543     }
544
545     /*
546     ** Show properties pages from other filters in graph
547     */
548     var_Get( p_this, "dshow-config", &val );
549     if( val.b_bool )
550     {
551         for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
552         {
553             IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
554             IBaseFilter *p_XF;
555
556             if( SUCCEEDED( pXbar->QueryInterface( IID_IBaseFilter,
557                                                   (void **)&p_XF ) ) )
558             {
559                 ShowPropertyPage( p_XF );
560                 p_XF->Release();
561             }
562         }
563     }
564
565     /* Initialize some data */
566     p_sys->i_current_stream = 0;
567
568     if( !p_sys->i_streams ) return VLC_EGENERIC;
569
570     return VLC_SUCCESS;
571 }
572
573 /*****************************************************************************
574  * DemuxOpen: open direct show device as an access_demux module
575  *****************************************************************************/
576 static int DemuxOpen( vlc_object_t *p_this )
577 {
578     demux_t      *p_demux = (demux_t *)p_this;
579     access_sys_t *p_sys;
580     int i;
581
582     p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t ) );
583     if( !p_sys )
584         return VLC_ENOMEM;
585     p_demux->p_sys = (demux_sys_t *)p_sys;
586
587     if( CommonOpen( p_this, p_sys, true ) != VLC_SUCCESS )
588     {
589         CommonClose( p_this, p_sys );
590         return VLC_EGENERIC;
591     }
592
593     /* Everything is ready. Let's rock baby */
594     msg_Dbg( p_this, "Playing...");
595     p_sys->p_control->Run();
596
597     p_demux->pf_demux   = Demux;
598     p_demux->pf_control = DemuxControl;
599     p_demux->info.i_update = 0;
600     p_demux->info.i_title = 0;
601     p_demux->info.i_seekpoint = 0;
602
603     for( i = 0; i < p_sys->i_streams; i++ )
604     {
605         dshow_stream_t *p_stream = p_sys->pp_streams[i];
606         es_format_t fmt;
607
608         if( p_stream->mt.majortype == MEDIATYPE_Video )
609         {
610             es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
611
612             fmt.video.i_width  = p_stream->header.video.bmiHeader.biWidth;
613             fmt.video.i_height = p_stream->header.video.bmiHeader.biHeight;
614             fmt.video.i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
615
616             if( !p_stream->header.video.bmiHeader.biCompression )
617             {
618                 /* RGB DIB are coded from bottom to top */
619                 fmt.video.i_height = (unsigned int)(-(int)fmt.video.i_height);
620             }
621
622             /* Setup rgb mask for RGB formats */
623             if( p_stream->i_fourcc == VLC_FOURCC('R','V','2','4') )
624             {
625                 /* This is in BGR format */
626                 fmt.video.i_bmask = 0x00ff0000;
627                 fmt.video.i_gmask = 0x0000ff00;
628                 fmt.video.i_rmask = 0x000000ff;
629             }
630
631             if( p_stream->header.video.AvgTimePerFrame )
632             {
633                 fmt.video.i_frame_rate = 10000000;
634                 fmt.video.i_frame_rate_base =
635                     p_stream->header.video.AvgTimePerFrame;
636             }
637         }
638         else if( p_stream->mt.majortype == MEDIATYPE_Audio )
639         {
640             es_format_Init( &fmt, AUDIO_ES, p_stream->i_fourcc );
641
642             fmt.audio.i_channels = p_stream->header.audio.nChannels;
643             fmt.audio.i_rate = p_stream->header.audio.nSamplesPerSec;
644             fmt.audio.i_bitspersample = p_stream->header.audio.wBitsPerSample;
645             fmt.audio.i_blockalign = fmt.audio.i_channels *
646                 fmt.audio.i_bitspersample / 8;
647             fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate *
648                 fmt.audio.i_bitspersample;
649         }
650
651         p_stream->p_es = es_out_Add( p_demux->out, &fmt );
652     }
653
654     return VLC_SUCCESS;
655 }
656
657 /*****************************************************************************
658  * AccessOpen: open direct show device as an access module
659  *****************************************************************************/
660 static int AccessOpen( vlc_object_t *p_this )
661 {
662     access_t     *p_access = (access_t*)p_this;
663     access_sys_t *p_sys;
664
665     p_access->p_sys = p_sys = (access_sys_t*)calloc( 1, sizeof( access_sys_t ) );
666     if( !p_sys )
667         return VLC_ENOMEM;
668
669     if( CommonOpen( p_this, p_sys, false ) != VLC_SUCCESS )
670     {
671         CommonClose( p_this, p_sys );
672         return VLC_EGENERIC;
673     }
674
675     dshow_stream_t *p_stream = p_sys->pp_streams[0];
676
677     /* Check if we need to force demuxers */
678     if( !p_access->psz_demux || !*p_access->psz_demux )
679     {
680         if( p_stream->i_fourcc == VLC_FOURCC('d','v','s','l') ||
681             p_stream->i_fourcc == VLC_FOURCC('d','v','s','d') ||
682             p_stream->i_fourcc == VLC_FOURCC('d','v','h','d') )
683         {
684             free( p_access->psz_demux );
685             p_access->psz_demux = strdup( "rawdv" );
686         }
687         else if( p_stream->i_fourcc == VLC_FOURCC('m','p','2','v') )
688         {
689             free( p_access->psz_demux );
690             p_access->psz_demux = strdup( "mpgv" );
691         }
692     }
693
694     /* Setup Access */
695     p_access->pf_read = NULL;
696     p_access->pf_block = ReadCompressed;
697     p_access->pf_control = AccessControl;
698     p_access->pf_seek = NULL;
699     p_access->info.i_update = 0;
700     p_access->info.i_size = 0;
701     p_access->info.i_pos = 0;
702     p_access->info.b_eof = false;
703     p_access->info.i_title = 0;
704     p_access->info.i_seekpoint = 0;
705     p_access->p_sys = p_sys;
706
707     /* Everything is ready. Let's rock baby */
708     msg_Dbg( p_this, "Playing...");
709     p_sys->p_control->Run();
710
711     return VLC_SUCCESS;
712 }
713
714 /*****************************************************************************
715  * CommonClose: close device
716  *****************************************************************************/
717 static void CommonClose( vlc_object_t *p_this, access_sys_t *p_sys )
718 {
719     msg_Dbg( p_this, "releasing DirectShow");
720
721     DeleteDirectShowGraph( p_sys );
722
723     /* Uninitialize OLE/COM */
724     CoUninitialize();
725
726     for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];
727     if( p_sys->i_streams ) free( p_sys->pp_streams );
728
729     vlc_mutex_destroy( &p_sys->lock );
730     vlc_cond_destroy( &p_sys->wait );
731
732     free( p_sys );
733 }
734
735 /*****************************************************************************
736  * AccessClose: close device
737  *****************************************************************************/
738 static void AccessClose( vlc_object_t *p_this )
739 {
740     access_t     *p_access = (access_t *)p_this;
741     access_sys_t *p_sys    = p_access->p_sys;
742
743     /* Stop capturing stuff */
744     p_sys->p_control->Stop();
745
746     CommonClose( p_this, p_sys );
747 }
748
749 /*****************************************************************************
750  * DemuxClose: close device
751  *****************************************************************************/
752 static void DemuxClose( vlc_object_t *p_this )
753 {
754     demux_t      *p_demux = (demux_t *)p_this;
755     access_sys_t *p_sys   = (access_sys_t *)p_demux->p_sys;
756
757     /* Stop capturing stuff */
758     p_sys->p_control->Stop();
759
760     CommonClose( p_this, p_sys );
761 }
762
763 /****************************************************************************
764  * ConnectFilters
765  ****************************************************************************/
766 static bool ConnectFilters( vlc_object_t *p_this, access_sys_t *p_sys,
767                             IBaseFilter *p_filter,
768                             CaptureFilter *p_capture_filter )
769 {
770     CapturePin *p_input_pin = p_capture_filter->CustomGetPin();
771
772     AM_MEDIA_TYPE mediaType = p_input_pin->CustomGetMediaType();
773
774     if( p_sys->p_capture_graph_builder2 )
775     {
776         if( FAILED(p_sys->p_capture_graph_builder2->
777                 RenderStream( &PIN_CATEGORY_CAPTURE, &mediaType.majortype,
778                               p_filter, 0, (IBaseFilter *)p_capture_filter )) )
779         {
780             return false;
781         }
782
783         // Sort out all the possible video inputs
784         // The class needs to be given the capture filters ANALOGVIDEO input pin
785         IEnumPins *pins = NULL;
786         if( ( mediaType.majortype == MEDIATYPE_Video ||
787               mediaType.majortype == MEDIATYPE_Stream ) &&
788             SUCCEEDED(p_filter->EnumPins(&pins)) )
789         {
790             IPin        *pP = NULL;
791             ULONG        n;
792             PIN_INFO     pinInfo;
793             BOOL         Found = FALSE;
794             IKsPropertySet *pKs = NULL;
795             GUID guid;
796             DWORD dw;
797
798             while( !Found && ( S_OK == pins->Next(1, &pP, &n) ) )
799             {
800                 if( S_OK == pP->QueryPinInfo(&pinInfo) )
801                 {
802                     // is this pin an ANALOGVIDEOIN input pin?
803                     if( pinInfo.dir == PINDIR_INPUT &&
804                         pP->QueryInterface( IID_IKsPropertySet,
805                                             (void **)&pKs ) == S_OK )
806                     {
807                         if( pKs->Get( AMPROPSETID_Pin,
808                                       AMPROPERTY_PIN_CATEGORY, NULL, 0,
809                                       &guid, sizeof(GUID), &dw ) == S_OK )
810                         {
811                             if( guid == PIN_CATEGORY_ANALOGVIDEOIN )
812                             {
813                                 // recursively search crossbar routes
814                                 FindCrossbarRoutes( p_this, p_sys, pP, 0 );
815                                 // found it
816                                 Found = TRUE;
817                             }
818                         }
819                         pKs->Release();
820                     }
821                     pinInfo.pFilter->Release();
822                 }
823                 pP->Release();
824             }
825             pins->Release();
826         }
827         return true;
828     }
829     else
830     {
831         IEnumPins *p_enumpins;
832         IPin *p_pin;
833
834         if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
835
836         while( S_OK == p_enumpins->Next( 1, &p_pin, NULL ) )
837         {
838             PIN_DIRECTION pin_dir;
839             p_pin->QueryDirection( &pin_dir );
840
841             if( pin_dir == PINDIR_OUTPUT &&
842                 p_sys->p_graph->ConnectDirect( p_pin, (IPin *)p_input_pin,
843                                                0 ) == S_OK )
844             {
845                 p_pin->Release();
846                 p_enumpins->Release();
847                 return true;
848             }
849             p_pin->Release();
850         }
851
852         p_enumpins->Release();
853         return false;
854     }
855 }
856
857 /*
858  * get fourcc priority from arbritary preference, the higher the better
859  */
860 static int GetFourCCPriority( int i_fourcc )
861 {
862     switch( i_fourcc )
863     {
864     case VLC_FOURCC('I','4','2','0'):
865     case VLC_FOURCC('f','l','3','2'):
866         return 9;
867     case VLC_FOURCC('Y','V','1','2'):
868     case VLC_FOURCC('a','r','a','w'):
869         return 8;
870     case VLC_FOURCC('R','V','2','4'):
871         return 7;
872     case VLC_FOURCC('Y','U','Y','2'):
873     case VLC_FOURCC('R','V','3','2'):
874     case VLC_FOURCC('R','G','B','A'):
875         return 6;
876     }
877
878     return 0;
879 }
880
881 #define MAX_MEDIA_TYPES 32
882
883 static int OpenDevice( vlc_object_t *p_this, access_sys_t *p_sys,
884                        string devicename, bool b_audio )
885 {
886     /* See if device is already opened */
887     for( int i = 0; i < p_sys->i_streams; i++ )
888     {
889         if( devicename.size() &&
890             p_sys->pp_streams[i]->devicename == devicename )
891         {
892             /* Already opened */
893             return VLC_SUCCESS;
894         }
895     }
896
897     list<string> list_devices;
898
899     /* Enumerate devices and display their names */
900     FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
901
902     if( !list_devices.size() )
903         return VLC_EGENERIC;
904
905     list<string>::iterator iter;
906     for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
907         msg_Dbg( p_this, "found device: %s", iter->c_str() );
908
909     /* If no device name was specified, pick the 1st one */
910     if( devicename.size() == 0 )
911     {
912         devicename = *list_devices.begin();
913     }
914
915     // Use the system device enumerator and class enumerator to find
916     // a capture/preview device, such as a desktop USB video camera.
917     IBaseFilter *p_device_filter =
918         FindCaptureDevice( p_this, &devicename, 0, b_audio );
919     if( p_device_filter )
920         msg_Dbg( p_this, "using device: %s", devicename.c_str() );
921     else
922     {
923         msg_Err( p_this, "can't use device: %s, unsupported device type",
924                  devicename.c_str() );
925         intf_UserFatal( p_this, false, _("Capturing failed"),
926                         _("VLC cannot use the device \"%s\", because its "
927                           "type is not supported.") );
928         return VLC_EGENERIC;
929     }
930
931     // Retreive acceptable media types supported by device
932     AM_MEDIA_TYPE media_types[MAX_MEDIA_TYPES];
933     size_t media_count =
934         EnumDeviceCaps( p_this, p_device_filter, b_audio ? 0 : p_sys->i_chroma,
935                         p_sys->i_width, p_sys->i_height,
936       b_audio ? var_CreateGetInteger( p_this, "dshow-audio-channels" ) : 0,
937       b_audio ? var_CreateGetInteger( p_this, "dshow-audio-samplerate" ) : 0,
938       b_audio ? var_CreateGetInteger( p_this, "dshow-audio-bitspersample" ) : 0,
939       media_types, MAX_MEDIA_TYPES );
940
941     AM_MEDIA_TYPE *mt = NULL;
942
943     if( media_count > 0 )
944     {
945         mt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * media_count);
946
947         // Order and copy returned media types according to arbitrary
948         // fourcc priority
949         for( size_t c = 0; c < media_count; c++ )
950         {
951             int slot_priority =
952                 GetFourCCPriority(GetFourCCFromMediaType(media_types[c]));
953             size_t slot_copy = c;
954             for( size_t d = c+1; d < media_count; d++ )
955             {
956                 int priority =
957                     GetFourCCPriority(GetFourCCFromMediaType(media_types[d]));
958                 if( priority > slot_priority )
959                 {
960                     slot_priority = priority;
961                     slot_copy = d;
962                 }
963             }
964             if( slot_copy != c )
965             {
966                 mt[c] = media_types[slot_copy];
967                 media_types[slot_copy] = media_types[c];
968             }
969             else
970             {
971                 mt[c] = media_types[c];
972             }
973         }
974     }
975     else {
976         /* capture device */
977         msg_Err( p_this, "capture device '%s' does not support required parameters !", devicename.c_str() );
978         intf_UserFatal( p_this, false, _("Capturing failed"),
979                         _("The capture device \"%s\" does not support the "
980                           "required parameters."), devicename.c_str() );
981         p_device_filter->Release();
982         return VLC_EGENERIC;
983     }
984
985     /* Create and add our capture filter */
986     CaptureFilter *p_capture_filter =
987         new CaptureFilter( p_this, p_sys, mt, media_count );
988     p_sys->p_graph->AddFilter( p_capture_filter, 0 );
989
990     /* Add the device filter to the graph (seems necessary with VfW before
991      * accessing pin attributes). */
992     p_sys->p_graph->AddFilter( p_device_filter, 0 );
993
994     /* Attempt to connect one of this device's capture output pins */
995     msg_Dbg( p_this, "connecting filters" );
996     if( ConnectFilters( p_this, p_sys, p_device_filter, p_capture_filter ) )
997     {
998         /* Success */
999         msg_Dbg( p_this, "filters connected successfully !" );
1000
1001         dshow_stream_t dshow_stream;
1002         dshow_stream.b_pts = false;
1003         dshow_stream.p_es = 0;
1004         dshow_stream.mt =
1005             p_capture_filter->CustomGetPin()->CustomGetMediaType();
1006
1007         /* Show Device properties. Done here so the VLC stream is setup with
1008          * the proper parameters. */
1009         vlc_value_t val;
1010         var_Get( p_this, "dshow-config", &val );
1011         if( val.b_bool )
1012         {
1013             ShowDeviceProperties( p_this, p_sys->p_capture_graph_builder2,
1014                                   p_device_filter, b_audio );
1015         }
1016
1017         ConfigTuner( p_this, p_sys->p_capture_graph_builder2,
1018                      p_device_filter );
1019
1020         var_Get( p_this, "dshow-tuner", &val );
1021         if( val.b_bool && dshow_stream.mt.majortype != MEDIATYPE_Stream )
1022         {
1023             /* FIXME: we do MEDIATYPE_Stream later so we don't do it twice. */
1024             ShowTunerProperties( p_this, p_sys->p_capture_graph_builder2,
1025                                  p_device_filter, b_audio );
1026         }
1027
1028         dshow_stream.mt =
1029             p_capture_filter->CustomGetPin()->CustomGetMediaType();
1030
1031         dshow_stream.i_fourcc = GetFourCCFromMediaType( dshow_stream.mt );
1032         if( dshow_stream.i_fourcc )
1033         {
1034             if( dshow_stream.mt.majortype == MEDIATYPE_Video )
1035             {
1036                 dshow_stream.header.video =
1037                     *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
1038                 msg_Dbg( p_this, "MEDIATYPE_Video" );
1039                 msg_Dbg( p_this, "selected video pin accepts format: %4.4s",
1040                          (char *)&dshow_stream.i_fourcc);
1041             }
1042             else if( dshow_stream.mt.majortype == MEDIATYPE_Audio )
1043             {
1044                 dshow_stream.header.audio =
1045                     *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
1046                 msg_Dbg( p_this, "MEDIATYPE_Audio" );
1047                 msg_Dbg( p_this, "selected audio pin accepts format: %4.4s",
1048                          (char *)&dshow_stream.i_fourcc);
1049             }
1050             else if( dshow_stream.mt.majortype == MEDIATYPE_Stream )
1051             {
1052                 msg_Dbg( p_this, "MEDIATYPE_Stream" );
1053                 msg_Dbg( p_this, "selected stream pin accepts format: %4.4s",
1054                          (char *)&dshow_stream.i_fourcc);
1055             }
1056             else
1057             {
1058                 msg_Dbg( p_this, "unknown stream majortype" );
1059                 goto fail;
1060             }
1061
1062             /* Add directshow elementary stream to our list */
1063             dshow_stream.p_device_filter = p_device_filter;
1064             dshow_stream.p_capture_filter = p_capture_filter;
1065
1066             p_sys->pp_streams = (dshow_stream_t **)realloc( p_sys->pp_streams,
1067                 sizeof(dshow_stream_t *) * (p_sys->i_streams + 1) );
1068             p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
1069             *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
1070
1071             return VLC_SUCCESS;
1072         }
1073     }
1074
1075  fail:
1076     /* Remove filters from graph */
1077     p_sys->p_graph->RemoveFilter( p_device_filter );
1078     p_sys->p_graph->RemoveFilter( p_capture_filter );
1079
1080     /* Release objects */
1081     p_device_filter->Release();
1082     p_capture_filter->Release();
1083
1084     return VLC_EGENERIC;
1085 }
1086
1087 static IBaseFilter *
1088 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
1089                    list<string> *p_listdevices, bool b_audio )
1090 {
1091     IBaseFilter *p_base_filter = NULL;
1092     IMoniker *p_moniker = NULL;
1093     ULONG i_fetched;
1094     HRESULT hr;
1095     list<string> devicelist;
1096
1097     /* Create the system device enumerator */
1098     ICreateDevEnum *p_dev_enum = NULL;
1099
1100     hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
1101                            IID_ICreateDevEnum, (void **)&p_dev_enum );
1102     if( FAILED(hr) )
1103     {
1104         msg_Err( p_this, "failed to create the device enumerator (0x%lx)", hr);
1105         return NULL;
1106     }
1107
1108     /* Create an enumerator for the video capture devices */
1109     IEnumMoniker *p_class_enum = NULL;
1110     if( !b_audio )
1111         hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
1112                                                 &p_class_enum, 0 );
1113     else
1114         hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
1115                                                 &p_class_enum, 0 );
1116     p_dev_enum->Release();
1117     if( FAILED(hr) )
1118     {
1119         msg_Err( p_this, "failed to create the class enumerator (0x%lx)", hr );
1120         return NULL;
1121     }
1122
1123     /* If there are no enumerators for the requested type, then
1124      * CreateClassEnumerator will succeed, but p_class_enum will be NULL */
1125     if( p_class_enum == NULL )
1126     {
1127         msg_Err( p_this, "no capture device was detected" );
1128         return NULL;
1129     }
1130
1131     /* Enumerate the devices */
1132
1133     /* Note that if the Next() call succeeds but there are no monikers,
1134      * it will return S_FALSE (which is not a failure). Therefore, we check
1135      * that the return code is S_OK instead of using SUCCEEDED() macro. */
1136
1137     while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
1138     {
1139         /* Getting the property page to get the device name */
1140         IPropertyBag *p_bag;
1141         hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
1142                                        (void **)&p_bag );
1143         if( SUCCEEDED(hr) )
1144         {
1145             VARIANT var;
1146             var.vt = VT_BSTR;
1147             hr = p_bag->Read( L"FriendlyName", &var, NULL );
1148             p_bag->Release();
1149             if( SUCCEEDED(hr) )
1150             {
1151                 int i_convert = WideCharToMultiByte(CP_ACP, 0, var.bstrVal,
1152                         SysStringLen(var.bstrVal), NULL, 0, NULL, NULL);
1153                 char *p_buf = (char *)alloca( i_convert+1 ); p_buf[0] = 0;
1154                 WideCharToMultiByte( CP_ACP, 0, var.bstrVal,
1155                         SysStringLen(var.bstrVal), p_buf, i_convert, NULL, NULL );
1156                 SysFreeString(var.bstrVal);
1157                 p_buf[i_convert] = '\0';
1158
1159         string devname = string(p_buf);
1160
1161         int dup = 0;
1162         /* find out if this name is already used by a previously found device */
1163         list<string>::const_iterator iter = devicelist.begin();
1164         list<string>::const_iterator end = devicelist.end();
1165         while ( iter != end )
1166         {
1167             if( 0 == (*iter).compare(0, devname.size(), devname) )
1168             ++dup;
1169             ++iter;
1170         }
1171         if( dup )
1172         {
1173             /* we have a duplicate device name, append a sequence number to name
1174                to provive a unique list back to the user */
1175             char seq[16];
1176             sprintf(seq, " #%d", dup);
1177             devname.append(seq);
1178         }
1179         devicelist.push_back( devname );
1180
1181                 if( p_devicename && *p_devicename == devname )
1182                 {
1183                     /* Bind Moniker to a filter object */
1184                     hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
1185                                                   (void **)&p_base_filter );
1186                     if( FAILED(hr) )
1187                     {
1188                         msg_Err( p_this, "couldn't bind moniker to filter "
1189                                  "object (0x%lx)", hr );
1190                         p_moniker->Release();
1191                         p_class_enum->Release();
1192                         return NULL;
1193                     }
1194                     p_moniker->Release();
1195                     p_class_enum->Release();
1196                     return p_base_filter;
1197                 }
1198             }
1199         }
1200
1201         p_moniker->Release();
1202     }
1203
1204     p_class_enum->Release();
1205
1206     if( p_listdevices ) {
1207     devicelist.sort();
1208     *p_listdevices = devicelist;
1209     }
1210     return NULL;
1211 }
1212
1213 static size_t EnumDeviceCaps( vlc_object_t *p_this, IBaseFilter *p_filter,
1214                               int i_fourcc, int i_width, int i_height,
1215                               int i_channels, int i_samplespersec,
1216                               int i_bitspersample, AM_MEDIA_TYPE *mt,
1217                               size_t mt_max )
1218 {
1219     IEnumPins *p_enumpins;
1220     IPin *p_output_pin;
1221     IEnumMediaTypes *p_enummt;
1222     size_t mt_count = 0;
1223
1224     LONGLONG i_AvgTimePerFrame = 0;
1225     float r_fps = var_GetFloat( p_this, "dshow-fps" );
1226     if( r_fps )
1227         i_AvgTimePerFrame = 10000000000LL/(LONGLONG)(r_fps*1000.0f);
1228
1229     if( FAILED(p_filter->EnumPins( &p_enumpins )) )
1230     {
1231         msg_Dbg( p_this, "EnumDeviceCaps failed: no pin enumeration !");
1232         return 0;
1233     }
1234
1235     while( S_OK == p_enumpins->Next( 1, &p_output_pin, NULL ) )
1236     {
1237         PIN_INFO info;
1238
1239         if( S_OK == p_output_pin->QueryPinInfo( &info ) )
1240         {
1241             msg_Dbg( p_this, "EnumDeviceCaps: %s pin: %S",
1242                      info.dir == PINDIR_INPUT ? "input" : "output",
1243                      info.achName );
1244             if( info.pFilter ) info.pFilter->Release();
1245         }
1246
1247         p_output_pin->Release();
1248     }
1249
1250     p_enumpins->Reset();
1251
1252     while( !mt_count && p_enumpins->Next( 1, &p_output_pin, NULL ) == S_OK )
1253     {
1254         PIN_INFO info;
1255
1256         if( S_OK == p_output_pin->QueryPinInfo( &info ) )
1257         {
1258             if( info.pFilter ) info.pFilter->Release();
1259             if( info.dir == PINDIR_INPUT )
1260             {
1261                 p_output_pin->Release();
1262                 continue;
1263             }
1264             msg_Dbg( p_this, "EnumDeviceCaps: trying pin %S", info.achName );
1265         }
1266
1267         AM_MEDIA_TYPE *p_mt;
1268
1269         /*
1270         ** Configure pin with a default compatible media if possible
1271         */
1272
1273         IAMStreamConfig *pSC;
1274         if( SUCCEEDED(p_output_pin->QueryInterface( IID_IAMStreamConfig,
1275                                             (void **)&pSC )) )
1276         {
1277             int piCount, piSize;
1278             if( SUCCEEDED(pSC->GetNumberOfCapabilities(&piCount, &piSize)) )
1279             {
1280                 BYTE *pSCC= (BYTE *)CoTaskMemAlloc(piSize);
1281                 if( NULL != pSCC )
1282                 {
1283                     int i_priority = -1;
1284                     for( int i=0; i<piCount; ++i )
1285                     {
1286                         if( SUCCEEDED(pSC->GetStreamCaps(i, &p_mt, pSCC)) )
1287                         {
1288                             int i_current_fourcc = GetFourCCFromMediaType( *p_mt );
1289                             int i_current_priority = GetFourCCPriority(i_current_fourcc);
1290
1291                             if( (i_fourcc && (i_current_fourcc != i_fourcc))
1292                              || (i_priority > i_current_priority) )
1293                             {
1294                                 // unwanted chroma, try next media type
1295                                 FreeMediaType( *p_mt );
1296                                 CoTaskMemFree( (PVOID)p_mt );
1297                                 continue;
1298                             }
1299
1300                             if( MEDIATYPE_Video == p_mt->majortype
1301                                     && FORMAT_VideoInfo == p_mt->formattype )
1302                             {
1303                                 VIDEO_STREAM_CONFIG_CAPS *pVSCC = reinterpret_cast<VIDEO_STREAM_CONFIG_CAPS*>(pSCC);
1304                                 VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(p_mt->pbFormat);
1305
1306                                 if( i_AvgTimePerFrame )
1307                                 {
1308                                     if( pVSCC->MinFrameInterval > i_AvgTimePerFrame
1309                                       || i_AvgTimePerFrame > pVSCC->MaxFrameInterval )
1310                                     {
1311                                         // required frame rate not compatible, try next media type
1312                                         FreeMediaType( *p_mt );
1313                                         CoTaskMemFree( (PVOID)p_mt );
1314                                         continue;
1315                                     }
1316                                     pVih->AvgTimePerFrame = i_AvgTimePerFrame;
1317                                 }
1318
1319                                 if( i_width )
1320                                 {
1321                                     if((   !pVSCC->OutputGranularityX
1322                                            && i_width != pVSCC->MinOutputSize.cx
1323                                            && i_width != pVSCC->MaxOutputSize.cx)
1324                                        ||
1325                                        (   pVSCC->OutputGranularityX
1326                                            && ((i_width % pVSCC->OutputGranularityX)
1327                                                || pVSCC->MinOutputSize.cx > i_width
1328                                                || i_width > pVSCC->MaxOutputSize.cx )))
1329                                     {
1330                                         // required width not compatible, try next media type
1331                                         FreeMediaType( *p_mt );
1332                                         CoTaskMemFree( (PVOID)p_mt );
1333                                         continue;
1334                                     }
1335                                     pVih->bmiHeader.biWidth = i_width;
1336                                 }
1337
1338                                 if( i_height )
1339                                 {
1340                                     if((   !pVSCC->OutputGranularityY
1341                                            && i_height != pVSCC->MinOutputSize.cy
1342                                            && i_height != pVSCC->MaxOutputSize.cy)
1343                                        ||
1344                                        (   pVSCC->OutputGranularityY
1345                                            && ((i_height % pVSCC->OutputGranularityY)
1346                                                || pVSCC->MinOutputSize.cy > i_height
1347                                                || i_height > pVSCC->MaxOutputSize.cy )))
1348                                     {
1349                                         // required height not compatible, try next media type
1350                                         FreeMediaType( *p_mt );
1351                                         CoTaskMemFree( (PVOID)p_mt );
1352                                         continue;
1353                                     }
1354                                     pVih->bmiHeader.biHeight = i_height;
1355                                 }
1356
1357                                 // Set the sample size and image size.
1358                                 // (Round the image width up to a DWORD boundary.)
1359                                 p_mt->lSampleSize = pVih->bmiHeader.biSizeImage =
1360                                     ((pVih->bmiHeader.biWidth + 3) & ~3) *
1361                                     pVih->bmiHeader.biHeight * (pVih->bmiHeader.biBitCount>>3);
1362
1363                                 // no cropping, use full video input buffer
1364                                 memset(&(pVih->rcSource), 0, sizeof(RECT));
1365                                 memset(&(pVih->rcTarget), 0, sizeof(RECT));
1366
1367                                 // select this format as default
1368                                 if( SUCCEEDED( pSC->SetFormat(p_mt) ) )
1369                                 {
1370                                     i_priority = i_current_priority;
1371                                     if( i_fourcc )
1372                                         // no need to check any more media types
1373                                         i = piCount;
1374                                 }
1375                             }
1376                             else if( p_mt->majortype == MEDIATYPE_Audio
1377                                     && p_mt->formattype == FORMAT_WaveFormatEx )
1378                             {
1379                                 AUDIO_STREAM_CONFIG_CAPS *pASCC = reinterpret_cast<AUDIO_STREAM_CONFIG_CAPS*>(pSCC);
1380                                 WAVEFORMATEX *pWfx = reinterpret_cast<WAVEFORMATEX*>(p_mt->pbFormat);
1381
1382                                 if( i_current_fourcc && (WAVE_FORMAT_PCM == pWfx->wFormatTag) )
1383                                 {
1384                                     int val = i_channels;
1385                                     if( ! val )
1386                                         val = 2;
1387
1388                                     if( (   !pASCC->ChannelsGranularity
1389                                             && (unsigned int)val != pASCC->MinimumChannels
1390                                             && (unsigned int)val != pASCC->MaximumChannels)
1391                                         ||
1392                                         (   pASCC->ChannelsGranularity
1393                                             && ((val % pASCC->ChannelsGranularity)
1394                                                 || (unsigned int)val < pASCC->MinimumChannels
1395                                                 || (unsigned int)val > pASCC->MaximumChannels)))
1396                                     {
1397                                         // required number channels not available, try next media type
1398                                         FreeMediaType( *p_mt );
1399                                         CoTaskMemFree( (PVOID)p_mt );
1400                                         continue;
1401                                     }
1402                                     pWfx->nChannels = val;
1403
1404                                     val = i_samplespersec;
1405                                     if( ! val )
1406                                         val = 44100;
1407
1408                                     if( (   !pASCC->SampleFrequencyGranularity
1409                                             && (unsigned int)val != pASCC->MinimumSampleFrequency
1410                                             && (unsigned int)val != pASCC->MaximumSampleFrequency)
1411                                         ||
1412                                         (   pASCC->SampleFrequencyGranularity
1413                                             && ((val % pASCC->SampleFrequencyGranularity)
1414                                                 || (unsigned int)val < pASCC->MinimumSampleFrequency
1415                                                 || (unsigned int)val > pASCC->MaximumSampleFrequency )))
1416                                     {
1417                                         // required sampling rate not available, try next media type
1418                                         FreeMediaType( *p_mt );
1419                                         CoTaskMemFree( (PVOID)p_mt );
1420                                         continue;
1421                                     }
1422                                     pWfx->nSamplesPerSec = val;
1423  
1424                                     val = i_bitspersample;
1425                                     if( ! val )
1426                                     {
1427                                         if( VLC_FOURCC('f', 'l', '3', '2') == i_current_fourcc )
1428                                             val = 32;
1429                                         else
1430                                             val = 16;
1431                                     }
1432
1433                                     if( (   !pASCC->BitsPerSampleGranularity
1434                                             && (unsigned int)val != pASCC->MinimumBitsPerSample
1435                                             &&  (unsigned int)val != pASCC->MaximumBitsPerSample )
1436                                         ||
1437                                         (   pASCC->BitsPerSampleGranularity
1438                                             && ((val % pASCC->BitsPerSampleGranularity)
1439                                                 || (unsigned int)val < pASCC->MinimumBitsPerSample
1440                                                 || (unsigned int)val > pASCC->MaximumBitsPerSample )))
1441                                     {
1442                                         // required sample size not available, try next media type
1443                                         FreeMediaType( *p_mt );
1444                                         CoTaskMemFree( (PVOID)p_mt );
1445                                         continue;
1446                                     }
1447
1448                                     pWfx->wBitsPerSample = val;
1449                                     pWfx->nBlockAlign = (pWfx->wBitsPerSample * pWfx->nChannels)/8;
1450                                     pWfx->nAvgBytesPerSec = pWfx->nSamplesPerSec * pWfx->nBlockAlign;
1451
1452                                     // select this format as default
1453                                     if( SUCCEEDED( pSC->SetFormat(p_mt) ) )
1454                                     {
1455                                         i_priority = i_current_priority;
1456                                     }
1457                                 }
1458                             }
1459                             FreeMediaType( *p_mt );
1460                             CoTaskMemFree( (PVOID)p_mt );
1461                         }
1462                     }
1463                     CoTaskMemFree( (LPVOID)pSCC );
1464                     if( i_priority >= 0 )
1465                         msg_Dbg( p_this, "EnumDeviceCaps: input pin default format configured");
1466                 }
1467             }
1468             pSC->Release();
1469         }
1470
1471         /*
1472         ** Probe pin for available medias (may be a previously configured one)
1473         */
1474
1475         if( FAILED( p_output_pin->EnumMediaTypes( &p_enummt ) ) )
1476         {
1477             p_output_pin->Release();
1478             continue;
1479         }
1480
1481         while( p_enummt->Next( 1, &p_mt, NULL ) == S_OK )
1482         {
1483             int i_current_fourcc = GetFourCCFromMediaType( *p_mt );
1484             if( i_current_fourcc && p_mt->majortype == MEDIATYPE_Video
1485                 && p_mt->formattype == FORMAT_VideoInfo )
1486             {
1487                 int i_current_width = ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biWidth;
1488                 int i_current_height = ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biHeight;
1489                 LONGLONG i_current_atpf = ((VIDEOINFOHEADER *)p_mt->pbFormat)->AvgTimePerFrame;
1490
1491                 if( i_current_height < 0 )
1492                     i_current_height = -i_current_height;
1493
1494                 msg_Dbg( p_this, "EnumDeviceCaps: input pin "
1495                          "accepts chroma: %4.4s, width:%i, height:%i, fps:%f",
1496                          (char *)&i_current_fourcc, i_current_width,
1497                          i_current_height, (10000000.0f/((float)i_current_atpf)) );
1498
1499                 if( ( !i_fourcc || i_fourcc == i_current_fourcc ) &&
1500                     ( !i_width || i_width == i_current_width ) &&
1501                     ( !i_height || i_height == i_current_height ) &&
1502                     ( !i_AvgTimePerFrame || i_AvgTimePerFrame == i_current_atpf ) &&
1503                     mt_count < mt_max )
1504                 {
1505                     /* Pick match */
1506                     mt[mt_count++] = *p_mt;
1507                 }
1508                 else FreeMediaType( *p_mt );
1509             }
1510             else if( i_current_fourcc && p_mt->majortype == MEDIATYPE_Audio
1511                     && p_mt->formattype == FORMAT_WaveFormatEx)
1512             {
1513                 int i_current_channels =
1514                     ((WAVEFORMATEX *)p_mt->pbFormat)->nChannels;
1515                 int i_current_samplespersec =
1516                     ((WAVEFORMATEX *)p_mt->pbFormat)->nSamplesPerSec;
1517                 int i_current_bitspersample =
1518                     ((WAVEFORMATEX *)p_mt->pbFormat)->wBitsPerSample;
1519
1520                 msg_Dbg( p_this, "EnumDeviceCaps: input pin "
1521                          "accepts format: %4.4s, channels:%i, "
1522                          "samples/sec:%i bits/sample:%i",
1523                          (char *)&i_current_fourcc, i_current_channels,
1524                          i_current_samplespersec, i_current_bitspersample);
1525
1526                 if( (!i_channels || i_channels == i_current_channels) &&
1527                     (!i_samplespersec ||
1528                      i_samplespersec == i_current_samplespersec) &&
1529                     (!i_bitspersample ||
1530                      i_bitspersample == i_current_bitspersample) &&
1531                     mt_count < mt_max )
1532                 {
1533                     /* Pick  match */
1534                     mt[mt_count++] = *p_mt;
1535
1536                     /* Setup a few properties like the audio latency */
1537                     IAMBufferNegotiation *p_ambuf;
1538                     if( SUCCEEDED( p_output_pin->QueryInterface(
1539                           IID_IAMBufferNegotiation, (void **)&p_ambuf ) ) )
1540                     {
1541                         ALLOCATOR_PROPERTIES AllocProp;
1542                         AllocProp.cbAlign = -1;
1543
1544                         /* 100 ms of latency */
1545                         AllocProp.cbBuffer = i_current_channels *
1546                           i_current_samplespersec *
1547                           i_current_bitspersample / 8 / 10;
1548
1549                         AllocProp.cbPrefix = -1;
1550                         AllocProp.cBuffers = -1;
1551                         p_ambuf->SuggestAllocatorProperties( &AllocProp );
1552                         p_ambuf->Release();
1553                     }
1554                 }
1555                 else FreeMediaType( *p_mt );
1556             }
1557             else if( i_current_fourcc && p_mt->majortype == MEDIATYPE_Stream )
1558             {
1559                 msg_Dbg( p_this, "EnumDeviceCaps: input pin "
1560                          "accepts stream format: %4.4s",
1561                          (char *)&i_current_fourcc );
1562
1563                 if( ( !i_fourcc || i_fourcc == i_current_fourcc ) &&
1564                     mt_count < mt_max )
1565                 {
1566                     /* Pick match */
1567                     mt[mt_count++] = *p_mt;
1568                     i_fourcc = i_current_fourcc;
1569                 }
1570                 else FreeMediaType( *p_mt );
1571             }
1572             else
1573             {
1574                 char *psz_type = "unknown";
1575                 if( p_mt->majortype == MEDIATYPE_Video ) psz_type = "video";
1576                 if( p_mt->majortype == MEDIATYPE_Audio ) psz_type = "audio";
1577                 if( p_mt->majortype == MEDIATYPE_Stream ) psz_type = "stream";
1578                 msg_Dbg( p_this, "EnumDeviceCaps: input pin media: unsupported format "
1579                          "(%s %4.4s)", psz_type, (char *)&p_mt->subtype );
1580
1581                 FreeMediaType( *p_mt );
1582             }
1583             CoTaskMemFree( (PVOID)p_mt );
1584         }
1585
1586         if( !mt_count && p_enummt->Reset() == S_OK )
1587         {
1588             // VLC did not find any supported MEDIATYPE for this output pin.
1589             // However the graph builder might insert converter filters in
1590             // the graph if we use a different codec in VLC filter input pin.
1591             // however, in order to avoid nasty surprises, make use of this
1592             // facility only for known unsupported codecs.
1593
1594             while( !mt_count && p_enummt->Next( 1, &p_mt, NULL ) == S_OK )
1595             {
1596                 // the first four bytes of subtype GUID contains the codec FOURCC
1597                 const char *pfcc = (char *)&p_mt->subtype;
1598                 int i_current_fourcc = VLC_FOURCC(pfcc[0], pfcc[1], pfcc[2], pfcc[3]);
1599                 if( VLC_FOURCC('H','C','W','2') == i_current_fourcc
1600                  && p_mt->majortype == MEDIATYPE_Video )
1601                 {
1602                     // output format for 'Hauppauge WinTV PVR PCI II Capture'
1603                     // try I420 as an input format
1604                     i_current_fourcc = VLC_FOURCC('I','4','2','0');
1605                     if( !i_fourcc || i_fourcc == i_current_fourcc )
1606                     {
1607                         // return alternative media type
1608                         AM_MEDIA_TYPE mtr;
1609                         VIDEOINFOHEADER vh;
1610  
1611                         mtr.majortype            = MEDIATYPE_Video;
1612                         mtr.subtype              = MEDIASUBTYPE_I420;
1613                         mtr.bFixedSizeSamples    = TRUE;
1614                         mtr.bTemporalCompression = FALSE;
1615                         mtr.pUnk                 = NULL;
1616                         mtr.formattype           = FORMAT_VideoInfo;
1617                         mtr.cbFormat             = sizeof(vh);
1618                         mtr.pbFormat             = (BYTE *)&vh;
1619  
1620                         memset(&vh, 0, sizeof(vh));
1621  
1622                         vh.bmiHeader.biSize   = sizeof(vh.bmiHeader);
1623                         vh.bmiHeader.biWidth  = i_width > 0 ? i_width :
1624                             ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biWidth;
1625                         vh.bmiHeader.biHeight = i_height > 0 ? i_height :
1626                             ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biHeight;
1627                         vh.bmiHeader.biPlanes      = 3;
1628                         vh.bmiHeader.biBitCount    = 12;
1629                         vh.bmiHeader.biCompression = VLC_FOURCC('I','4','2','0');
1630                         vh.bmiHeader.biSizeImage   = vh.bmiHeader.biWidth * 12 *
1631                             vh.bmiHeader.biHeight / 8;
1632                         mtr.lSampleSize            = vh.bmiHeader.biSizeImage;
1633  
1634                         msg_Dbg( p_this, "EnumDeviceCaps: input pin media: using 'I420' in place of unsupported format 'HCW2'");
1635
1636                         if( SUCCEEDED(CopyMediaType(mt+mt_count, &mtr)) )
1637                             ++mt_count;
1638                     }
1639                 }
1640                 FreeMediaType( *p_mt );
1641             }
1642         }
1643
1644         p_enummt->Release();
1645         p_output_pin->Release();
1646     }
1647
1648     p_enumpins->Release();
1649     return mt_count;
1650 }
1651
1652 /*****************************************************************************
1653  * ReadCompressed: reads compressed (MPEG/DV) data from the device.
1654  *****************************************************************************
1655  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
1656  * bytes.
1657  *****************************************************************************/
1658 static block_t *ReadCompressed( access_t *p_access )
1659 {
1660     access_sys_t   *p_sys = p_access->p_sys;
1661     dshow_stream_t *p_stream = NULL;
1662     VLCMediaSample sample;
1663
1664     /* Read 1 DV/MPEG frame (they contain the video and audio data) */
1665
1666     /* There must be only 1 elementary stream to produce a valid stream
1667      * of MPEG or DV data */
1668     p_stream = p_sys->pp_streams[0];
1669
1670     while( 1 )
1671     {
1672         if( !vlc_object_alive (p_access) || p_access->b_error ) return 0;
1673
1674         /* Get new sample/frame from the elementary stream (blocking). */
1675         vlc_mutex_lock( &p_sys->lock );
1676
1677         if( p_stream->p_capture_filter->CustomGetPin()
1678               ->CustomGetSample( &sample ) != S_OK )
1679         {
1680             /* No data available. Wait until some data has arrived */
1681             vlc_cond_wait( &p_sys->wait, &p_sys->lock );
1682             vlc_mutex_unlock( &p_sys->lock );
1683             continue;
1684         }
1685
1686         vlc_mutex_unlock( &p_sys->lock );
1687
1688         /*
1689          * We got our sample
1690          */
1691         block_t *p_block;
1692         uint8_t *p_data;
1693         int i_data_size = sample.p_sample->GetActualDataLength();
1694
1695         if( !i_data_size || !(p_block = block_New( p_access, i_data_size )) )
1696         {
1697             sample.p_sample->Release();
1698             continue;
1699         }
1700
1701         sample.p_sample->GetPointer( &p_data );
1702         vlc_memcpy( p_block->p_buffer, p_data, i_data_size );
1703         sample.p_sample->Release();
1704
1705         /* The caller got what he wanted */
1706         return p_block;
1707     }
1708
1709     return NULL; /* never reached */
1710 }
1711
1712 /****************************************************************************
1713  * Demux:
1714  ****************************************************************************/
1715 static int Demux( demux_t *p_demux )
1716 {
1717     access_sys_t *p_sys = (access_sys_t *)p_demux->p_sys;
1718     int i_stream;
1719     int i_found_samples;
1720
1721     i_found_samples = 0;
1722     vlc_mutex_lock( &p_sys->lock );
1723
1724     while ( !i_found_samples )
1725     {
1726         /* Try to grab samples from all streams */
1727         for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
1728         {
1729             dshow_stream_t *p_stream = p_sys->pp_streams[i_stream];
1730             if( p_stream->p_capture_filter &&
1731                 p_stream->p_capture_filter->CustomGetPin()
1732                 ->CustomGetSamples( p_stream->samples_queue ) == S_OK )
1733             {
1734                 i_found_samples = 1;
1735             }
1736         }
1737
1738         if ( !i_found_samples)
1739         {
1740             /* Didn't find any audio nor video sample, just wait till the
1741              * dshow thread pushes some samples */
1742             vlc_cond_wait( &p_sys->wait, &p_sys->lock );
1743             /* Some DShow thread pushed data, or the OS broke the wait all
1744              * by itself. In all cases, it's *strongly* advised to test the
1745              * condition again, so let the loop do the test again */
1746         }
1747     }
1748
1749     vlc_mutex_unlock( &p_sys->lock );
1750
1751     for ( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
1752     {
1753         int i_samples;
1754         dshow_stream_t *p_stream = p_sys->pp_streams[i_stream];
1755
1756         i_samples = p_stream->samples_queue.size();
1757         while ( i_samples > 0 )
1758         {
1759             int i_data_size;
1760             uint8_t *p_data;
1761             block_t *p_block;
1762             VLCMediaSample sample;
1763
1764             sample = p_stream->samples_queue.front();
1765             p_stream->samples_queue.pop_front();
1766
1767             i_data_size = sample.p_sample->GetActualDataLength();
1768             sample.p_sample->GetPointer( &p_data );
1769
1770             REFERENCE_TIME i_pts, i_end_date;
1771             HRESULT hr = sample.p_sample->GetTime( &i_pts, &i_end_date );
1772             if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
1773
1774             if( !i_pts )
1775             {
1776                 if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
1777                 {
1778                     /* Use our data timestamp */
1779                     i_pts = sample.i_timestamp;
1780                     p_stream->b_pts = true;
1781                 }
1782             }
1783
1784             i_pts /= 10; /* Dshow works with 100 nano-seconds resolution */
1785
1786 #if 0
1787             msg_Dbg( p_demux, "Read() stream: %i, size: %i, PTS: %"PRId64,
1788                      i_stream, i_data_size, i_pts );
1789 #endif
1790
1791             p_block = block_New( p_demux, i_data_size );
1792             vlc_memcpy( p_block->p_buffer, p_data, i_data_size );
1793             p_block->i_pts = p_block->i_dts = i_pts;
1794             sample.p_sample->Release();
1795
1796             es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_pts > 0 ? i_pts : 0 );
1797             es_out_Send( p_demux->out, p_stream->p_es, p_block );
1798
1799             i_samples--;
1800         }
1801     }
1802
1803     return 1;
1804 }
1805
1806 /*****************************************************************************
1807  * AccessControl:
1808  *****************************************************************************/
1809 static int AccessControl( access_t *p_access, int i_query, va_list args )
1810 {
1811     bool   *pb_bool;
1812     int          *pi_int;
1813     int64_t      *pi_64;
1814
1815     switch( i_query )
1816     {
1817     /* */
1818     case ACCESS_CAN_SEEK:
1819     case ACCESS_CAN_FASTSEEK:
1820     case ACCESS_CAN_PAUSE:
1821     case ACCESS_CAN_CONTROL_PACE:
1822         pb_bool = (bool*)va_arg( args, bool* );
1823         *pb_bool = false;
1824         break;
1825
1826     /* */
1827     case ACCESS_GET_PTS_DELAY:
1828         pi_64 = (int64_t*)va_arg( args, int64_t * );
1829         *pi_64 = (int64_t)var_GetInteger( p_access, "dshow-caching" ) * 1000;
1830         break;
1831
1832     /* */
1833     case ACCESS_SET_PAUSE_STATE:
1834     case ACCESS_GET_TITLE_INFO:
1835     case ACCESS_SET_TITLE:
1836     case ACCESS_SET_SEEKPOINT:
1837     case ACCESS_SET_PRIVATE_ID_STATE:
1838         return VLC_EGENERIC;
1839
1840     default:
1841         msg_Warn( p_access, "unimplemented query in control" );
1842         return VLC_EGENERIC;
1843     }
1844
1845     return VLC_SUCCESS;
1846 }
1847
1848 /****************************************************************************
1849  * DemuxControl:
1850  ****************************************************************************/
1851 static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
1852 {
1853     bool *pb;
1854     int64_t    *pi64;
1855
1856     switch( i_query )
1857     {
1858     /* Special for access_demux */
1859     case DEMUX_CAN_PAUSE:
1860     case DEMUX_CAN_SEEK:
1861     case DEMUX_SET_PAUSE_STATE:
1862     case DEMUX_CAN_CONTROL_PACE:
1863         pb = (bool*)va_arg( args, bool * );
1864         *pb = false;
1865         return VLC_SUCCESS;
1866
1867     case DEMUX_GET_PTS_DELAY:
1868         pi64 = (int64_t*)va_arg( args, int64_t * );
1869         *pi64 = (int64_t)var_GetInteger( p_demux, "dshow-caching" ) * 1000;
1870         return VLC_SUCCESS;
1871
1872     case DEMUX_GET_TIME:
1873         pi64 = (int64_t*)va_arg( args, int64_t * );
1874         *pi64 = mdate();
1875         return VLC_SUCCESS;
1876
1877     /* TODO implement others */
1878     default:
1879         return VLC_EGENERIC;
1880     }
1881
1882     return VLC_EGENERIC;
1883 }
1884
1885 /*****************************************************************************
1886  * config variable callback
1887  *****************************************************************************/
1888 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
1889                                vlc_value_t newval, vlc_value_t oldval, void * )
1890 {
1891     module_config_t *p_item;
1892     bool b_audio = false;
1893     int i;
1894
1895     p_item = config_FindConfig( p_this, psz_name );
1896     if( !p_item ) return VLC_SUCCESS;
1897
1898     if( !strcmp( psz_name, "dshow-adev" ) ) b_audio = true;
1899
1900     /* Clear-up the current list */
1901     if( p_item->i_list )
1902     {
1903         /* Keep the 2 first entries */
1904         for( i = 2; i < p_item->i_list; i++ )
1905         {
1906             free( const_cast<char *>(p_item->ppsz_list[i]) );
1907             free( const_cast<char *>(p_item->ppsz_list_text[i]) );
1908         }
1909         /* TODO: Remove when no more needed */
1910         p_item->ppsz_list[i] = NULL;
1911         p_item->ppsz_list_text[i] = NULL;
1912     }
1913     p_item->i_list = 2;
1914
1915     /* Find list of devices */
1916     list<string> list_devices;
1917
1918     /* Initialize OLE/COM */
1919     CoInitialize( 0 );
1920
1921     FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
1922
1923     /* Uninitialize OLE/COM */
1924     CoUninitialize();
1925
1926     if( !list_devices.size() ) return VLC_SUCCESS;
1927
1928     p_item->ppsz_list =
1929         (char **)realloc( p_item->ppsz_list,
1930                           (list_devices.size()+3) * sizeof(char *) );
1931     p_item->ppsz_list_text =
1932         (char **)realloc( p_item->ppsz_list_text,
1933                           (list_devices.size()+3) * sizeof(char *) );
1934
1935     list<string>::iterator iter;
1936     for( iter = list_devices.begin(), i = 2; iter != list_devices.end();
1937          iter++, i++ )
1938     {
1939         p_item->ppsz_list[i] = strdup( iter->c_str() );
1940         p_item->ppsz_list_text[i] = NULL;
1941         p_item->i_list++;
1942     }
1943     p_item->ppsz_list[i] = NULL;
1944     p_item->ppsz_list_text[i] = NULL;
1945
1946     /* Signal change to the interface */
1947     p_item->b_dirty = true;
1948
1949     return VLC_SUCCESS;
1950 }
1951
1952 static int ConfigDevicesCallback( vlc_object_t *p_this, char const *psz_name,
1953                                vlc_value_t newval, vlc_value_t oldval, void * )
1954 {
1955     module_config_t *p_item;
1956     bool b_audio = false;
1957
1958     /* Initialize OLE/COM */
1959     CoInitialize( 0 );
1960
1961     p_item = config_FindConfig( p_this, psz_name );
1962     if( !p_item ) return VLC_SUCCESS;
1963
1964     if( !strcmp( psz_name, "dshow-adev" ) ) b_audio = true;
1965
1966     string devicename;
1967
1968     if( newval.psz_string && *newval.psz_string )
1969     {
1970         devicename = newval.psz_string;
1971     }
1972     else
1973     {
1974         /* If no device name was specified, pick the 1st one */
1975         list<string> list_devices;
1976
1977         /* Enumerate devices */
1978         FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
1979         if( !list_devices.size() ) return VLC_EGENERIC;
1980         devicename = *list_devices.begin();
1981     }
1982
1983     IBaseFilter *p_device_filter =
1984         FindCaptureDevice( p_this, &devicename, NULL, b_audio );
1985     if( p_device_filter )
1986     {
1987         ShowPropertyPage( p_device_filter );
1988         p_device_filter->Release();
1989     }
1990     else
1991     {
1992         /* Uninitialize OLE/COM */
1993         CoUninitialize();
1994
1995         msg_Err( p_this, "didn't find device: %s", devicename.c_str() );
1996         return VLC_EGENERIC;
1997     }
1998
1999     /* Uninitialize OLE/COM */
2000     CoUninitialize();
2001
2002     return VLC_SUCCESS;
2003 }
2004
2005 /*****************************************************************************
2006  * Properties
2007  *****************************************************************************/
2008 static void ShowPropertyPage( IUnknown *obj )
2009 {
2010     ISpecifyPropertyPages *p_spec;
2011     CAUUID cauuid;
2012
2013     HRESULT hr = obj->QueryInterface( IID_ISpecifyPropertyPages,
2014                                       (void **)&p_spec );
2015     if( FAILED(hr) ) return;
2016
2017     if( SUCCEEDED(p_spec->GetPages( &cauuid )) )
2018     {
2019         if( cauuid.cElems > 0 )
2020         {
2021             HWND hwnd_desktop = ::GetDesktopWindow();
2022
2023             OleCreatePropertyFrame( hwnd_desktop, 30, 30, NULL, 1, &obj,
2024                                     cauuid.cElems, cauuid.pElems, 0, 0, NULL );
2025
2026             CoTaskMemFree( cauuid.pElems );
2027         }
2028         p_spec->Release();
2029     }
2030 }
2031
2032 static void ShowDeviceProperties( vlc_object_t *p_this,
2033                                   ICaptureGraphBuilder2 *p_graph,
2034                                   IBaseFilter *p_device_filter,
2035                                   bool b_audio )
2036 {
2037     HRESULT hr;
2038     msg_Dbg( p_this, "configuring Device Properties" );
2039
2040     /*
2041      * Video or audio capture filter page
2042      */
2043     ShowPropertyPage( p_device_filter );
2044
2045     /*
2046      * Audio capture pin
2047      */
2048     if( p_graph && b_audio )
2049     {
2050         IAMStreamConfig *p_SC;
2051
2052         msg_Dbg( p_this, "showing WDM Audio Configuration Pages" );
2053
2054         hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2055                                      &MEDIATYPE_Audio, p_device_filter,
2056                                      IID_IAMStreamConfig, (void **)&p_SC );
2057         if( SUCCEEDED(hr) )
2058         {
2059             ShowPropertyPage(p_SC);
2060             p_SC->Release();
2061         }
2062
2063         /*
2064          * TV Audio filter
2065          */
2066         IAMTVAudio *p_TVA;
2067         HRESULT hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2068                                              &MEDIATYPE_Audio, p_device_filter,
2069                                              IID_IAMTVAudio, (void **)&p_TVA );
2070         if( SUCCEEDED(hr) )
2071         {
2072             ShowPropertyPage(p_TVA);
2073             p_TVA->Release();
2074         }
2075     }
2076
2077     /*
2078      * Video capture pin
2079      */
2080     if( p_graph && !b_audio )
2081     {
2082         IAMStreamConfig *p_SC;
2083
2084         msg_Dbg( p_this, "showing WDM Video Configuration Pages" );
2085
2086         hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2087                                      &MEDIATYPE_Interleaved, p_device_filter,
2088                                      IID_IAMStreamConfig, (void **)&p_SC );
2089         if( FAILED(hr) )
2090         {
2091             hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2092                                          &MEDIATYPE_Video, p_device_filter,
2093                                          IID_IAMStreamConfig, (void **)&p_SC );
2094         }
2095
2096         if( FAILED(hr) )
2097         {
2098             hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2099                                          &MEDIATYPE_Stream, p_device_filter,
2100                                          IID_IAMStreamConfig, (void **)&p_SC );
2101         }
2102
2103         if( SUCCEEDED(hr) )
2104         {
2105             ShowPropertyPage(p_SC);
2106             p_SC->Release();
2107         }
2108     }
2109 }
2110
2111 static void ShowTunerProperties( vlc_object_t *p_this,
2112                                  ICaptureGraphBuilder2 *p_graph,
2113                                  IBaseFilter *p_device_filter,
2114                                  bool b_audio )
2115 {
2116     HRESULT hr;
2117     msg_Dbg( p_this, "configuring Tuner Properties" );
2118
2119     if( !p_graph || b_audio ) return;
2120
2121     IAMTVTuner *p_TV;
2122     hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2123                                  &MEDIATYPE_Interleaved, p_device_filter,
2124                                  IID_IAMTVTuner, (void **)&p_TV );
2125     if( FAILED(hr) )
2126     {
2127         hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2128                                      &MEDIATYPE_Video, p_device_filter,
2129                                      IID_IAMTVTuner, (void **)&p_TV );
2130     }
2131
2132     if( FAILED(hr) )
2133     {
2134         hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE,
2135                                      &MEDIATYPE_Stream, p_device_filter,
2136                                      IID_IAMTVTuner, (void **)&p_TV );
2137     }
2138
2139     if( SUCCEEDED(hr) )
2140     {
2141         ShowPropertyPage(p_TV);
2142         p_TV->Release();
2143     }
2144 }
2145
2146 static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph,
2147                          IBaseFilter *p_device_filter )
2148 {
2149     int i_channel, i_country, i_input, i_amtuner_mode;
2150     long l_modes = 0;
2151     IAMTVTuner *p_TV;
2152     HRESULT hr;
2153
2154     if( !p_graph ) return;
2155
2156     i_channel = var_GetInteger( p_this, "dshow-tuner-channel" );
2157     i_country = var_GetInteger( p_this, "dshow-tuner-country" );
2158     i_input = var_GetInteger( p_this, "dshow-tuner-input" );
2159     i_amtuner_mode = var_GetInteger( p_this, "dshow-amtuner-mode" );
2160
2161     if( !i_channel && !i_country && !i_input ) return; /* Nothing to do */
2162
2163     msg_Dbg( p_this, "tuner config: channel %i, country %i, input type %i",
2164              i_channel, i_country, i_input );
2165
2166     hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved,
2167                                  p_device_filter, IID_IAMTVTuner,
2168                                  (void **)&p_TV );
2169     if( FAILED(hr) )
2170     {
2171         hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
2172                                      p_device_filter, IID_IAMTVTuner,
2173                                      (void **)&p_TV );
2174     }
2175
2176     if( FAILED(hr) )
2177     {
2178         hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Stream,
2179                                      p_device_filter, IID_IAMTVTuner,
2180                                      (void **)&p_TV );
2181     }
2182
2183     if( FAILED(hr) )
2184     {
2185         msg_Dbg( p_this, "couldn't find tuner interface" );
2186         return;
2187     }
2188
2189     hr = p_TV->GetAvailableModes( &l_modes );
2190     if( SUCCEEDED(hr) && (l_modes & i_amtuner_mode) )
2191     {
2192         hr = p_TV->put_Mode( (AMTunerModeType)i_amtuner_mode );
2193     }
2194
2195     if( i_input == 1 ) p_TV->put_InputType( 0, TunerInputCable );
2196     else if( i_input == 2 ) p_TV->put_InputType( 0, TunerInputAntenna );
2197
2198     p_TV->put_CountryCode( i_country );
2199     p_TV->put_Channel( i_channel, AMTUNER_SUBCHAN_NO_TUNE,
2200                        AMTUNER_SUBCHAN_NO_TUNE );
2201     p_TV->Release();
2202 }