]> git.sesse.net Git - vlc/blob - modules/access/dshow/dshow.cpp
* modules/access/dshow/*: bug fixes.
[vlc] / modules / access / dshow / dshow.cpp
1 /*****************************************************************************
2  * dshow.c : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: dshow.cpp,v 1.4 2003/08/26 19:14:09 gbazin 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 #ifndef _MSC_VER
36 #   include <wtypes.h>
37 #   include <unknwn.h>
38 #   include <ole2.h>
39 #   include <limits.h>
40 #   define _WINGDI_ 1
41 #   define AM_NOVTABLE
42 #   define _OBJBASE_H_
43 #   undef _X86_
44 #   define _I64_MAX LONG_LONG_MAX
45 #   define LONGLONG long long
46 #endif
47
48 #include <dshow.h>
49
50 #include "filter.h"
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 static int  AccessOpen  ( vlc_object_t * );
56 static void AccessClose ( vlc_object_t * );
57 static int  Read        ( input_thread_t *, byte_t *, size_t );
58
59 static int  DemuxOpen  ( vlc_object_t * );
60 static void DemuxClose ( vlc_object_t * );
61 static int  Demux      ( input_thread_t * );
62
63 static int OpenDevice( input_thread_t *, string, vlc_bool_t );
64 static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
65                                        list<string> *, vlc_bool_t );
66 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
67                             IPin *p_input_pin );
68
69 /*****************************************************************************
70  * Module descriptior
71  *****************************************************************************/
72 #define CACHING_TEXT N_("Caching value in ms")
73 #define CACHING_LONGTEXT N_( \
74     "Allows you to modify the default caching value for directshow streams. " \
75     "This value should be set in miliseconds units." )
76
77 vlc_module_begin();
78     set_description( _("DirectShow input") );
79     add_category_hint( N_("dshow"), NULL, VLC_TRUE );
80     add_integer( "dshow-caching", DEFAULT_PTS_DELAY / 1000, NULL,
81                  CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
82     add_shortcut( "dshow" );
83     set_capability( "access", 0 );
84     set_callbacks( AccessOpen, AccessClose );
85
86     add_submodule();
87     set_description( _("DirectShow demuxer") );
88     add_shortcut( "dshow" );
89     set_capability( "demux", 200 );
90     set_callbacks( DemuxOpen, DemuxClose );
91
92 vlc_module_end();
93
94 /****************************************************************************
95  * I. Access Part
96  ****************************************************************************/
97
98 /*
99  * header:
100  *  fcc  ".dsh"
101  *  u32    stream count
102  *      fcc "auds"|"vids"       0
103  *      fcc codec               4
104  *      if vids
105  *          u32 width           8
106  *          u32 height          12
107  *          u32 padding         16
108  *      if auds
109  *          u32 channels        12
110  *          u32 samplerate      8
111  *          u32 samplesize      16
112  *
113  * data:
114  *  u32     stream number
115  *  u32     data size
116  *  u8      data
117  */
118
119 static void SetDWBE( uint8_t *p, uint32_t dw )
120 {
121     p[0] = (dw >> 24)&0xff;
122     p[1] = (dw >> 16)&0xff;
123     p[2] = (dw >>  8)&0xff;
124     p[3] = (dw      )&0xff;
125 }
126
127 static void SetQWBE( uint8_t *p, uint64_t qw )
128 {
129     SetDWBE( p, (qw >> 32)&0xffffffff );
130     SetDWBE( &p[4], qw&0xffffffff );
131 }
132
133 /****************************************************************************
134  * DirectShow elementary stream descriptor
135  ****************************************************************************/
136 typedef struct dshow_stream_t
137 {
138     string          devicename;
139     IBaseFilter     *p_device_filter;
140     CaptureFilter   *p_capture_filter;
141     AM_MEDIA_TYPE   mt;
142     int             i_fourcc;
143
144     union
145     {
146       VIDEOINFOHEADER video;
147       WAVEFORMATEX    audio;
148
149     } header;
150
151     VLCMediaSample  sample;
152     int             i_data_size;
153     int             i_data_pos;
154     uint8_t         *p_data;
155
156 } dshow_stream_t;
157
158 /****************************************************************************
159  * Access descriptor declaration
160  ****************************************************************************/
161 struct access_sys_t
162 {
163     IFilterGraph  *p_graph;
164     IMediaControl *p_control;
165
166     /* header */
167     int     i_header_size;
168     int     i_header_pos;
169     uint8_t *p_header;
170
171     /* list of elementary streams */
172     dshow_stream_t **pp_streams;
173     int            i_streams;
174     int            i_current_stream;
175 };
176
177 /*****************************************************************************
178  * Open: open direct show device
179  *****************************************************************************/
180 static int AccessOpen( vlc_object_t *p_this )
181 {
182     input_thread_t *p_input = (input_thread_t *)p_this;
183     access_sys_t   *p_sys;
184
185     /* parse url and open device(s) */
186     char *psz_dup, *psz_parser;
187     psz_dup = strdup( p_input->psz_name );
188     psz_parser = psz_dup;
189     string vdevname, adevname;
190
191     while( *psz_parser && *psz_parser != ':' )
192     {
193         psz_parser++;
194     }
195
196     if( *psz_parser == ':' )
197     {
198         /* read options */
199         for( ;; )
200         {
201             int i_len;
202
203             *psz_parser++ = '\0';
204             if( !strncmp( psz_parser, "vdev=", strlen( "vdev=" ) ) )
205             {
206                 psz_parser += strlen( "vdev=" );
207                 if( strchr( psz_parser, ':' ) )
208                 {
209                     i_len = strchr( psz_parser, ':' ) - psz_parser;
210                 }
211                 else
212                 {
213                     i_len = strlen( psz_parser );
214                 }
215
216                 vdevname = string( psz_parser, i_len );
217
218                 psz_parser += i_len;
219             }
220             else if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) ) )
221             {
222                 psz_parser += strlen( "adev=" );
223                 if( strchr( psz_parser, ':' ) )
224                 {
225                     i_len = strchr( psz_parser, ':' ) - psz_parser;
226                 }
227                 else
228                 {
229                     i_len = strlen( psz_parser );
230                 }
231
232                 adevname = string( psz_parser, i_len );
233
234                 psz_parser += i_len;
235             }
236             else
237             {
238                 msg_Warn( p_input, "unknown option" );
239             }
240
241             while( *psz_parser && *psz_parser != ':' )
242             {
243                 psz_parser++;
244             }
245
246             if( *psz_parser == '\0' )
247             {
248                 break;
249             }
250         }
251     }
252
253     free( psz_dup );
254
255     p_input->pf_read        = Read;
256     p_input->pf_seek        = NULL;
257     p_input->pf_set_area    = NULL;
258     p_input->pf_set_program = NULL;
259
260     vlc_mutex_lock( &p_input->stream.stream_lock );
261     p_input->stream.b_pace_control = 0;
262     p_input->stream.b_seekable = 0;
263     p_input->stream.p_selected_area->i_size = 0;
264     p_input->stream.p_selected_area->i_tell = 0;
265     p_input->stream.i_method = INPUT_METHOD_FILE;
266     vlc_mutex_unlock( &p_input->stream.stream_lock );
267     p_input->i_pts_delay = config_GetInt( p_input, "dshow-caching" ) * 1000;
268
269     /* Initialize OLE/COM */
270     CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
271
272     /* create access private data */
273     p_input->p_access_data = p_sys =
274         (access_sys_t *)malloc( sizeof( access_sys_t ) );
275
276     /* Initialize some data */
277     p_sys->i_streams = 0;
278     p_sys->pp_streams = (dshow_stream_t **)malloc( 1 );
279
280     /* Create header */
281     p_sys->i_header_size = 8;
282     p_sys->p_header      = (uint8_t *)malloc( p_sys->i_header_size );
283     memcpy(  &p_sys->p_header[0], ".dsh", 4 );
284     SetDWBE( &p_sys->p_header[4], 1 );
285     p_sys->i_header_pos = p_sys->i_header_size;
286
287     /* Build directshow graph */
288     CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
289                       (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
290
291     p_sys->p_graph->QueryInterface( IID_IMediaControl,
292                                     (void **)&p_sys->p_control );
293
294     if( OpenDevice( p_input, vdevname, 0 ) != VLC_SUCCESS )
295     {
296         msg_Err( p_input, "can't open video");
297     }
298
299     if( OpenDevice( p_input, adevname, 1 ) != VLC_SUCCESS )
300     {
301         msg_Err( p_input, "can't open audio");
302     }
303
304     if( !p_sys->i_streams )
305     {
306         /* Release directshow objects */
307         p_sys->p_control->Release();
308         p_sys->p_graph->Release();
309
310         /* Uninitialize OLE/COM */
311         CoUninitialize();   
312
313         free( p_sys->p_header );
314         free( p_sys );
315         return VLC_EGENERIC;
316     }
317
318     /* Initialize some data */
319     p_sys->i_current_stream = 0;
320     p_sys->i_header_pos = 0;
321
322     /* Everything is ready. Let's rock baby */
323     p_sys->p_control->Run();
324
325     return VLC_SUCCESS;
326 }
327
328 /*****************************************************************************
329  * AccessClose: close device
330  *****************************************************************************/
331 static void AccessClose( vlc_object_t *p_this )
332 {
333     input_thread_t *p_input = (input_thread_t *)p_this;
334     access_sys_t    *p_sys  = p_input->p_access_data;
335
336     /* Stop capturing stuff */
337     p_sys->p_control->Stop();
338     p_sys->p_control->Release();
339
340     /* Remove filters from graph */
341     for( int i = 0; i < p_sys->i_streams; i++ )
342     {
343         p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );
344         p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );
345         p_sys->pp_streams[i]->p_device_filter->Release();
346         p_sys->pp_streams[i]->p_capture_filter->Release();
347     }
348     p_sys->p_graph->Release();
349
350     /* Uninitialize OLE/COM */
351     CoUninitialize();   
352
353     free( p_sys->p_header );
354     for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];
355     free( p_sys->pp_streams );
356     free( p_sys );
357 }
358
359 /****************************************************************************
360  * ConnectFilters
361  ****************************************************************************/
362 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
363                             IPin *p_input_pin )
364 {
365     IEnumPins *p_enumpins;
366     IPin *p_output_pin;
367     ULONG i_fetched;
368
369     if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
370
371     while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
372     {
373         if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
374         {
375             p_enumpins->Release();
376             return true;
377         }
378     }
379
380     p_enumpins->Release();
381     return false;
382 }
383
384 static int OpenDevice( input_thread_t *p_input, string devicename,
385                        vlc_bool_t b_audio )
386 {
387     access_sys_t *p_sys = p_input->p_access_data;
388     list<string> list_devices;
389
390     /* Enumerate audio devices and display their names */
391     FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );
392
393     list<string>::iterator iter;
394     for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
395         msg_Dbg( p_input, "found device: %s", iter->c_str() );
396
397     /* If no device name was specified, pick the 1st one */
398     if( devicename.size() == 0 )
399     {
400         devicename = *list_devices.begin();
401     }
402
403     // Use the system device enumerator and class enumerator to find
404     // a capture/preview device, such as a desktop USB video camera.
405     IBaseFilter *p_device_filter =
406         FindCaptureDevice( (vlc_object_t *)p_input, &devicename,
407                            NULL, b_audio );
408     if( p_device_filter )
409         msg_Dbg( p_input, "using device: %s", devicename.c_str() );
410     else
411     {
412         msg_Err( p_input, "can't use device: %s", devicename.c_str() );
413         return VLC_EGENERIC;
414     }
415
416     /* Create and add our capture filter */
417     CaptureFilter *p_capture_filter = new CaptureFilter( p_input );
418     p_sys->p_graph->AddFilter( p_capture_filter, 0 );
419
420     /* Add the device filter to the graph (seems necessary with VfW before
421      * accessing pin attributes). */
422     p_sys->p_graph->AddFilter( p_device_filter, 0 );
423
424     /* Attempt to connect one of this device's capture output pins */
425     msg_Dbg( p_input, "connecting filters" );
426     if( ConnectFilters( p_sys->p_graph, p_device_filter,
427                         p_capture_filter->CustomGetPin() ) )
428     {
429         /* Success */
430         dshow_stream_t dshow_stream;
431         dshow_stream.mt =
432             p_capture_filter->CustomGetPin()->CustomGetMediaType();
433
434         if( dshow_stream.mt.majortype == MEDIATYPE_Video )
435         {
436             msg_Dbg( p_input, "MEDIATYPE_Video");
437
438             if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB8 )
439                 dshow_stream.i_fourcc = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
440             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB555 )
441                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
442             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB565 )
443                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
444             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB24 )
445                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
446             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB32 )
447                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
448             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_ARGB32 )
449                 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
450             
451             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUYV )
452                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
453             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )
454                 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
455             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y41P )
456                 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
457             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUY2 )
458                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
459             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVYU )
460                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
461             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )
462                 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
463             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YV12 )
464                 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
465             else goto fail;
466
467             dshow_stream.header.video =
468                 *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
469
470             /* Add video stream to header */
471             p_sys->i_header_size += 20;
472             p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
473                                                   p_sys->i_header_size );
474             memcpy(  &p_sys->p_header[p_sys->i_header_pos], "vids", 4 );
475             memcpy(  &p_sys->p_header[p_sys->i_header_pos + 4],
476                      &dshow_stream.i_fourcc, 4 );
477             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
478                      dshow_stream.header.video.bmiHeader.biWidth );
479             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],
480                      dshow_stream.header.video.bmiHeader.biHeight );
481             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16], 0 );
482             p_sys->i_header_pos = p_sys->i_header_size;
483         }
484
485         else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&
486                  dshow_stream.mt.formattype == FORMAT_WaveFormatEx )
487         {
488             msg_Dbg( p_input, "MEDIATYPE_Audio");
489
490             if( dshow_stream.mt.subtype == MEDIASUBTYPE_PCM )
491                 dshow_stream.i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
492 #if 0
493             else if( dshow_stream.mt.subtype == MEDIASUBTYPE_IEEE_FLOAT )
494                 dshow_stream.i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );
495 #endif
496             else goto fail;
497
498             dshow_stream.header.audio =
499                 *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
500
501             /* Add audio stream to header */
502             p_sys->i_header_size += 20;
503             p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
504                                                   p_sys->i_header_size );
505             memcpy(  &p_sys->p_header[p_sys->i_header_pos], "auds", 4 );
506             memcpy(  &p_sys->p_header[p_sys->i_header_pos + 4],
507                      &dshow_stream.i_fourcc, 4 );
508             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
509                      dshow_stream.header.audio.nChannels );
510             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],
511                      dshow_stream.header.audio.nSamplesPerSec );
512             SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16],
513                      dshow_stream.header.audio.wBitsPerSample );
514             p_sys->i_header_pos = p_sys->i_header_size;
515         }
516         else goto fail;
517
518         /* Add directshow elementary stream to our list */
519         dshow_stream.sample.p_sample  = NULL;
520         dshow_stream.i_data_size = 0;
521         dshow_stream.i_data_pos = 0;
522         dshow_stream.p_device_filter = p_device_filter;
523         dshow_stream.p_capture_filter = p_capture_filter;
524
525         p_sys->pp_streams =
526             (dshow_stream_t **)realloc( p_sys->pp_streams,
527                                         sizeof(dshow_stream_t *)
528                                         * (p_sys->i_streams + 1) );
529         p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
530         *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
531         SetDWBE( &p_sys->p_header[4], (uint32_t)p_sys->i_streams );
532
533         return VLC_SUCCESS;
534     }
535
536  fail:
537     /* Remove filters from graph */
538     p_sys->p_graph->RemoveFilter( p_device_filter );
539     p_sys->p_graph->RemoveFilter( p_capture_filter );
540
541     /* Release objects */
542     p_device_filter->Release();
543     p_capture_filter->Release();
544
545     return VLC_EGENERIC;
546 }
547
548 static IBaseFilter *
549 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
550                    list<string> *p_listdevices, vlc_bool_t b_audio )
551 {
552     IBaseFilter *p_base_filter = NULL;
553     IMoniker *p_moniker = NULL;
554     ULONG i_fetched;
555     HRESULT hr;
556
557     /* Create the system device enumerator */
558     ICreateDevEnum *p_dev_enum = NULL;
559
560     hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
561                            IID_ICreateDevEnum, (void **)&p_dev_enum );
562     if( FAILED(hr) )
563     {
564         msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
565         return NULL;
566     }
567
568     /* Create an enumerator for the video capture devices */
569     IEnumMoniker *p_class_enum = NULL;
570     if( !b_audio )
571         hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
572                                                 &p_class_enum, 0 );
573     else
574         hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
575                                                 &p_class_enum, 0 );
576     p_dev_enum->Release();
577     if( FAILED(hr) )
578     {
579         msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
580         return NULL;
581     }
582
583     /* If there are no enumerators for the requested type, then 
584      * CreateClassEnumerator will succeed, but p_class_enum will be NULL */
585     if( p_class_enum == NULL )
586     {
587         msg_Err( p_this, "no capture device was detected." );
588         return NULL;
589     }
590
591     /* Enumerate the devices */
592
593     /* Note that if the Next() call succeeds but there are no monikers,
594      * it will return S_FALSE (which is not a failure). Therefore, we check
595      * that the return code is S_OK instead of using SUCCEEDED() macro. */
596
597     while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
598     {
599         /* Getting the property page to get the device name */
600         IPropertyBag *p_bag;
601         hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
602                                        (void **)&p_bag );
603         if( SUCCEEDED(hr) )
604         {
605             VARIANT var;
606             var.vt = VT_BSTR;
607             hr = p_bag->Read( L"FriendlyName", &var, NULL );
608             p_bag->Release();
609             if( SUCCEEDED(hr) )
610             {
611                 int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
612                 char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
613                 WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
614                                      i_convert, NULL, NULL );
615                 SysFreeString(var.bstrVal);
616
617                 if( p_listdevices ) p_listdevices->push_back( p_buf );
618
619                 if( p_devicename && *p_devicename == string(p_buf) )
620                 {
621                     /* Bind Moniker to a filter object */
622                     hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
623                                                   (void **)&p_base_filter );
624                     if( FAILED(hr) )
625                     {
626                         msg_Err( p_this, "couldn't bind moniker to filter "
627                                  "object (0x%x)", hr );
628                         p_moniker->Release();
629                         p_class_enum->Release();
630                         return NULL;
631                     }
632                     p_moniker->Release();
633                     p_class_enum->Release();
634                     return p_base_filter;
635                 }
636             }
637         }
638
639         p_moniker->Release();
640     }
641
642     p_class_enum->Release();
643     return NULL;
644 }
645
646 /*****************************************************************************
647  * Read: reads from the device into PES packets.
648  *****************************************************************************
649  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
650  * bytes.
651  *****************************************************************************/
652 static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
653 {
654     access_sys_t   *p_sys = p_input->p_access_data;
655     dshow_stream_t *p_stream = p_sys->pp_streams[p_sys->i_current_stream];
656     int            i_data = 0;
657
658 #if 0
659     msg_Info( p_input, "access read data_size %i, data_pos %i",
660               p_sys->i_data_size, p_sys->i_data_pos );
661 #endif
662
663     while( i_len > 0 )
664     {
665         /* First copy header if any */
666         if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
667         {
668             int i_copy;
669
670             i_copy = __MIN( p_sys->i_header_size -
671                             p_sys->i_header_pos, (int)i_len );
672             memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );
673             p_sys->i_header_pos += i_copy;
674
675             p_buffer += i_copy;
676             i_len -= i_copy;
677             i_data += i_copy;
678         }
679
680         /* Then copy stream data if any */
681         if( i_len > 0 && p_stream->i_data_pos < p_stream->i_data_size )
682         {
683             int i_copy = __MIN( p_stream->i_data_size -
684                                 p_stream->i_data_pos, (int)i_len );
685
686             memcpy( p_buffer, &p_stream->p_data[p_stream->i_data_pos],
687                     i_copy );
688             p_stream->i_data_pos += i_copy;
689
690             p_buffer += i_copy;
691             i_len -= i_copy;
692             i_data += i_copy;
693         }
694
695         /* The caller got what he wanted */
696         if( i_len <= 0 ) return i_data;
697
698         /* Read no more than one frame at a time, otherwise we kill latency */
699         if( p_stream->i_data_size && i_data &&
700             p_stream->i_data_pos == p_stream->i_data_size )
701         {
702             p_stream->i_data_pos = p_stream->i_data_size = 0;
703             return i_data;
704         }
705
706         /* Get new sample/frame from next stream */
707         //if( p_stream->sample.p_sample ) p_stream->sample.p_sample->Release();
708         p_sys->i_current_stream =
709             (p_sys->i_current_stream + 1) % p_sys->i_streams;
710         p_stream = p_sys->pp_streams[p_sys->i_current_stream];
711         if( p_stream->p_capture_filter &&
712             p_stream->p_capture_filter->CustomGetPin()
713                 ->CustomGetSample( &p_stream->sample ) == S_OK )
714         {
715             p_stream->i_data_pos = 0;
716             p_stream->i_data_size =
717                 p_stream->sample.p_sample->GetActualDataLength();
718             p_stream->sample.p_sample->GetPointer( &p_stream->p_data );
719
720             REFERENCE_TIME i_pts, i_end_date;
721             HRESULT hr =
722                 p_stream->sample.p_sample->GetTime( &i_pts, &i_end_date );
723             if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
724
725             if( !i_pts )
726             {
727                 /* Use our data timestamp */
728                 i_pts = p_stream->sample.i_timestamp;
729             }
730
731 #if 0
732             msg_Dbg( p_input, "Read() PTS: "I64Fd, i_pts );
733 #endif
734
735             /* Create pseudo header */
736             p_sys->i_header_size = 16;
737             p_sys->i_header_pos  = 0;
738             SetDWBE( &p_sys->p_header[0], p_sys->i_current_stream );
739             SetDWBE( &p_sys->p_header[4], p_stream->i_data_size );
740             SetQWBE( &p_sys->p_header[8], i_pts  * 9 / 1000 );
741         }
742         else msleep( 10000 );
743     }
744
745     return i_data;
746 }
747
748 /****************************************************************************
749  * I. Demux Part
750  ****************************************************************************/
751 static int DemuxOpen( vlc_object_t *p_this )
752 {
753     input_thread_t *p_input = (input_thread_t *)p_this;
754
755     uint8_t        *p_peek;
756     int            i_streams;
757     int            i;
758
759     data_packet_t  *p_pk;
760
761     /* Initialize access plug-in structures. */
762     if( p_input->i_mtu == 0 )
763     {
764         /* Improve speed. */
765         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
766     }
767
768     /* a little test to see if it's a dshow stream */
769     if( input_Peek( p_input, &p_peek, 8 ) < 8 )
770     {
771         msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
772         return( VLC_EGENERIC );
773     }
774
775     if( strcmp( (const char *)p_peek, ".dsh" ) ||
776         GetDWBE( &p_peek[4] ) <= 0 )
777     {
778         msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
779         return VLC_EGENERIC;
780     }
781
782     /*  create one program */
783     vlc_mutex_lock( &p_input->stream.stream_lock );
784     if( input_InitStream( p_input, 0 ) == -1)
785     {
786         vlc_mutex_unlock( &p_input->stream.stream_lock );
787         msg_Err( p_input, "cannot init stream" );
788         return( VLC_EGENERIC );
789     }
790     if( input_AddProgram( p_input, 0, 0) == NULL )
791     {
792         vlc_mutex_unlock( &p_input->stream.stream_lock );
793         msg_Err( p_input, "cannot add program" );
794         return( VLC_EGENERIC );
795     }
796
797     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
798     p_input->stream.i_mux_rate =  0;
799
800     i_streams = GetDWBE( &p_peek[4] );
801     if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
802         < 8 + 20 * i_streams )
803     {
804         msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
805         return( VLC_EGENERIC );
806     }
807     p_peek += 8;
808
809     for( i = 0; i < i_streams; i++ )
810     {
811         es_descriptor_t *p_es;
812
813         if( !strncmp( (const char *)p_peek, "auds", 4 ) )
814         {
815 #define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
816             p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
817                                 i + 1, AUDIO_ES, NULL, 0 );
818             p_es->i_stream_id   = i + 1;
819             p_es->i_fourcc      =
820                 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
821
822             p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
823
824             wf->wFormatTag      = 0;//WAVE_FORMAT_UNKNOWN;
825             wf->nChannels       = GetDWBE( &p_peek[8] );
826             wf->nSamplesPerSec  = GetDWBE( &p_peek[12] );
827             wf->wBitsPerSample  = GetDWBE( &p_peek[16] );
828             wf->nBlockAlign     = wf->wBitsPerSample * wf->nChannels / 8;
829             wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
830             wf->cbSize          = 0;
831
832             msg_Dbg( p_input, "added new audio es %d channels %dHz",
833                      wf->nChannels, wf->nSamplesPerSec );
834
835             input_SelectES( p_input, p_es );
836 #undef wf
837         }
838         else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
839         {
840 #define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
841             p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
842                                 i + 1, VIDEO_ES, NULL, 0 );
843             p_es->i_stream_id   = i + 1;
844             p_es->i_fourcc  =
845                 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
846
847             p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
848
849             bih->biSize     = sizeof( BITMAPINFOHEADER );
850             bih->biWidth    = GetDWBE( &p_peek[8] );
851             bih->biHeight   = GetDWBE( &p_peek[12] );
852             bih->biPlanes   = 0;
853             bih->biBitCount = 0;
854             bih->biCompression      = 0;
855             bih->biSizeImage= 0;
856             bih->biXPelsPerMeter    = 0;
857             bih->biYPelsPerMeter    = 0;
858             bih->biClrUsed  = 0;
859             bih->biClrImportant     = 0;
860
861             msg_Dbg( p_input, "added new video es %4.4s %dx%d",
862                      (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
863
864             input_SelectES( p_input, p_es );
865 #undef bih
866         }
867
868         p_peek += 20;
869     }
870
871     p_input->stream.p_selected_program->b_is_ok = 1;
872     vlc_mutex_unlock( &p_input->stream.stream_lock );
873
874     if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
875     {
876         input_DeletePacket( p_input->p_method_data, p_pk );
877     }
878
879     p_input->pf_demux = Demux;
880     return VLC_SUCCESS;
881 }
882
883 static void DemuxClose( vlc_object_t *p_this )
884 {
885     return;
886 }
887
888 static int Demux( input_thread_t *p_input )
889 {
890     es_descriptor_t *p_es;
891     pes_packet_t    *p_pes;
892
893     int i_stream;
894     int i_size;
895     uint8_t *p_peek;
896     mtime_t i_pcr;
897
898     if( input_Peek( p_input, &p_peek, 16 ) < 16 )
899     {
900         msg_Warn( p_input, "cannot peek (EOF ?)" );
901         return( 0 );
902     }
903
904     i_stream = GetDWBE( &p_peek[0] );
905     i_size   = GetDWBE( &p_peek[4] );
906     i_pcr    = GetQWBE( &p_peek[8] );
907
908     //msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
909     //p_es = input_FindES( p_input, i_stream );
910
911     p_es = p_input->stream.p_selected_program->pp_es[i_stream];
912     if( !p_es )
913     {
914         msg_Err( p_input, "cannot find ES" );
915     }
916
917     p_pes = input_NewPES( p_input->p_method_data );
918     if( p_pes == NULL )
919     {
920         msg_Warn( p_input, "cannot allocate PES" );
921         msleep( 1000 );
922         return( 1 );
923     }
924     i_size += 16;
925     while( i_size > 0 )
926     {
927         data_packet_t   *p_data;
928         int i_read;
929
930         if( (i_read = input_SplitBuffer( p_input, &p_data,
931                                          __MIN( i_size, 10000 ) ) ) <= 0 )
932         {
933             input_DeletePES( p_input->p_method_data, p_pes );
934             return( 0 );
935         }
936         if( !p_pes->p_first )
937         {
938             p_pes->p_first = p_data;
939             p_pes->i_nb_data = 1;
940             p_pes->i_pes_size = i_read;
941         }
942         else
943         {
944             p_pes->p_last->p_next  = p_data;
945             p_pes->i_nb_data++;
946             p_pes->i_pes_size += i_read;
947         }
948         p_pes->p_last  = p_data;
949         i_size -= i_read;
950     }
951
952     p_pes->p_first->p_payload_start += 16;
953     p_pes->i_pes_size               -= 16;
954
955     if( p_es && p_es->p_decoder_fifo )
956     {
957         /* Call the pace control. */
958         input_ClockManageRef( p_input, p_input->stream.p_selected_program,
959                               i_pcr );
960
961         p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
962             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
963                               i_pcr );
964
965         input_DecodePES( p_es->p_decoder_fifo, p_pes );
966     }
967     else
968     {
969         input_DeletePES( p_input->p_method_data, p_pes );
970     }
971
972     return 1;
973 }