]> git.sesse.net Git - vlc/blob - modules/access/dshow/dshow.cpp
* dshow: ported to es_out_* and stream_*. Not tested (sorry).
[vlc] / modules / access / dshow / dshow.cpp
1 /*****************************************************************************
2  * dshow.cpp : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: dshow.cpp,v 1.15 2003/11/24 19:30:54 fenrir Exp $
6  *
7  * Author: Gildas Bazin <gbazin@netcourrier.com>
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  * Module descriptor
39  *****************************************************************************/
40 static char *ppsz_vdev[] = { "", "none" };
41 static char *ppsz_vdev_text[] = { N_("Default"), N_("None") };
42 static char *ppsz_adev[] = { "", "none" };
43 static char *ppsz_adev_text[] = { N_("Default"), N_("None") };
44
45 #define CACHING_TEXT N_("Caching value in ms")
46 #define CACHING_LONGTEXT N_( \
47     "Allows you to modify the default caching value for directshow streams. " \
48     "This value should be set in miliseconds units." )
49 #define VDEV_TEXT N_("Video device name")
50 #define VDEV_LONGTEXT N_( \
51     "You can specify the name of the video device that will be used by the " \
52     "DirectShow plugin. If you don't specify anything, the default device " \
53     "will be used.")
54 #define ADEV_TEXT N_("Audio device name")
55 #define ADEV_LONGTEXT N_( \
56     "You can specify the name of the audio device that will be used by the " \
57     "DirectShow plugin. If you don't specify anything, the default device " \
58     "will be used.")
59 #define SIZE_TEXT N_("Video size")
60 #define SIZE_LONGTEXT N_( \
61     "You can specify the size of the video that will be displayed by the " \
62     "DirectShow plugin. If you don't specify anything the default size for " \
63     "your device will be used.")
64 #define CHROMA_TEXT N_("Video input chroma format")
65 #define CHROMA_LONGTEXT N_( \
66     "Force the DirectShow video input to use a specific chroma format " \
67     "(eg. I420 (default), RV24, etc...)")
68
69 static int  AccessOpen ( vlc_object_t * );
70 static void AccessClose( vlc_object_t * );
71
72 static int  DemuxOpen  ( vlc_object_t * );
73 static void DemuxClose ( vlc_object_t * );
74
75 vlc_module_begin();
76     set_description( _("DirectShow input") );
77     add_category_hint( N_("dshow"), NULL, VLC_TRUE );
78     add_integer( "dshow-caching", (mtime_t)(0.2*CLOCK_FREQ) / 1000, NULL,
79                  CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
80
81     add_string( "dshow-vdev", NULL, NULL, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE);
82         change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback );
83
84     add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE);
85         change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback );
86
87     add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE);
88
89     add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
90                 VLC_TRUE );
91     add_shortcut( "dshow" );
92     set_capability( "access", 0 );
93     set_callbacks( AccessOpen, AccessClose );
94
95     add_submodule();
96     set_description( _("DirectShow demuxer") );
97     add_shortcut( "dshow" );
98     set_capability( "demux", 200 );
99     set_callbacks( DemuxOpen, DemuxClose );
100
101 vlc_module_end();
102
103
104 /*****************************************************************************
105  * Access: local prototypes
106  *****************************************************************************/
107 static ssize_t Read        ( input_thread_t *, byte_t *, size_t );
108 static ssize_t ReadDV      ( input_thread_t *, byte_t *, size_t );
109
110 static int OpenDevice( input_thread_t *, string, vlc_bool_t );
111 static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
112                                        list<string> *, vlc_bool_t );
113 static AM_MEDIA_TYPE EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
114                                      int, int, int, int, int, int );
115 static bool ConnectFilters( IFilterGraph *, IBaseFilter *, IPin * );
116
117 static int FindDevicesCallback( vlc_object_t *, char const *,
118                                 vlc_value_t, vlc_value_t, void * );
119 #if 0
120     /* Debug only, use this to find out GUIDs */
121     unsigned char p_st[];
122     UuidToString( (IID *)&IID_IAMBufferNegotiation, &p_st );
123     msg_Err( p_input, "BufferNegotiation: %s" , p_st );
124 #endif
125
126 /*
127  * header:
128  *  fcc  ".dsh"
129  *  u32    stream count
130  *      fcc "auds"|"vids"       0
131  *      fcc codec               4
132  *      if vids
133  *          u32 width           8
134  *          u32 height          12
135  *          u32 padding         16
136  *      if auds
137  *          u32 channels        12
138  *          u32 samplerate      8
139  *          u32 samplesize      16
140  *
141  * data:
142  *  u32     stream number
143  *  u32     data size
144  *  u8      data
145  */
146
147 static void SetDWBE( uint8_t *p, uint32_t dw )
148 {
149     p[0] = (dw >> 24)&0xff;
150     p[1] = (dw >> 16)&0xff;
151     p[2] = (dw >>  8)&0xff;
152     p[3] = (dw      )&0xff;
153 }
154
155 static void SetQWBE( uint8_t *p, uint64_t qw )
156 {
157     SetDWBE( p, (qw >> 32)&0xffffffff );
158     SetDWBE( &p[4], qw&0xffffffff );
159 }
160
161 /****************************************************************************
162  * DirectShow elementary stream descriptor
163  ****************************************************************************/
164 typedef struct dshow_stream_t
165 {
166     string          devicename;
167     IBaseFilter     *p_device_filter;
168     CaptureFilter   *p_capture_filter;
169     AM_MEDIA_TYPE   mt;
170     int             i_fourcc;
171     vlc_bool_t      b_invert;
172
173     union
174     {
175       VIDEOINFOHEADER video;
176       WAVEFORMATEX    audio;
177
178     } header;
179
180     vlc_bool_t      b_pts;
181
182 } dshow_stream_t;
183
184 /****************************************************************************
185  * Access descriptor declaration
186  ****************************************************************************/
187 struct access_sys_t
188 {
189     vlc_mutex_t lock;
190     vlc_cond_t  wait;
191
192     IFilterGraph  *p_graph;
193     IMediaControl *p_control;
194
195     /* header */
196     int     i_header_size;
197     int     i_header_pos;
198     uint8_t *p_header;
199
200     /* list of elementary streams */
201     dshow_stream_t **pp_streams;
202     int            i_streams;
203     int            i_current_stream;
204
205     /* misc properties */
206     int            i_width;
207     int            i_height;
208     int            i_chroma;
209 };
210
211 /*****************************************************************************
212  * Open: open direct show device
213  *****************************************************************************/
214 static int AccessOpen( vlc_object_t *p_this )
215 {
216     input_thread_t *p_input = (input_thread_t *)p_this;
217     access_sys_t   *p_sys;
218     vlc_value_t    val;
219
220     /* Get/parse options and open device(s) */
221     string vdevname, adevname;
222     int i_width = 0, i_height = 0, i_chroma = VLC_FOURCC('I','4','2','0');
223
224     var_Create( p_input, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
225     var_Get( p_input, "dshow-vdev", &val );
226     if( val.psz_string ) vdevname = string( val.psz_string );
227     if( val.psz_string ) free( val.psz_string );
228
229     var_Create( p_input, "dshow-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
230     var_Get( p_input, "dshow-adev", &val );
231     if( val.psz_string ) adevname = string( val.psz_string );
232     if( val.psz_string ) free( val.psz_string );
233
234     var_Create( p_input, "dshow-size", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
235     var_Get( p_input, "dshow-size", &val );
236     if( val.psz_string && *val.psz_string )
237     {
238         if( !strcmp( val.psz_string, "subqcif" ) )
239         {
240             i_width  = 128; i_height = 96;
241         }
242         else if( !strcmp( val.psz_string, "qsif" ) )
243         {
244             i_width  = 160; i_height = 120;
245         }
246         else if( !strcmp( val.psz_string, "qcif" ) )
247         {
248             i_width  = 176; i_height = 144;
249         }
250         else if( !strcmp( val.psz_string, "sif" ) )
251         {
252             i_width  = 320; i_height = 240;
253         }
254         else if( !strcmp( val.psz_string, "cif" ) )
255         {
256             i_width  = 352; i_height = 288;
257         }
258         else if( !strcmp( val.psz_string, "vga" ) )
259         {
260             i_width  = 640; i_height = 480;
261         }
262         else
263         {
264             /* Width x Height */
265             char *psz_parser;
266             i_width = strtol( val.psz_string, &psz_parser, 0 );
267             if( *psz_parser == 'x' || *psz_parser == 'X')
268             {
269                 i_height = strtol( psz_parser + 1, &psz_parser, 0 );
270             }
271             msg_Dbg( p_input, "Width x Height %dx%d", i_width, i_height );
272         }
273     }
274     if( val.psz_string ) free( val.psz_string );
275
276     var_Create( p_input, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
277     var_Get( p_input, "dshow-chroma", &val );
278     if( val.psz_string && strlen( val.psz_string ) >= 4 )
279     {
280         i_chroma = VLC_FOURCC( val.psz_string[0], val.psz_string[1],
281                                val.psz_string[2], val.psz_string[3] );
282     }
283     if( val.psz_string ) free( val.psz_string );
284
285     p_input->pf_read        = Read;
286     p_input->pf_seek        = NULL;
287     p_input->pf_set_area    = NULL;
288     p_input->pf_set_program = NULL;
289
290     vlc_mutex_lock( &p_input->stream.stream_lock );
291     p_input->stream.b_pace_control = 0;
292     p_input->stream.b_seekable = 0;
293     p_input->stream.p_selected_area->i_size = 0;
294     p_input->stream.p_selected_area->i_tell = 0;
295     p_input->stream.i_method = INPUT_METHOD_FILE;
296     vlc_mutex_unlock( &p_input->stream.stream_lock );
297
298     var_Create( p_input, "dshow-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
299     var_Get( p_input, "dshow-caching", &val );
300     p_input->i_pts_delay = val.i_int * 1000;
301
302     /* Initialize OLE/COM */
303     CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
304
305     /* create access private data */
306     p_input->p_access_data = p_sys =
307         (access_sys_t *)malloc( sizeof( access_sys_t ) );
308
309     /* Initialize some data */
310     p_sys->i_streams = 0;
311     p_sys->pp_streams = (dshow_stream_t **)malloc( 1 );
312     p_sys->i_width = i_width;
313     p_sys->i_height = i_height;
314     p_sys->i_chroma = i_chroma;
315
316     /* Create header */
317     p_sys->i_header_size = 8;
318     p_sys->p_header      = (uint8_t *)malloc( p_sys->i_header_size );
319     memcpy(  &p_sys->p_header[0], ".dsh", 4 );
320     SetDWBE( &p_sys->p_header[4], 1 );
321     p_sys->i_header_pos = p_sys->i_header_size;
322
323     /* Build directshow graph */
324     CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
325                       (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
326
327     p_sys->p_graph->QueryInterface( IID_IMediaControl,
328                                     (void **)&p_sys->p_control );
329
330     if( OpenDevice( p_input, vdevname, 0 ) != VLC_SUCCESS )
331     {
332         msg_Err( p_input, "can't open video");
333     }
334
335     if( OpenDevice( p_input, adevname, 1 ) != VLC_SUCCESS )
336     {
337         msg_Err( p_input, "can't open audio");
338     }
339
340     if( !p_sys->i_streams )
341     {
342         /* Release directshow objects */
343         if( p_sys->p_control ) p_sys->p_control->Release();
344         p_sys->p_graph->Release();
345
346         /* Uninitialize OLE/COM */
347         CoUninitialize();
348
349         free( p_sys->p_header );
350         free( p_sys->pp_streams );
351         free( p_sys );
352         return VLC_EGENERIC;
353     }
354
355     /* Initialize some data */
356     p_sys->i_current_stream = 0;
357     p_input->i_mtu += p_sys->i_header_size + 16 /* data header size */;
358
359     vlc_mutex_init( p_input, &p_sys->lock );
360     vlc_cond_init( p_input, &p_sys->wait );
361
362     /* Everything is ready. Let's rock baby */
363     p_sys->p_control->Run();
364
365     return VLC_SUCCESS;
366 }
367
368 /*****************************************************************************
369  * AccessClose: close device
370  *****************************************************************************/
371 static void AccessClose( vlc_object_t *p_this )
372 {
373     input_thread_t *p_input = (input_thread_t *)p_this;
374     access_sys_t    *p_sys  = p_input->p_access_data;
375
376     /* Stop capturing stuff */
377     p_sys->p_control->Stop();
378     p_sys->p_control->Release();
379
380     /* Remove filters from graph */
381     for( int i = 0; i < p_sys->i_streams; i++ )
382     {
383         p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );
384         p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );
385         p_sys->pp_streams[i]->p_capture_filter->Release();
386         p_sys->pp_streams[i]->p_device_filter->Release();
387     }
388     p_sys->p_graph->Release();
389
390     /* Uninitialize OLE/COM */
391     CoUninitialize();
392
393     free( p_sys->p_header );
394     for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];
395     free( p_sys->pp_streams );
396     free( p_sys );
397 }
398
399 /****************************************************************************
400  * ConnectFilters
401  ****************************************************************************/
402 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
403                             IPin *p_input_pin )
404 {
405     IEnumPins *p_enumpins;
406     IPin *p_output_pin;
407     ULONG i_fetched;
408
409     if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
410
411     while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
412     {
413         if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
414         {
415             p_enumpins->Release();
416             return true;
417         }
418     }
419
420     p_enumpins->Release();
421     return false;
422 }
423
424 static int OpenDevice( input_thread_t *p_input, string devicename,
425                        vlc_bool_t b_audio )
426 {
427     access_sys_t *p_sys = p_input->p_access_data;
428     list<string> list_devices;
429
430     /* Enumerate devices and display their names */
431     FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );
432
433     if( !list_devices.size() )
434         return VLC_EGENERIC;
435
436     list<string>::iterator iter;
437     for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
438         msg_Dbg( p_input, "found device: %s", iter->c_str() );
439
440     /* If no device name was specified, pick the 1st one */
441     if( devicename.size() == 0 )
442     {
443         devicename = *list_devices.begin();
444     }
445
446     // Use the system device enumerator and class enumerator to find
447     // a capture/preview device, such as a desktop USB video camera.
448     IBaseFilter *p_device_filter =
449         FindCaptureDevice( (vlc_object_t *)p_input, &devicename,
450                            NULL, b_audio );
451     if( p_device_filter )
452         msg_Dbg( p_input, "using device: %s", devicename.c_str() );
453     else
454     {
455         msg_Err( p_input, "can't use device: %s", devicename.c_str() );
456         return VLC_EGENERIC;
457     }
458
459     AM_MEDIA_TYPE media_type =
460         EnumDeviceCaps( (vlc_object_t *)p_input, p_device_filter,
461                         p_sys->i_chroma, p_sys->i_width, p_sys->i_height,
462                         0, 0, 0 );
463
464     /* Create and add our capture filter */
465     CaptureFilter *p_capture_filter = new CaptureFilter( p_input, media_type );
466     p_sys->p_graph->AddFilter( p_capture_filter, 0 );
467
468     /* Add the device filter to the graph (seems necessary with VfW before
469      * accessing pin attributes). */
470     p_sys->p_graph->AddFilter( p_device_filter, 0 );
471
472     /* Attempt to connect one of this device's capture output pins */
473     msg_Dbg( p_input, "connecting filters" );
474     if( ConnectFilters( p_sys->p_graph, p_device_filter,
475                         p_capture_filter->CustomGetPin() ) )
476     {
477         /* Success */
478         dshow_stream_t dshow_stream;
479         dshow_stream.b_invert = VLC_FALSE;
480         dshow_stream.b_pts = VLC_FALSE;
481         dshow_stream.mt =
482             p_capture_filter->CustomGetPin()->CustomGetMediaType();
483
484         if( dshow_stream.mt.majortype == MEDIATYPE_Video )
485         {
486             msg_Dbg( p_input, "MEDIATYPE_Video");
487
488             /* Packed RGB formats */
489             if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB1 )
490                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
491             if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB4 )
492                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
493             if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB8 )
494                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
495             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB555 )
496                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
497             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB565 )
498                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
499             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB24 )
500                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
501             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB32 )
502                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
503             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_ARGB32 )
504                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
505
506             /* Packed YUV formats */
507             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVYU )
508                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
509             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUYV )
510                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
511             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )
512                 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
513             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y211 )
514                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', '2', '1', '1' );
515             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUY2 ||
516                      dshow_stream.mt.subtype == MEDIASUBTYPE_UYVY )
517                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
518
519             /* Planar YUV formats */
520             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_I420 )
521                 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
522             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y41P )
523                 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
524             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YV12 ||
525                      dshow_stream.mt.subtype == MEDIASUBTYPE_IYUV )
526                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
527             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVU9 )
528                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'U', '9' );
529
530             /* DV formats */
531             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_dvsl )
532                 dshow_stream.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
533             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_dvsd )
534                 dshow_stream.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'd' );
535             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_dvhd )
536                 dshow_stream.i_fourcc = VLC_FOURCC( 'd', 'v', 'h', 'd' );
537
538             else goto fail;
539
540             dshow_stream.header.video =
541                 *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
542
543             int i_height = dshow_stream.header.video.bmiHeader.biHeight;
544
545             /* Check if the image is inverted (bottom to top) */
546             if( dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', '1' ) ||
547                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', '4' ) ||
548                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', '8' ) ||
549                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '1', '5' ) ||
550                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '1', '6' ) ||
551                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '2', '4' ) ||
552                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '3', '2' ) ||
553                 dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', 'A' ) )
554             {
555                 if( i_height > 0 ) dshow_stream.b_invert = VLC_TRUE;
556                 else i_height = - i_height;
557             }
558
559             /* Check if we are dealing with a DV stream */
560             if( dshow_stream.i_fourcc == VLC_FOURCC( 'd', 'v', 's', 'l' ) ||
561                 dshow_stream.i_fourcc == VLC_FOURCC( 'd', 'v', 's', 'd' ) ||
562                 dshow_stream.i_fourcc == VLC_FOURCC( 'd', 'v', 'h', 'd' ) )
563             {
564                 p_input->pf_read = ReadDV;
565                 if( !p_input->psz_demux || !*p_input->psz_demux )
566                 {
567                     p_input->psz_demux = "rawdv";
568                 }
569             }
570
571
572             /* Add video stream to header */
573             p_sys->i_header_size += 20;
574             p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
575                                                   p_sys->i_header_size );
576             memcpy(  &p_sys->p_header[p_sys->i_header_pos], "vids", 4 );
577             memcpy(  &p_sys->p_header[p_sys->i_header_pos + 4],
578                      &dshow_stream.i_fourcc, 4 );
579             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
580                      dshow_stream.header.video.bmiHeader.biWidth );
581             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12], i_height );
582             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16], 0 );
583             p_sys->i_header_pos = p_sys->i_header_size;
584
585             /* Greatly simplifies the reading routine */
586             int i_mtu = dshow_stream.header.video.bmiHeader.biWidth *
587                 dshow_stream.header.video.bmiHeader.biHeight * 4;
588             p_input->i_mtu = __MAX(p_input->i_mtu,i_mtu);
589         }
590
591         else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&
592                  dshow_stream.mt.formattype == FORMAT_WaveFormatEx )
593         {
594             msg_Dbg( p_input, "MEDIATYPE_Audio");
595
596             if( dshow_stream.mt.subtype == MEDIASUBTYPE_PCM )
597                 dshow_stream.i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
598             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_IEEE_FLOAT )
599                 dshow_stream.i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );
600             else goto fail;
601
602             dshow_stream.header.audio =
603                 *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
604
605             /* Add audio stream to header */
606             p_sys->i_header_size += 20;
607             p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
608                                                   p_sys->i_header_size );
609             memcpy(  &p_sys->p_header[p_sys->i_header_pos], "auds", 4 );
610             memcpy(  &p_sys->p_header[p_sys->i_header_pos + 4],
611                      &dshow_stream.i_fourcc, 4 );
612             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
613                      dshow_stream.header.audio.nChannels );
614             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],
615                      dshow_stream.header.audio.nSamplesPerSec );
616             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16],
617                      dshow_stream.header.audio.wBitsPerSample );
618             p_sys->i_header_pos = p_sys->i_header_size;
619
620             /* Greatly simplifies the reading routine */
621             IAMBufferNegotiation *p_ambuf;
622             IPin *p_pin;
623             int i_mtu;
624
625             p_capture_filter->CustomGetPin()->ConnectedTo( &p_pin );
626             if( SUCCEEDED( p_pin->QueryInterface(
627                   IID_IAMBufferNegotiation, (void **)&p_ambuf ) ) )
628             {
629                 ALLOCATOR_PROPERTIES AllocProp;
630                 memset( &AllocProp, 0, sizeof( ALLOCATOR_PROPERTIES ) );
631                 p_ambuf->GetAllocatorProperties( &AllocProp );
632                 p_ambuf->Release();
633                 i_mtu = AllocProp.cbBuffer;
634             }
635             else
636             {
637                 /* Worst case */
638                 i_mtu = dshow_stream.header.audio.nSamplesPerSec *
639                         dshow_stream.header.audio.nChannels *
640                         dshow_stream.header.audio.wBitsPerSample / 8;
641             }
642             p_pin->Release();
643             p_input->i_mtu = __MAX( p_input->i_mtu, i_mtu );
644         }
645         else goto fail;
646
647         /* Add directshow elementary stream to our list */
648         dshow_stream.p_device_filter = p_device_filter;
649         dshow_stream.p_capture_filter = p_capture_filter;
650
651         p_sys->pp_streams =
652             (dshow_stream_t **)realloc( p_sys->pp_streams,
653                                         sizeof(dshow_stream_t *)
654                                         * (p_sys->i_streams + 1) );
655         p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
656         *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
657         SetDWBE( &p_sys->p_header[4], (uint32_t)p_sys->i_streams );
658
659         return VLC_SUCCESS;
660     }
661
662  fail:
663     /* Remove filters from graph */
664     p_sys->p_graph->RemoveFilter( p_device_filter );
665     p_sys->p_graph->RemoveFilter( p_capture_filter );
666
667     /* Release objects */
668     p_device_filter->Release();
669     p_capture_filter->Release();
670
671     return VLC_EGENERIC;
672 }
673
674 static IBaseFilter *
675 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
676                    list<string> *p_listdevices, vlc_bool_t b_audio )
677 {
678     IBaseFilter *p_base_filter = NULL;
679     IMoniker *p_moniker = NULL;
680     ULONG i_fetched;
681     HRESULT hr;
682
683     /* Create the system device enumerator */
684     ICreateDevEnum *p_dev_enum = NULL;
685
686     hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
687                            IID_ICreateDevEnum, (void **)&p_dev_enum );
688     if( FAILED(hr) )
689     {
690         msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
691         return NULL;
692     }
693
694     /* Create an enumerator for the video capture devices */
695     IEnumMoniker *p_class_enum = NULL;
696     if( !b_audio )
697         hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
698                                                 &p_class_enum, 0 );
699     else
700         hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
701                                                 &p_class_enum, 0 );
702     p_dev_enum->Release();
703     if( FAILED(hr) )
704     {
705         msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
706         return NULL;
707     }
708
709     /* If there are no enumerators for the requested type, then
710      * CreateClassEnumerator will succeed, but p_class_enum will be NULL */
711     if( p_class_enum == NULL )
712     {
713         msg_Err( p_this, "no capture device was detected." );
714         return NULL;
715     }
716
717     /* Enumerate the devices */
718
719     /* Note that if the Next() call succeeds but there are no monikers,
720      * it will return S_FALSE (which is not a failure). Therefore, we check
721      * that the return code is S_OK instead of using SUCCEEDED() macro. */
722
723     while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
724     {
725         /* Getting the property page to get the device name */
726         IPropertyBag *p_bag;
727         hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
728                                        (void **)&p_bag );
729         if( SUCCEEDED(hr) )
730         {
731             VARIANT var;
732             var.vt = VT_BSTR;
733             hr = p_bag->Read( L"FriendlyName", &var, NULL );
734             p_bag->Release();
735             if( SUCCEEDED(hr) )
736             {
737                 int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
738                 char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
739                 WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
740                                      i_convert, NULL, NULL );
741                 SysFreeString(var.bstrVal);
742
743                 if( p_listdevices ) p_listdevices->push_back( p_buf );
744
745                 if( p_devicename && *p_devicename == string(p_buf) )
746                 {
747                     /* Bind Moniker to a filter object */
748                     hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
749                                                   (void **)&p_base_filter );
750                     if( FAILED(hr) )
751                     {
752                         msg_Err( p_this, "couldn't bind moniker to filter "
753                                  "object (0x%x)", hr );
754                         p_moniker->Release();
755                         p_class_enum->Release();
756                         return NULL;
757                     }
758                     p_moniker->Release();
759                     p_class_enum->Release();
760                     return p_base_filter;
761                 }
762             }
763         }
764
765         p_moniker->Release();
766     }
767
768     p_class_enum->Release();
769     return NULL;
770 }
771
772 static AM_MEDIA_TYPE EnumDeviceCaps( vlc_object_t *p_this,
773                                      IBaseFilter *p_filter,
774                                      int i_chroma, int i_width, int i_height,
775                                      int i_channels, int i_samplespersec,
776                                      int i_bitspersample )
777 {
778     IEnumPins *p_enumpins;
779     IPin *p_output_pin;
780     IEnumMediaTypes *p_enummt;
781
782     AM_MEDIA_TYPE media_type;
783     media_type.majortype = GUID_NULL;
784     media_type.subtype = GUID_NULL;
785     media_type.formattype = GUID_NULL;
786     media_type.pUnk = NULL;
787     media_type.cbFormat = 0;
788     media_type.pbFormat = NULL;
789
790     if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return media_type;
791
792     /*while*/if( p_enumpins->Next( 1, &p_output_pin, NULL ) == S_OK )
793     {
794         /* Probe pin */
795         if( SUCCEEDED( p_output_pin->EnumMediaTypes( &p_enummt ) ) )
796         {
797             AM_MEDIA_TYPE *p_mt;
798             while( p_enummt->Next( 1, &p_mt, NULL ) == S_OK )
799             {
800
801                 if( p_mt->majortype == MEDIATYPE_Video )
802                 {
803                     int i_fourcc = VLC_FOURCC(' ', ' ', ' ', ' ');
804
805                     /* Packed RGB formats */
806                     if( p_mt->subtype == MEDIASUBTYPE_RGB1 )
807                         i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
808                     if( p_mt->subtype == MEDIASUBTYPE_RGB4 )
809                         i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
810                     if( p_mt->subtype == MEDIASUBTYPE_RGB8 )
811                         i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
812                     else if( p_mt->subtype == MEDIASUBTYPE_RGB555 )
813                         i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
814                     else if( p_mt->subtype == MEDIASUBTYPE_RGB565 )
815                         i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
816                     else if( p_mt->subtype == MEDIASUBTYPE_RGB24 )
817                         i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
818                     else if( p_mt->subtype == MEDIASUBTYPE_RGB32 )
819                         i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
820                     else if( p_mt->subtype == MEDIASUBTYPE_ARGB32 )
821                         i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
822                     else i_fourcc = *((int *)&p_mt->subtype);
823
824                     int i_current_width = p_mt->pbFormat ?
825                         ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biWidth : 0;
826                     int i_current_height = p_mt->pbFormat ?
827                         ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biHeight : 0;
828
829                     msg_Dbg( p_this, "EnumDeviceCaps: input pin "
830                              "accepts chroma: %4.4s, width:%i, height:%i",
831                              (char *)&i_fourcc, i_current_width,
832                              i_current_height );
833
834                     if( (!i_chroma || i_fourcc == i_chroma) &&
835                         (!i_width || i_width == i_current_width) &&
836                         (!i_height || i_height == i_current_height) )
837                     {
838                         /* Pick the 1st match */
839                         media_type = *p_mt;
840                         i_chroma = i_fourcc;
841                         i_width = i_current_width;
842                         i_height = i_current_height;
843                     }
844                     else
845                     {
846                         FreeMediaType( *p_mt );
847                     }
848                 }
849                 else if( p_mt->majortype == MEDIATYPE_Audio )
850                 {
851                     int i_fourcc;
852                     int i_current_channels =
853                         ((WAVEFORMATEX *)p_mt->pbFormat)->nChannels;
854                     int i_current_samplespersec =
855                         ((WAVEFORMATEX *)p_mt->pbFormat)->nSamplesPerSec;
856                     int i_current_bitspersample =
857                         ((WAVEFORMATEX *)p_mt->pbFormat)->wBitsPerSample;
858
859                     if( p_mt->subtype == MEDIASUBTYPE_PCM )
860                         i_fourcc = VLC_FOURCC( 'p', 'c', 'm', ' ' );
861                     else i_fourcc = *((int *)&p_mt->subtype);
862
863                     msg_Dbg( p_this, "EnumDeviceCaps: input pin "
864                              "accepts format: %4.4s, channels:%i, "
865                              "samples/sec:%i bits/sample:%i",
866                              (char *)&i_fourcc, i_current_channels,
867                              i_current_samplespersec, i_current_bitspersample);
868
869                     if( (!i_channels || i_channels == i_current_channels) &&
870                         (!i_samplespersec ||
871                          i_samplespersec == i_current_samplespersec) &&
872                         (!i_bitspersample ||
873                          i_bitspersample == i_current_bitspersample) )
874                     {
875                         /* Pick the 1st match */
876                         media_type = *p_mt;
877                         i_channels = i_current_channels;
878                         i_samplespersec = i_current_samplespersec;
879                         i_bitspersample = i_current_bitspersample;
880
881                         /* Setup a few properties like the audio latency */
882                         IAMBufferNegotiation *p_ambuf;
883
884                         if( SUCCEEDED( p_output_pin->QueryInterface(
885                               IID_IAMBufferNegotiation, (void **)&p_ambuf ) ) )
886                         {
887                             ALLOCATOR_PROPERTIES AllocProp;
888                             AllocProp.cbAlign = -1;
889                             AllocProp.cbBuffer = i_channels * i_samplespersec *
890                               i_bitspersample / 8 / 10 ; /*100 ms of latency*/
891                             AllocProp.cbPrefix = -1;
892                             AllocProp.cBuffers = -1;
893                             p_ambuf->SuggestAllocatorProperties( &AllocProp );
894                             p_ambuf->Release();
895                         }
896                     }
897                     else
898                     {
899                         FreeMediaType( *p_mt );
900                     }
901                 }
902
903                 CoTaskMemFree( (PVOID)p_mt );
904             }
905             p_enummt->Release();
906         }
907
908         p_output_pin->Release();
909     }
910
911     p_enumpins->Release();
912     return media_type;
913 }
914
915 /*****************************************************************************
916  * Read: reads from the device into PES packets.
917  *****************************************************************************
918  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
919  * bytes.
920  *****************************************************************************/
921 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
922                      size_t i_len )
923 {
924     access_sys_t   *p_sys = p_input->p_access_data;
925     dshow_stream_t *p_stream = NULL;
926     byte_t         *p_buf_orig = p_buffer;
927     VLCMediaSample  sample;
928     int             i_data_size;
929     uint8_t         *p_data;
930
931     if( p_sys->i_header_pos )
932     {
933         /* First header of the stream */
934         memcpy( p_buffer, p_sys->p_header, p_sys->i_header_size );
935         p_buffer += p_sys->i_header_size;
936         p_sys->i_header_pos = 0;
937     }
938
939     while( 1 )
940     {
941         /* Get new sample/frame from next elementary stream.
942          * We first loop through all the elementary streams and if all our
943          * fifos are empty we block until we are signaled some new data has
944          * arrived. */
945         vlc_mutex_lock( &p_sys->lock );
946
947         int i_stream;
948         for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
949         {
950             p_stream = p_sys->pp_streams[i_stream];
951             if( p_stream->mt.majortype == MEDIATYPE_Audio &&
952                 p_stream->p_capture_filter &&
953                 p_stream->p_capture_filter->CustomGetPin()
954                   ->CustomGetSample( &sample ) == S_OK )
955             {
956                 break;
957             }
958         }
959         if( i_stream == p_sys->i_streams )
960         for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
961         {
962             p_stream = p_sys->pp_streams[i_stream];
963             if( p_stream->p_capture_filter &&
964                 p_stream->p_capture_filter->CustomGetPin()
965                   ->CustomGetSample( &sample ) == S_OK )
966             {
967                 break;
968             }
969         }
970         if( i_stream == p_sys->i_streams )
971         {
972             /* No data available. Wait until some data has arrived */
973             vlc_cond_wait( &p_sys->wait, &p_sys->lock );
974             vlc_mutex_unlock( &p_sys->lock );
975             continue;
976         }
977
978         vlc_mutex_unlock( &p_sys->lock );
979
980         /*
981          * We got our sample
982          */
983         i_data_size = sample.p_sample->GetActualDataLength();
984         sample.p_sample->GetPointer( &p_data );
985
986         REFERENCE_TIME i_pts, i_end_date;
987         HRESULT hr = sample.p_sample->GetTime( &i_pts, &i_end_date );
988         if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
989
990         if( !i_pts )
991         {
992             if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
993             {
994                 /* Use our data timestamp */
995                 i_pts = sample.i_timestamp;
996                 p_stream->b_pts = VLC_TRUE;
997             }
998         }
999
1000 #if 0
1001         msg_Dbg( p_input, "Read() stream: %i PTS: "I64Fd, i_stream, i_pts );
1002 #endif
1003
1004         /* Create pseudo header */
1005         SetDWBE( &p_sys->p_header[0], i_stream );
1006         SetDWBE( &p_sys->p_header[4], i_data_size );
1007         SetQWBE( &p_sys->p_header[8], i_pts  * 9 / 1000 );
1008
1009 #if 0
1010         msg_Info( p_input, "access read %i data_size %i", i_len, i_data_size );
1011 #endif
1012
1013         /* First copy header */
1014         memcpy( p_buffer, p_sys->p_header, 16 /* header size */ );
1015         p_buffer += 16 /* header size */;
1016
1017         /* Then copy stream data if any */
1018         if( !p_stream->b_invert )
1019         {
1020             p_input->p_vlc->pf_memcpy( p_buffer, p_data, i_data_size );
1021             p_buffer += i_data_size;
1022         }
1023         else
1024         {
1025             int i_width = p_stream->header.video.bmiHeader.biWidth;
1026             int i_height = p_stream->header.video.bmiHeader.biHeight;
1027
1028             switch( p_stream->i_fourcc )
1029             {
1030             case VLC_FOURCC( 'R', 'V', '1', '5' ):
1031             case VLC_FOURCC( 'R', 'V', '1', '6' ):
1032                 i_width *= 2;
1033                 break;
1034             case VLC_FOURCC( 'R', 'V', '2', '4' ):
1035                 i_width *= 3;
1036                 break;
1037             case VLC_FOURCC( 'R', 'V', '3', '2' ):
1038             case VLC_FOURCC( 'R', 'G', 'B', 'A' ):
1039                 i_width *= 4;
1040                 break;
1041             }
1042
1043             for( int i = i_height - 1; i >= 0; i-- )
1044             {
1045                 p_input->p_vlc->pf_memcpy( p_buffer,
1046                      &p_data[i * i_width], i_width );
1047
1048                 p_buffer += i_width;
1049             }
1050         }
1051
1052         sample.p_sample->Release();
1053
1054         /* The caller got what he wanted */
1055         return p_buffer - p_buf_orig;
1056     }
1057
1058     return 0; /* never reached */
1059 }
1060
1061 /*****************************************************************************
1062  * ReadDV: reads from the DV device into PES packets.
1063  *****************************************************************************
1064  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
1065  * bytes.
1066  *****************************************************************************/
1067 static ssize_t ReadDV( input_thread_t * p_input, byte_t * p_buffer,
1068                        size_t i_len )
1069 {
1070     access_sys_t   *p_sys = p_input->p_access_data;
1071     dshow_stream_t *p_stream = NULL;
1072     VLCMediaSample  sample;
1073     int             i_data_size;
1074     uint8_t         *p_data;
1075
1076     /* Read 1 DV frame (they contain the video and audio data) */
1077
1078     /* There must be only 1 elementary stream to produce a valid
1079      * raw DV stream*/
1080     p_stream = p_sys->pp_streams[0];
1081
1082     while( 1 )
1083     {
1084         /* Get new sample/frame from the elementary stream (blocking). */
1085         vlc_mutex_lock( &p_sys->lock );
1086
1087         if( p_stream->p_capture_filter->CustomGetPin()
1088               ->CustomGetSample( &sample ) != S_OK )
1089         {
1090             /* No data available. Wait until some data has arrived */
1091             vlc_cond_wait( &p_sys->wait, &p_sys->lock );
1092             vlc_mutex_unlock( &p_sys->lock );
1093             continue;
1094         }
1095
1096         vlc_mutex_unlock( &p_sys->lock );
1097
1098         /*
1099          * We got our sample
1100          */
1101         i_data_size = sample.p_sample->GetActualDataLength();
1102         sample.p_sample->GetPointer( &p_data );
1103
1104         REFERENCE_TIME i_pts, i_end_date;
1105         HRESULT hr = sample.p_sample->GetTime( &i_pts, &i_end_date );
1106         if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
1107
1108         if( !i_pts )
1109         {
1110             if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
1111             {
1112                 /* Use our data timestamp */
1113                 i_pts = sample.i_timestamp;
1114                 p_stream->b_pts = VLC_TRUE;
1115             }
1116         }
1117
1118 #if 0
1119         msg_Info( p_input, "access read %i data_size %i PTS: "I64Fd,
1120                   i_len, i_data_size, i_pts );
1121 #endif
1122
1123         p_input->p_vlc->pf_memcpy( p_buffer, p_data, i_data_size );
1124
1125         sample.p_sample->Release();
1126
1127         /* The caller got what he wanted */
1128         return i_data_size;
1129     }
1130
1131     return 0; /* never reached */
1132 }
1133
1134 /*****************************************************************************
1135  * Demux: local prototypes
1136  *****************************************************************************/
1137 struct demux_sys_t
1138 {
1139     int         i_es;
1140     es_out_id_t **es;
1141 };
1142
1143 static int  Demux      ( input_thread_t * );
1144
1145 /****************************************************************************
1146  * DemuxOpen:
1147  ****************************************************************************/
1148 static int DemuxOpen( vlc_object_t *p_this )
1149 {
1150     input_thread_t *p_input = (input_thread_t *)p_this;
1151     demux_sys_t    *p_sys;
1152
1153     uint8_t        *p_peek;
1154     int            i_es;
1155     int            i;
1156
1157     /* a little test to see if it's a dshow stream */
1158     if( stream_Peek( p_input->s, &p_peek, 8 ) < 8 )
1159     {
1160         msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
1161         return VLC_EGENERIC;
1162     }
1163
1164     if( strncmp( p_peek, ".dsh", 4 ) ||
1165         ( i_es = GetDWBE( &p_peek[4] ) ) <= 0 )
1166     {
1167         msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
1168         return VLC_EGENERIC;
1169     }
1170
1171     vlc_mutex_lock( &p_input->stream.stream_lock );
1172     if( input_InitStream( p_input, 0 ) == -1)
1173     {
1174         vlc_mutex_unlock( &p_input->stream.stream_lock );
1175         msg_Err( p_input, "cannot init stream" );
1176         return( VLC_EGENERIC );
1177     }
1178     p_input->stream.i_mux_rate =  0 / 50;
1179     vlc_mutex_unlock( &p_input->stream.stream_lock );
1180
1181     p_input->pf_demux = Demux;
1182     p_input->pf_demux_control = demux_vaControlDefault;
1183     p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
1184     p_sys->i_es = 0;
1185     p_sys->es   = NULL;
1186
1187     if( stream_Peek( p_input->s, &p_peek, 8 + 20 * i_es ) < 8 + 20 * i_es )
1188     {
1189         msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
1190         return VLC_EGENERIC;
1191     }
1192     p_peek += 8;
1193
1194     for( i = 0; i < i_es; i++ )
1195     {
1196         es_format_t fmt;
1197
1198         if( !strncmp( p_peek, "auds", 4 ) )
1199         {
1200             es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
1201                                                         p_peek[6], p_peek[7] ) );
1202
1203             fmt.audio.i_channels = GetDWBE( &p_peek[8] );
1204             fmt.audio.i_rate = GetDWBE( &p_peek[12] );
1205             fmt.audio.i_bitspersample = GetDWBE( &p_peek[16] );
1206             fmt.audio.i_blockalign = fmt.audio.i_channels *
1207                                      fmt.audio.i_bitspersample / 8;
1208             fmt.i_bitrate = fmt.audio.i_channels *
1209                             fmt.audio.i_rate *
1210                             fmt.audio.i_bitspersample;
1211
1212             msg_Dbg( p_input, "new audio es %d channels %dHz",
1213                      fmt.audio.i_channels, fmt.audio.i_rate );
1214
1215             TAB_APPEND( p_sys->i_es, p_sys->es,
1216                         es_out_Add( p_input->p_es_out, &fmt ) );
1217         }
1218         else if( !strncmp( p_peek, "vids", 4 ) )
1219         {
1220             es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
1221                                                         p_peek[6], p_peek[7] ) );
1222             fmt.video.i_width  = GetDWBE( &p_peek[8] );
1223             fmt.video.i_height = GetDWBE( &p_peek[12] );
1224
1225             msg_Dbg( p_input, "added new video es %4.4s %dx%d",
1226                      (char*)&fmt.i_codec,
1227                      fmt.video.i_width, fmt.video.i_height );
1228             TAB_APPEND( p_sys->i_es, p_sys->es,
1229                         es_out_Add( p_input->p_es_out, &fmt ) );
1230         }
1231
1232         p_peek += 20;
1233     }
1234
1235     /* Skip header */
1236     stream_Read( p_input->s, NULL, 8 + 20 * i_es );
1237
1238     return VLC_SUCCESS;
1239 }
1240
1241 /****************************************************************************
1242  * DemuxClose:
1243  ****************************************************************************/
1244 static void DemuxClose( vlc_object_t *p_this )
1245 {
1246     input_thread_t *p_input = (input_thread_t *)p_this;
1247     demux_sys_t    *p_sys = p_input->p_demux_data;
1248
1249     if( p_sys->i_es > 0 )
1250     {
1251         free( p_sys->es );
1252     }
1253     free( p_sys );
1254 }
1255
1256 /****************************************************************************
1257  * Demux:
1258  ****************************************************************************/
1259 static int Demux( input_thread_t *p_input )
1260 {
1261     demux_sys_t *p_sys = p_input->p_demux_data;
1262     block_t     *p_block;
1263
1264     int i_es;
1265     int i_size;
1266
1267     uint8_t *p_peek;
1268     mtime_t i_pts;
1269
1270     if( stream_Peek( p_input->s, &p_peek, 16 ) < 16 )
1271     {
1272         msg_Warn( p_input, "cannot peek (EOF ?)" );
1273         return 0;
1274     }
1275
1276     i_es   = GetDWBE( &p_peek[0] );
1277     if( i_es < 0 || i_es >= p_sys->i_es )
1278     {
1279         msg_Err( p_input, "cannot find ES" );
1280         return -1;
1281     }
1282
1283     i_size = GetDWBE( &p_peek[4] );
1284     i_pts  = GetQWBE( &p_peek[8] );
1285
1286     if( ( p_block = stream_Block( p_input->s, 16 + i_size ) ) == NULL )
1287     {
1288         msg_Warn( p_input, "cannot read data" );
1289         return 0;
1290     }
1291
1292     p_block->p_buffer += 16;
1293     p_block->i_buffer -= 16;
1294
1295     /* Call the pace control. */
1296     input_ClockManageRef( p_input, p_input->stream.p_selected_program,
1297                           i_pts );
1298
1299     p_block->i_dts =
1300     p_block->i_pts = i_pcr <= 0 ? 0 :
1301         input_ClockGetTS( p_input, p_input->stream.p_selected_program, i_pts );
1302
1303     es_out_Send( p_input->p_es_out, p_sys->es[i_es], p_block );
1304
1305     return 1;
1306 }
1307
1308
1309 /*****************************************************************************
1310  * config variable callback
1311  *****************************************************************************/
1312 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
1313                                vlc_value_t newval, vlc_value_t oldval, void * )
1314 {
1315     module_t *p_module;
1316     module_config_t *p_item;
1317     vlc_bool_t b_audio = VLC_FALSE;
1318     int i;
1319
1320     p_item = config_FindConfig( p_this, psz_name );
1321     if( !p_item ) return VLC_SUCCESS;
1322
1323     if( !strcmp( psz_name, "dshow-adev" ) ) b_audio = VLC_TRUE;
1324
1325     /* Clear-up the current list */
1326     if( p_item->i_list )
1327     {
1328         /* Keep the 2 first entries */
1329         for( i = 2; i < p_item->i_list; i++ )
1330         {
1331             free( p_item->ppsz_list[i] );
1332             free( p_item->ppsz_list_text[i] );
1333         }
1334         /* TODO: Remove when no more needed */
1335         p_item->ppsz_list[i] = NULL;
1336         p_item->ppsz_list_text[i] = NULL;
1337     }
1338     p_item->i_list = 2;
1339
1340     /* Find list of devices */
1341     list<string> list_devices;
1342
1343     FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
1344
1345     if( !list_devices.size() ) return VLC_SUCCESS;
1346
1347     p_item->ppsz_list =
1348         (char **)realloc( p_item->ppsz_list,
1349                           (list_devices.size()+3) * sizeof(char *) );
1350     p_item->ppsz_list_text =
1351         (char **)realloc( p_item->ppsz_list_text,
1352                           (list_devices.size()+3) * sizeof(char *) );
1353
1354     list<string>::iterator iter;
1355     for( iter = list_devices.begin(), i = 2; iter != list_devices.end();
1356          iter++, i++ )
1357     {
1358         p_item->ppsz_list[i] = strdup( iter->c_str() );
1359         p_item->ppsz_list_text[i] = strdup( iter->c_str() );
1360         p_item->i_list++;
1361     }
1362     p_item->ppsz_list[i] = NULL;
1363     p_item->ppsz_list_text[i] = NULL;
1364
1365     return VLC_SUCCESS;
1366 }