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 $
7 * Author: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc/input.h>
37 /*****************************************************************************
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") };
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 " \
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 " \
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...)")
69 static int AccessOpen ( vlc_object_t * );
70 static void AccessClose( vlc_object_t * );
72 static int DemuxOpen ( vlc_object_t * );
73 static void DemuxClose ( vlc_object_t * );
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 );
81 add_string( "dshow-vdev", NULL, NULL, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE);
82 change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback );
84 add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE);
85 change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback );
87 add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE);
89 add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
91 add_shortcut( "dshow" );
92 set_capability( "access", 0 );
93 set_callbacks( AccessOpen, AccessClose );
96 set_description( _("DirectShow demuxer") );
97 add_shortcut( "dshow" );
98 set_capability( "demux", 200 );
99 set_callbacks( DemuxOpen, DemuxClose );
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 );
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 * );
117 static int FindDevicesCallback( vlc_object_t *, char const *,
118 vlc_value_t, vlc_value_t, void * );
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 );
130 * fcc "auds"|"vids" 0
147 static void SetDWBE( uint8_t *p, uint32_t dw )
149 p[0] = (dw >> 24)&0xff;
150 p[1] = (dw >> 16)&0xff;
151 p[2] = (dw >> 8)&0xff;
155 static void SetQWBE( uint8_t *p, uint64_t qw )
157 SetDWBE( p, (qw >> 32)&0xffffffff );
158 SetDWBE( &p[4], qw&0xffffffff );
161 /****************************************************************************
162 * DirectShow elementary stream descriptor
163 ****************************************************************************/
164 typedef struct dshow_stream_t
167 IBaseFilter *p_device_filter;
168 CaptureFilter *p_capture_filter;
175 VIDEOINFOHEADER video;
184 /****************************************************************************
185 * Access descriptor declaration
186 ****************************************************************************/
192 IFilterGraph *p_graph;
193 IMediaControl *p_control;
200 /* list of elementary streams */
201 dshow_stream_t **pp_streams;
203 int i_current_stream;
205 /* misc properties */
211 /*****************************************************************************
212 * Open: open direct show device
213 *****************************************************************************/
214 static int AccessOpen( vlc_object_t *p_this )
216 input_thread_t *p_input = (input_thread_t *)p_this;
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');
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 );
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 );
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 )
238 if( !strcmp( val.psz_string, "subqcif" ) )
240 i_width = 128; i_height = 96;
242 else if( !strcmp( val.psz_string, "qsif" ) )
244 i_width = 160; i_height = 120;
246 else if( !strcmp( val.psz_string, "qcif" ) )
248 i_width = 176; i_height = 144;
250 else if( !strcmp( val.psz_string, "sif" ) )
252 i_width = 320; i_height = 240;
254 else if( !strcmp( val.psz_string, "cif" ) )
256 i_width = 352; i_height = 288;
258 else if( !strcmp( val.psz_string, "vga" ) )
260 i_width = 640; i_height = 480;
266 i_width = strtol( val.psz_string, &psz_parser, 0 );
267 if( *psz_parser == 'x' || *psz_parser == 'X')
269 i_height = strtol( psz_parser + 1, &psz_parser, 0 );
271 msg_Dbg( p_input, "Width x Height %dx%d", i_width, i_height );
274 if( val.psz_string ) free( val.psz_string );
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 )
280 i_chroma = VLC_FOURCC( val.psz_string[0], val.psz_string[1],
281 val.psz_string[2], val.psz_string[3] );
283 if( val.psz_string ) free( val.psz_string );
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;
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 );
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;
302 /* Initialize OLE/COM */
303 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
305 /* create access private data */
306 p_input->p_access_data = p_sys =
307 (access_sys_t *)malloc( sizeof( access_sys_t ) );
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;
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;
323 /* Build directshow graph */
324 CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
325 (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
327 p_sys->p_graph->QueryInterface( IID_IMediaControl,
328 (void **)&p_sys->p_control );
330 if( OpenDevice( p_input, vdevname, 0 ) != VLC_SUCCESS )
332 msg_Err( p_input, "can't open video");
335 if( OpenDevice( p_input, adevname, 1 ) != VLC_SUCCESS )
337 msg_Err( p_input, "can't open audio");
340 if( !p_sys->i_streams )
342 /* Release directshow objects */
343 if( p_sys->p_control ) p_sys->p_control->Release();
344 p_sys->p_graph->Release();
346 /* Uninitialize OLE/COM */
349 free( p_sys->p_header );
350 free( p_sys->pp_streams );
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 */;
359 vlc_mutex_init( p_input, &p_sys->lock );
360 vlc_cond_init( p_input, &p_sys->wait );
362 /* Everything is ready. Let's rock baby */
363 p_sys->p_control->Run();
368 /*****************************************************************************
369 * AccessClose: close device
370 *****************************************************************************/
371 static void AccessClose( vlc_object_t *p_this )
373 input_thread_t *p_input = (input_thread_t *)p_this;
374 access_sys_t *p_sys = p_input->p_access_data;
376 /* Stop capturing stuff */
377 p_sys->p_control->Stop();
378 p_sys->p_control->Release();
380 /* Remove filters from graph */
381 for( int i = 0; i < p_sys->i_streams; i++ )
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();
388 p_sys->p_graph->Release();
390 /* Uninitialize OLE/COM */
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 );
399 /****************************************************************************
401 ****************************************************************************/
402 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
405 IEnumPins *p_enumpins;
409 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
411 while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
413 if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
415 p_enumpins->Release();
420 p_enumpins->Release();
424 static int OpenDevice( input_thread_t *p_input, string devicename,
427 access_sys_t *p_sys = p_input->p_access_data;
428 list<string> list_devices;
430 /* Enumerate devices and display their names */
431 FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );
433 if( !list_devices.size() )
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() );
440 /* If no device name was specified, pick the 1st one */
441 if( devicename.size() == 0 )
443 devicename = *list_devices.begin();
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,
451 if( p_device_filter )
452 msg_Dbg( p_input, "using device: %s", devicename.c_str() );
455 msg_Err( p_input, "can't use device: %s", devicename.c_str() );
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,
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 );
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 );
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() ) )
478 dshow_stream_t dshow_stream;
479 dshow_stream.b_invert = VLC_FALSE;
480 dshow_stream.b_pts = VLC_FALSE;
482 p_capture_filter->CustomGetPin()->CustomGetMediaType();
484 if( dshow_stream.mt.majortype == MEDIATYPE_Video )
486 msg_Dbg( p_input, "MEDIATYPE_Video");
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' );
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' );
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' );
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' );
540 dshow_stream.header.video =
541 *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
543 int i_height = dshow_stream.header.video.bmiHeader.biHeight;
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' ) )
555 if( i_height > 0 ) dshow_stream.b_invert = VLC_TRUE;
556 else i_height = - i_height;
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' ) )
564 p_input->pf_read = ReadDV;
565 if( !p_input->psz_demux || !*p_input->psz_demux )
567 p_input->psz_demux = "rawdv";
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;
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);
591 else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&
592 dshow_stream.mt.formattype == FORMAT_WaveFormatEx )
594 msg_Dbg( p_input, "MEDIATYPE_Audio");
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' );
602 dshow_stream.header.audio =
603 *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
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;
620 /* Greatly simplifies the reading routine */
621 IAMBufferNegotiation *p_ambuf;
625 p_capture_filter->CustomGetPin()->ConnectedTo( &p_pin );
626 if( SUCCEEDED( p_pin->QueryInterface(
627 IID_IAMBufferNegotiation, (void **)&p_ambuf ) ) )
629 ALLOCATOR_PROPERTIES AllocProp;
630 memset( &AllocProp, 0, sizeof( ALLOCATOR_PROPERTIES ) );
631 p_ambuf->GetAllocatorProperties( &AllocProp );
633 i_mtu = AllocProp.cbBuffer;
638 i_mtu = dshow_stream.header.audio.nSamplesPerSec *
639 dshow_stream.header.audio.nChannels *
640 dshow_stream.header.audio.wBitsPerSample / 8;
643 p_input->i_mtu = __MAX( p_input->i_mtu, i_mtu );
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;
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 );
663 /* Remove filters from graph */
664 p_sys->p_graph->RemoveFilter( p_device_filter );
665 p_sys->p_graph->RemoveFilter( p_capture_filter );
667 /* Release objects */
668 p_device_filter->Release();
669 p_capture_filter->Release();
675 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
676 list<string> *p_listdevices, vlc_bool_t b_audio )
678 IBaseFilter *p_base_filter = NULL;
679 IMoniker *p_moniker = NULL;
683 /* Create the system device enumerator */
684 ICreateDevEnum *p_dev_enum = NULL;
686 hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
687 IID_ICreateDevEnum, (void **)&p_dev_enum );
690 msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
694 /* Create an enumerator for the video capture devices */
695 IEnumMoniker *p_class_enum = NULL;
697 hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
700 hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
702 p_dev_enum->Release();
705 msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
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 )
713 msg_Err( p_this, "no capture device was detected." );
717 /* Enumerate the devices */
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. */
723 while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
725 /* Getting the property page to get the device name */
727 hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
733 hr = p_bag->Read( L"FriendlyName", &var, NULL );
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);
743 if( p_listdevices ) p_listdevices->push_back( p_buf );
745 if( p_devicename && *p_devicename == string(p_buf) )
747 /* Bind Moniker to a filter object */
748 hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
749 (void **)&p_base_filter );
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();
758 p_moniker->Release();
759 p_class_enum->Release();
760 return p_base_filter;
765 p_moniker->Release();
768 p_class_enum->Release();
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 )
778 IEnumPins *p_enumpins;
780 IEnumMediaTypes *p_enummt;
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;
790 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return media_type;
792 /*while*/if( p_enumpins->Next( 1, &p_output_pin, NULL ) == S_OK )
795 if( SUCCEEDED( p_output_pin->EnumMediaTypes( &p_enummt ) ) )
798 while( p_enummt->Next( 1, &p_mt, NULL ) == S_OK )
801 if( p_mt->majortype == MEDIATYPE_Video )
803 int i_fourcc = VLC_FOURCC(' ', ' ', ' ', ' ');
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);
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;
829 msg_Dbg( p_this, "EnumDeviceCaps: input pin "
830 "accepts chroma: %4.4s, width:%i, height:%i",
831 (char *)&i_fourcc, i_current_width,
834 if( (!i_chroma || i_fourcc == i_chroma) &&
835 (!i_width || i_width == i_current_width) &&
836 (!i_height || i_height == i_current_height) )
838 /* Pick the 1st match */
841 i_width = i_current_width;
842 i_height = i_current_height;
846 FreeMediaType( *p_mt );
849 else if( p_mt->majortype == MEDIATYPE_Audio )
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;
859 if( p_mt->subtype == MEDIASUBTYPE_PCM )
860 i_fourcc = VLC_FOURCC( 'p', 'c', 'm', ' ' );
861 else i_fourcc = *((int *)&p_mt->subtype);
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);
869 if( (!i_channels || i_channels == i_current_channels) &&
871 i_samplespersec == i_current_samplespersec) &&
873 i_bitspersample == i_current_bitspersample) )
875 /* Pick the 1st match */
877 i_channels = i_current_channels;
878 i_samplespersec = i_current_samplespersec;
879 i_bitspersample = i_current_bitspersample;
881 /* Setup a few properties like the audio latency */
882 IAMBufferNegotiation *p_ambuf;
884 if( SUCCEEDED( p_output_pin->QueryInterface(
885 IID_IAMBufferNegotiation, (void **)&p_ambuf ) ) )
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 );
899 FreeMediaType( *p_mt );
903 CoTaskMemFree( (PVOID)p_mt );
908 p_output_pin->Release();
911 p_enumpins->Release();
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
920 *****************************************************************************/
921 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
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;
931 if( p_sys->i_header_pos )
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;
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
945 vlc_mutex_lock( &p_sys->lock );
948 for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
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 )
959 if( i_stream == p_sys->i_streams )
960 for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
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 )
970 if( i_stream == p_sys->i_streams )
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 );
978 vlc_mutex_unlock( &p_sys->lock );
983 i_data_size = sample.p_sample->GetActualDataLength();
984 sample.p_sample->GetPointer( &p_data );
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;
992 if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
994 /* Use our data timestamp */
995 i_pts = sample.i_timestamp;
996 p_stream->b_pts = VLC_TRUE;
1001 msg_Dbg( p_input, "Read() stream: %i PTS: "I64Fd, i_stream, i_pts );
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 );
1010 msg_Info( p_input, "access read %i data_size %i", i_len, i_data_size );
1013 /* First copy header */
1014 memcpy( p_buffer, p_sys->p_header, 16 /* header size */ );
1015 p_buffer += 16 /* header size */;
1017 /* Then copy stream data if any */
1018 if( !p_stream->b_invert )
1020 p_input->p_vlc->pf_memcpy( p_buffer, p_data, i_data_size );
1021 p_buffer += i_data_size;
1025 int i_width = p_stream->header.video.bmiHeader.biWidth;
1026 int i_height = p_stream->header.video.bmiHeader.biHeight;
1028 switch( p_stream->i_fourcc )
1030 case VLC_FOURCC( 'R', 'V', '1', '5' ):
1031 case VLC_FOURCC( 'R', 'V', '1', '6' ):
1034 case VLC_FOURCC( 'R', 'V', '2', '4' ):
1037 case VLC_FOURCC( 'R', 'V', '3', '2' ):
1038 case VLC_FOURCC( 'R', 'G', 'B', 'A' ):
1043 for( int i = i_height - 1; i >= 0; i-- )
1045 p_input->p_vlc->pf_memcpy( p_buffer,
1046 &p_data[i * i_width], i_width );
1048 p_buffer += i_width;
1052 sample.p_sample->Release();
1054 /* The caller got what he wanted */
1055 return p_buffer - p_buf_orig;
1058 return 0; /* never reached */
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
1066 *****************************************************************************/
1067 static ssize_t ReadDV( input_thread_t * p_input, byte_t * p_buffer,
1070 access_sys_t *p_sys = p_input->p_access_data;
1071 dshow_stream_t *p_stream = NULL;
1072 VLCMediaSample sample;
1076 /* Read 1 DV frame (they contain the video and audio data) */
1078 /* There must be only 1 elementary stream to produce a valid
1080 p_stream = p_sys->pp_streams[0];
1084 /* Get new sample/frame from the elementary stream (blocking). */
1085 vlc_mutex_lock( &p_sys->lock );
1087 if( p_stream->p_capture_filter->CustomGetPin()
1088 ->CustomGetSample( &sample ) != S_OK )
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 );
1096 vlc_mutex_unlock( &p_sys->lock );
1101 i_data_size = sample.p_sample->GetActualDataLength();
1102 sample.p_sample->GetPointer( &p_data );
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;
1110 if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
1112 /* Use our data timestamp */
1113 i_pts = sample.i_timestamp;
1114 p_stream->b_pts = VLC_TRUE;
1119 msg_Info( p_input, "access read %i data_size %i PTS: "I64Fd,
1120 i_len, i_data_size, i_pts );
1123 p_input->p_vlc->pf_memcpy( p_buffer, p_data, i_data_size );
1125 sample.p_sample->Release();
1127 /* The caller got what he wanted */
1131 return 0; /* never reached */
1134 /*****************************************************************************
1135 * Demux: local prototypes
1136 *****************************************************************************/
1143 static int Demux ( input_thread_t * );
1145 /****************************************************************************
1147 ****************************************************************************/
1148 static int DemuxOpen( vlc_object_t *p_this )
1150 input_thread_t *p_input = (input_thread_t *)p_this;
1157 /* a little test to see if it's a dshow stream */
1158 if( stream_Peek( p_input->s, &p_peek, 8 ) < 8 )
1160 msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
1161 return VLC_EGENERIC;
1164 if( strncmp( p_peek, ".dsh", 4 ) ||
1165 ( i_es = GetDWBE( &p_peek[4] ) ) <= 0 )
1167 msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
1168 return VLC_EGENERIC;
1171 vlc_mutex_lock( &p_input->stream.stream_lock );
1172 if( input_InitStream( p_input, 0 ) == -1)
1174 vlc_mutex_unlock( &p_input->stream.stream_lock );
1175 msg_Err( p_input, "cannot init stream" );
1176 return( VLC_EGENERIC );
1178 p_input->stream.i_mux_rate = 0 / 50;
1179 vlc_mutex_unlock( &p_input->stream.stream_lock );
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 ) );
1187 if( stream_Peek( p_input->s, &p_peek, 8 + 20 * i_es ) < 8 + 20 * i_es )
1189 msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
1190 return VLC_EGENERIC;
1194 for( i = 0; i < i_es; i++ )
1198 if( !strncmp( p_peek, "auds", 4 ) )
1200 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
1201 p_peek[6], p_peek[7] ) );
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 *
1210 fmt.audio.i_bitspersample;
1212 msg_Dbg( p_input, "new audio es %d channels %dHz",
1213 fmt.audio.i_channels, fmt.audio.i_rate );
1215 TAB_APPEND( p_sys->i_es, p_sys->es,
1216 es_out_Add( p_input->p_es_out, &fmt ) );
1218 else if( !strncmp( p_peek, "vids", 4 ) )
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] );
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 ) );
1236 stream_Read( p_input->s, NULL, 8 + 20 * i_es );
1241 /****************************************************************************
1243 ****************************************************************************/
1244 static void DemuxClose( vlc_object_t *p_this )
1246 input_thread_t *p_input = (input_thread_t *)p_this;
1247 demux_sys_t *p_sys = p_input->p_demux_data;
1249 if( p_sys->i_es > 0 )
1256 /****************************************************************************
1258 ****************************************************************************/
1259 static int Demux( input_thread_t *p_input )
1261 demux_sys_t *p_sys = p_input->p_demux_data;
1270 if( stream_Peek( p_input->s, &p_peek, 16 ) < 16 )
1272 msg_Warn( p_input, "cannot peek (EOF ?)" );
1276 i_es = GetDWBE( &p_peek[0] );
1277 if( i_es < 0 || i_es >= p_sys->i_es )
1279 msg_Err( p_input, "cannot find ES" );
1283 i_size = GetDWBE( &p_peek[4] );
1284 i_pts = GetQWBE( &p_peek[8] );
1286 if( ( p_block = stream_Block( p_input->s, 16 + i_size ) ) == NULL )
1288 msg_Warn( p_input, "cannot read data" );
1292 p_block->p_buffer += 16;
1293 p_block->i_buffer -= 16;
1295 /* Call the pace control. */
1296 input_ClockManageRef( p_input, p_input->stream.p_selected_program,
1300 p_block->i_pts = i_pcr <= 0 ? 0 :
1301 input_ClockGetTS( p_input, p_input->stream.p_selected_program, i_pts );
1303 es_out_Send( p_input->p_es_out, p_sys->es[i_es], p_block );
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 * )
1316 module_config_t *p_item;
1317 vlc_bool_t b_audio = VLC_FALSE;
1320 p_item = config_FindConfig( p_this, psz_name );
1321 if( !p_item ) return VLC_SUCCESS;
1323 if( !strcmp( psz_name, "dshow-adev" ) ) b_audio = VLC_TRUE;
1325 /* Clear-up the current list */
1326 if( p_item->i_list )
1328 /* Keep the 2 first entries */
1329 for( i = 2; i < p_item->i_list; i++ )
1331 free( p_item->ppsz_list[i] );
1332 free( p_item->ppsz_list_text[i] );
1334 /* TODO: Remove when no more needed */
1335 p_item->ppsz_list[i] = NULL;
1336 p_item->ppsz_list_text[i] = NULL;
1340 /* Find list of devices */
1341 list<string> list_devices;
1343 FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
1345 if( !list_devices.size() ) return VLC_SUCCESS;
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 *) );
1354 list<string>::iterator iter;
1355 for( iter = list_devices.begin(), i = 2; iter != list_devices.end();
1358 p_item->ppsz_list[i] = strdup( iter->c_str() );
1359 p_item->ppsz_list_text[i] = strdup( iter->c_str() );
1362 p_item->ppsz_list[i] = NULL;
1363 p_item->ppsz_list_text[i] = NULL;