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