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