1 /*****************************************************************************
2 * dshow.c : DirectShow access module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: dshow.cpp,v 1.7 2003/08/31 22:06:17 gbazin 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 int AccessOpen ( vlc_object_t * );
41 static void AccessClose ( vlc_object_t * );
42 static int Read ( input_thread_t *, byte_t *, size_t );
44 static int DemuxOpen ( vlc_object_t * );
45 static void DemuxClose ( vlc_object_t * );
46 static int Demux ( input_thread_t * );
48 static int OpenDevice( input_thread_t *, string, vlc_bool_t );
49 static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
50 list<string> *, vlc_bool_t );
51 static AM_MEDIA_TYPE EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
52 vlc_bool_t, int, int, int );
53 static bool ConnectFilters( IFilterGraph *, IBaseFilter *, IPin * );
55 /*****************************************************************************
57 *****************************************************************************/
58 #define CACHING_TEXT N_("Caching value in ms")
59 #define CACHING_LONGTEXT N_( \
60 "Allows you to modify the default caching value for directshow streams. " \
61 "This value should be set in miliseconds units." )
64 set_description( _("DirectShow input") );
65 add_category_hint( N_("dshow"), NULL, VLC_TRUE );
66 add_integer( "dshow-caching", DEFAULT_PTS_DELAY / 1000, NULL,
67 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
68 add_shortcut( "dshow" );
69 set_capability( "access", 0 );
70 set_callbacks( AccessOpen, AccessClose );
73 set_description( _("DirectShow demuxer") );
74 add_shortcut( "dshow" );
75 set_capability( "demux", 200 );
76 set_callbacks( DemuxOpen, DemuxClose );
80 /****************************************************************************
82 ****************************************************************************/
105 static void SetDWBE( uint8_t *p, uint32_t dw )
107 p[0] = (dw >> 24)&0xff;
108 p[1] = (dw >> 16)&0xff;
109 p[2] = (dw >> 8)&0xff;
113 static void SetQWBE( uint8_t *p, uint64_t qw )
115 SetDWBE( p, (qw >> 32)&0xffffffff );
116 SetDWBE( &p[4], qw&0xffffffff );
119 /****************************************************************************
120 * DirectShow elementary stream descriptor
121 ****************************************************************************/
122 typedef struct dshow_stream_t
125 IBaseFilter *p_device_filter;
126 CaptureFilter *p_capture_filter;
133 VIDEOINFOHEADER video;
138 VLCMediaSample sample;
145 /****************************************************************************
146 * Access descriptor declaration
147 ****************************************************************************/
150 IFilterGraph *p_graph;
151 IMediaControl *p_control;
158 /* list of elementary streams */
159 dshow_stream_t **pp_streams;
161 int i_current_stream;
163 /* misc properties */
169 /*****************************************************************************
170 * Open: open direct show device
171 *****************************************************************************/
172 static int AccessOpen( vlc_object_t *p_this )
174 input_thread_t *p_input = (input_thread_t *)p_this;
177 /* parse url and open device(s) */
178 char *psz_dup, *psz_parser;
179 psz_dup = strdup( p_input->psz_name );
180 psz_parser = psz_dup;
181 string vdevname, adevname;
182 int i_width = 0, i_height = 0, i_chroma = VLC_FOURCC('I','4','2','0');
184 while( *psz_parser && *psz_parser != ':' )
189 if( *psz_parser == ':' )
196 *psz_parser++ = '\0';
197 if( !strncmp( psz_parser, "vdev=", strlen( "vdev=" ) ) )
199 psz_parser += strlen( "vdev=" );
200 if( strchr( psz_parser, ':' ) )
202 i_len = strchr( psz_parser, ':' ) - psz_parser;
206 i_len = strlen( psz_parser );
209 vdevname = string( psz_parser, i_len );
213 else if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) ) )
215 psz_parser += strlen( "adev=" );
216 if( strchr( psz_parser, ':' ) )
218 i_len = strchr( psz_parser, ':' ) - psz_parser;
222 i_len = strlen( psz_parser );
225 adevname = string( psz_parser, i_len );
229 else if( !strncmp( psz_parser, "size=", strlen( "size=" ) ) )
231 psz_parser += strlen( "size=" );
232 if( !strncmp( psz_parser, "subqcif", strlen( "subqcif" ) ) )
237 else if( !strncmp( psz_parser, "qsif", strlen( "qsif" ) ) )
242 else if( !strncmp( psz_parser, "qcif", strlen( "qcif" ) ) )
247 else if( !strncmp( psz_parser, "sif", strlen( "sif" ) ) )
252 else if( !strncmp( psz_parser, "cif", strlen( "cif" ) ) )
257 else if( !strncmp( psz_parser, "vga", strlen( "vga" ) ) )
265 i_width = strtol( psz_parser, &psz_parser, 0 );
266 if( *psz_parser == 'x' || *psz_parser == 'X')
268 i_height = strtol( psz_parser + 1, &psz_parser, 0 );
270 msg_Dbg( p_input, "WidthxHeight %dx%d", i_width, i_height );
273 else if( !strncmp( psz_parser, "chroma=", strlen( "chroma=" ) ) )
275 psz_parser += strlen( "chroma=" );
276 if( strlen( psz_parser ) >= 4 )
278 i_chroma = VLC_FOURCC( psz_parser[0],psz_parser[1],
279 psz_parser[2],psz_parser[3] );
284 msg_Warn( p_input, "unknown option" );
287 while( *psz_parser && *psz_parser != ':' )
292 if( *psz_parser == '\0' )
301 p_input->pf_read = Read;
302 p_input->pf_seek = NULL;
303 p_input->pf_set_area = NULL;
304 p_input->pf_set_program = NULL;
306 vlc_mutex_lock( &p_input->stream.stream_lock );
307 p_input->stream.b_pace_control = 0;
308 p_input->stream.b_seekable = 0;
309 p_input->stream.p_selected_area->i_size = 0;
310 p_input->stream.p_selected_area->i_tell = 0;
311 p_input->stream.i_method = INPUT_METHOD_FILE;
312 vlc_mutex_unlock( &p_input->stream.stream_lock );
313 p_input->i_pts_delay = config_GetInt( p_input, "dshow-caching" ) * 1000;
315 /* Initialize OLE/COM */
316 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
318 /* create access private data */
319 p_input->p_access_data = p_sys =
320 (access_sys_t *)malloc( sizeof( access_sys_t ) );
322 /* Initialize some data */
323 p_sys->i_streams = 0;
324 p_sys->pp_streams = (dshow_stream_t **)malloc( 1 );
325 p_sys->i_width = i_width;
326 p_sys->i_height = i_height;
327 p_sys->i_chroma = i_chroma;
330 p_sys->i_header_size = 8;
331 p_sys->p_header = (uint8_t *)malloc( p_sys->i_header_size );
332 memcpy( &p_sys->p_header[0], ".dsh", 4 );
333 SetDWBE( &p_sys->p_header[4], 1 );
334 p_sys->i_header_pos = p_sys->i_header_size;
336 /* Build directshow graph */
337 CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
338 (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
340 p_sys->p_graph->QueryInterface( IID_IMediaControl,
341 (void **)&p_sys->p_control );
343 if( OpenDevice( p_input, vdevname, 0 ) != VLC_SUCCESS )
345 msg_Err( p_input, "can't open video");
348 if( OpenDevice( p_input, adevname, 1 ) != VLC_SUCCESS )
350 msg_Err( p_input, "can't open audio");
353 if( !p_sys->i_streams )
355 /* Release directshow objects */
356 if( p_sys->p_control ) p_sys->p_control->Release();
357 p_sys->p_graph->Release();
359 /* Uninitialize OLE/COM */
362 free( p_sys->p_header );
363 free( p_sys->pp_streams );
368 /* Initialize some data */
369 p_sys->i_current_stream = 0;
370 p_sys->i_header_pos = 0;
372 /* Everything is ready. Let's rock baby */
373 p_sys->p_control->Run();
378 /*****************************************************************************
379 * AccessClose: close device
380 *****************************************************************************/
381 static void AccessClose( vlc_object_t *p_this )
383 input_thread_t *p_input = (input_thread_t *)p_this;
384 access_sys_t *p_sys = p_input->p_access_data;
386 /* Stop capturing stuff */
387 p_sys->p_control->Stop();
388 p_sys->p_control->Release();
390 /* Remove filters from graph */
391 for( int i = 0; i < p_sys->i_streams; i++ )
393 p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );
394 p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );
395 p_sys->pp_streams[i]->p_device_filter->Release();
396 p_sys->pp_streams[i]->p_capture_filter->Release();
398 p_sys->p_graph->Release();
400 /* Uninitialize OLE/COM */
403 free( p_sys->p_header );
404 for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];
405 free( p_sys->pp_streams );
409 /****************************************************************************
411 ****************************************************************************/
412 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
415 IEnumPins *p_enumpins;
419 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
421 while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
423 if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
425 p_enumpins->Release();
430 p_enumpins->Release();
434 static int OpenDevice( input_thread_t *p_input, string devicename,
437 access_sys_t *p_sys = p_input->p_access_data;
438 list<string> list_devices;
440 /* Enumerate devices and display their names */
441 FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );
443 if( !list_devices.size() )
446 list<string>::iterator iter;
447 for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
448 msg_Dbg( p_input, "found device: %s", iter->c_str() );
450 /* If no device name was specified, pick the 1st one */
451 if( devicename.size() == 0 )
453 devicename = *list_devices.begin();
456 // Use the system device enumerator and class enumerator to find
457 // a capture/preview device, such as a desktop USB video camera.
458 IBaseFilter *p_device_filter =
459 FindCaptureDevice( (vlc_object_t *)p_input, &devicename,
461 if( p_device_filter )
462 msg_Dbg( p_input, "using device: %s", devicename.c_str() );
465 msg_Err( p_input, "can't use device: %s", devicename.c_str() );
469 AM_MEDIA_TYPE media_type =
470 EnumDeviceCaps( (vlc_object_t *)p_input, p_device_filter, b_audio,
471 p_sys->i_chroma, p_sys->i_width, p_sys->i_height );
473 /* Create and add our capture filter */
474 CaptureFilter *p_capture_filter = new CaptureFilter( p_input, media_type );
475 p_sys->p_graph->AddFilter( p_capture_filter, 0 );
477 /* Add the device filter to the graph (seems necessary with VfW before
478 * accessing pin attributes). */
479 p_sys->p_graph->AddFilter( p_device_filter, 0 );
481 /* Attempt to connect one of this device's capture output pins */
482 msg_Dbg( p_input, "connecting filters" );
483 if( ConnectFilters( p_sys->p_graph, p_device_filter,
484 p_capture_filter->CustomGetPin() ) )
487 dshow_stream_t dshow_stream;
488 dshow_stream.b_invert = VLC_FALSE;
490 p_capture_filter->CustomGetPin()->CustomGetMediaType();
492 if( dshow_stream.mt.majortype == MEDIATYPE_Video )
494 msg_Dbg( p_input, "MEDIATYPE_Video");
496 /* Packed RGB formats */
497 if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB1 )
498 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
499 if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB4 )
500 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
501 if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB8 )
502 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
503 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB555 )
504 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
505 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB565 )
506 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
507 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB24 )
508 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
509 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB32 )
510 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
511 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_ARGB32 )
512 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
514 /* Packed YUV formats */
515 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVYU )
516 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
517 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUYV )
518 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
519 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )
520 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
521 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y211 )
522 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', '2', '1', '1' );
523 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUY2 ||
524 dshow_stream.mt.subtype == MEDIASUBTYPE_UYVY )
525 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
527 /* Planar YUV formats */
528 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_I420 )
529 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
530 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y41P )
531 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
532 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YV12 ||
533 dshow_stream.mt.subtype == MEDIASUBTYPE_IYUV )
534 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
535 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVU9 )
536 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'U', '9' );
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 /* Add video stream to header */
560 p_sys->i_header_size += 20;
561 p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
562 p_sys->i_header_size );
563 memcpy( &p_sys->p_header[p_sys->i_header_pos], "vids", 4 );
564 memcpy( &p_sys->p_header[p_sys->i_header_pos + 4],
565 &dshow_stream.i_fourcc, 4 );
566 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
567 dshow_stream.header.video.bmiHeader.biWidth );
568 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12], i_height );
569 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16], 0 );
570 p_sys->i_header_pos = p_sys->i_header_size;
573 else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&
574 dshow_stream.mt.formattype == FORMAT_WaveFormatEx )
576 msg_Dbg( p_input, "MEDIATYPE_Audio");
578 if( dshow_stream.mt.subtype == MEDIASUBTYPE_PCM )
579 dshow_stream.i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
581 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_IEEE_FLOAT )
582 dshow_stream.i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );
586 dshow_stream.header.audio =
587 *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
589 /* Add audio stream to header */
590 p_sys->i_header_size += 20;
591 p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
592 p_sys->i_header_size );
593 memcpy( &p_sys->p_header[p_sys->i_header_pos], "auds", 4 );
594 memcpy( &p_sys->p_header[p_sys->i_header_pos + 4],
595 &dshow_stream.i_fourcc, 4 );
596 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
597 dshow_stream.header.audio.nChannels );
598 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],
599 dshow_stream.header.audio.nSamplesPerSec );
600 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16],
601 dshow_stream.header.audio.wBitsPerSample );
602 p_sys->i_header_pos = p_sys->i_header_size;
606 /* Add directshow elementary stream to our list */
607 dshow_stream.sample.p_sample = NULL;
608 dshow_stream.i_data_size = 0;
609 dshow_stream.i_data_pos = 0;
610 dshow_stream.p_device_filter = p_device_filter;
611 dshow_stream.p_capture_filter = p_capture_filter;
614 (dshow_stream_t **)realloc( p_sys->pp_streams,
615 sizeof(dshow_stream_t *)
616 * (p_sys->i_streams + 1) );
617 p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
618 *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
619 SetDWBE( &p_sys->p_header[4], (uint32_t)p_sys->i_streams );
625 /* Remove filters from graph */
626 p_sys->p_graph->RemoveFilter( p_device_filter );
627 p_sys->p_graph->RemoveFilter( p_capture_filter );
629 /* Release objects */
630 p_device_filter->Release();
631 p_capture_filter->Release();
637 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
638 list<string> *p_listdevices, vlc_bool_t b_audio )
640 IBaseFilter *p_base_filter = NULL;
641 IMoniker *p_moniker = NULL;
645 /* Create the system device enumerator */
646 ICreateDevEnum *p_dev_enum = NULL;
648 hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
649 IID_ICreateDevEnum, (void **)&p_dev_enum );
652 msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
656 /* Create an enumerator for the video capture devices */
657 IEnumMoniker *p_class_enum = NULL;
659 hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
662 hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
664 p_dev_enum->Release();
667 msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
671 /* If there are no enumerators for the requested type, then
672 * CreateClassEnumerator will succeed, but p_class_enum will be NULL */
673 if( p_class_enum == NULL )
675 msg_Err( p_this, "no capture device was detected." );
679 /* Enumerate the devices */
681 /* Note that if the Next() call succeeds but there are no monikers,
682 * it will return S_FALSE (which is not a failure). Therefore, we check
683 * that the return code is S_OK instead of using SUCCEEDED() macro. */
685 while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
687 /* Getting the property page to get the device name */
689 hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
695 hr = p_bag->Read( L"FriendlyName", &var, NULL );
699 int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
700 char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
701 WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
702 i_convert, NULL, NULL );
703 SysFreeString(var.bstrVal);
705 if( p_listdevices ) p_listdevices->push_back( p_buf );
707 if( p_devicename && *p_devicename == string(p_buf) )
709 /* Bind Moniker to a filter object */
710 hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
711 (void **)&p_base_filter );
714 msg_Err( p_this, "couldn't bind moniker to filter "
715 "object (0x%x)", hr );
716 p_moniker->Release();
717 p_class_enum->Release();
720 p_moniker->Release();
721 p_class_enum->Release();
722 return p_base_filter;
727 p_moniker->Release();
730 p_class_enum->Release();
734 static AM_MEDIA_TYPE EnumDeviceCaps( vlc_object_t *p_this,
735 IBaseFilter *p_filter, vlc_bool_t b_audio,
736 int i_chroma, int i_width, int i_height )
738 IEnumPins *p_enumpins;
740 IEnumMediaTypes *p_enummt;
742 AM_MEDIA_TYPE media_type;
743 media_type.majortype = GUID_NULL;
744 media_type.subtype = GUID_NULL;
745 media_type.formattype = GUID_NULL;
746 media_type.pUnk = NULL;
747 media_type.cbFormat = 0;
748 media_type.pbFormat = NULL;
750 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return media_type;
752 /*while*/if( p_enumpins->Next( 1, &p_output_pin, NULL ) == S_OK )
756 SUCCEEDED( p_output_pin->EnumMediaTypes( &p_enummt ) ) )
759 while( p_enummt->Next( 1, &p_mt, NULL ) == S_OK )
761 int i_fourcc = VLC_FOURCC(' ', ' ', ' ', ' ');
763 /* Packed RGB formats */
764 if( p_mt->subtype == MEDIASUBTYPE_RGB1 )
765 i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
766 if( p_mt->subtype == MEDIASUBTYPE_RGB4 )
767 i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
768 if( p_mt->subtype == MEDIASUBTYPE_RGB8 )
769 i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
770 else if( p_mt->subtype == MEDIASUBTYPE_RGB555 )
771 i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
772 else if( p_mt->subtype == MEDIASUBTYPE_RGB565 )
773 i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
774 else if( p_mt->subtype == MEDIASUBTYPE_RGB24 )
775 i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
776 else if( p_mt->subtype == MEDIASUBTYPE_RGB32 )
777 i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
778 else if( p_mt->subtype == MEDIASUBTYPE_ARGB32 )
779 i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
780 else i_fourcc = *((int *)&p_mt->subtype);
782 int i_current_width = p_mt->pbFormat ?
783 ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biWidth : 0;
784 int i_current_height = p_mt->pbFormat ?
785 ((VIDEOINFOHEADER *)p_mt->pbFormat)->bmiHeader.biHeight : 0;
787 msg_Dbg( p_this, "EnumDeviceCaps: input pin "
788 "accepts chroma: %4.4s, width:%i, height:%i",
789 (char *)&i_fourcc, i_current_width,
792 if( i_fourcc == i_chroma )
794 media_type.subtype = p_mt->subtype;
797 if( i_fourcc == i_chroma && p_mt->pbFormat &&
798 i_width && i_height && i_width == i_current_width &&
799 i_height == i_current_height )
805 FreeMediaType( *p_mt );
807 CoTaskMemFree( (PVOID)p_mt );
811 p_output_pin->Release();
814 p_enumpins->Release();
818 /*****************************************************************************
819 * Read: reads from the device into PES packets.
820 *****************************************************************************
821 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
823 *****************************************************************************/
824 static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
826 access_sys_t *p_sys = p_input->p_access_data;
827 dshow_stream_t *p_stream = p_sys->pp_streams[p_sys->i_current_stream];
831 msg_Info( p_input, "access read data_size %i, data_pos %i",
832 p_sys->i_data_size, p_sys->i_data_pos );
837 /* First copy header if any */
838 if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
842 i_copy = __MIN( p_sys->i_header_size -
843 p_sys->i_header_pos, (int)i_len );
844 memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );
845 p_sys->i_header_pos += i_copy;
852 /* Then copy stream data if any */
853 if( i_len > 0 && p_stream->i_data_pos < p_stream->i_data_size )
855 int i_copy = __MIN( p_stream->i_data_size -
856 p_stream->i_data_pos, (int)i_len );
858 if( !p_stream->b_invert )
860 p_input->p_vlc->pf_memcpy( p_buffer,
861 &p_stream->p_data[p_stream->i_data_pos], i_copy );
866 int i_width = p_stream->header.video.bmiHeader.biWidth;
867 int i_height = p_stream->header.video.bmiHeader.biHeight;
869 switch( p_stream->i_fourcc )
871 case VLC_FOURCC( 'R', 'V', '1', '5' ):
872 case VLC_FOURCC( 'R', 'V', '1', '6' ):
875 case VLC_FOURCC( 'R', 'V', '2', '4' ):
878 case VLC_FOURCC( 'R', 'V', '3', '2' ):
879 case VLC_FOURCC( 'R', 'G', 'B', 'A' ):
884 int i_line_pos = i_height - 1 - p_stream->i_data_pos / i_width;
885 int i_offset = p_stream->i_data_pos % i_width;
887 i_copied = __MIN( i_width - i_offset, i_copy );
889 /* copy already started line if any */
893 &p_stream->p_data[i_line_pos * i_width + i_offset],
896 p_stream->i_data_pos += i_copied;
897 p_buffer += i_copied;
903 /* The caller got what he wanted */
904 if( i_len <= 0 ) return i_data;
906 i_line_pos = i_height - 1 - p_stream->i_data_pos / i_width;
907 i_copied = i_copy / i_width;
911 memcpy( p_buffer, &p_stream->p_data[i_line_pos * i_width],
913 p_stream->i_data_pos += i_width;
922 /* copy left over if any */
925 memcpy( p_buffer, &p_stream->p_data[i_line_pos * i_width],
930 p_stream->i_data_pos += i_copy;
936 /* The caller got what he wanted */
937 if( i_len <= 0 ) return i_data;
939 /* Read no more than one frame at a time, otherwise we kill latency */
940 if( p_stream->i_data_size && i_data &&
941 p_stream->i_data_pos == p_stream->i_data_size )
943 p_stream->i_data_pos = p_stream->i_data_size = 0;
947 /* Get new sample/frame from next stream */
948 if( p_stream->sample.p_sample )
950 p_stream->sample.p_sample->Release();
951 p_stream->sample.p_sample = NULL;
953 p_sys->i_current_stream =
954 (p_sys->i_current_stream + 1) % p_sys->i_streams;
955 p_stream = p_sys->pp_streams[p_sys->i_current_stream];
956 if( p_stream->p_capture_filter &&
957 p_stream->p_capture_filter->CustomGetPin()
958 ->CustomGetSample( &p_stream->sample ) == S_OK )
960 p_stream->i_data_pos = 0;
961 p_stream->i_data_size =
962 p_stream->sample.p_sample->GetActualDataLength();
963 p_stream->sample.p_sample->GetPointer( &p_stream->p_data );
965 REFERENCE_TIME i_pts, i_end_date;
967 p_stream->sample.p_sample->GetTime( &i_pts, &i_end_date );
968 if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
972 /* Use our data timestamp */
973 i_pts = p_stream->sample.i_timestamp;
977 msg_Dbg( p_input, "Read() stream: %i PTS: "I64Fd,
978 p_sys->i_current_stream, i_pts );
981 /* Create pseudo header */
982 p_sys->i_header_size = 16;
983 p_sys->i_header_pos = 0;
984 SetDWBE( &p_sys->p_header[0], p_sys->i_current_stream );
985 SetDWBE( &p_sys->p_header[4], p_stream->i_data_size );
986 SetQWBE( &p_sys->p_header[8], i_pts * 9 / 1000 );
994 /****************************************************************************
996 ****************************************************************************/
997 static int DemuxOpen( vlc_object_t *p_this )
999 input_thread_t *p_input = (input_thread_t *)p_this;
1005 data_packet_t *p_pk;
1007 /* Initialize access plug-in structures. */
1008 if( p_input->i_mtu == 0 )
1010 /* Improve speed. */
1011 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
1014 /* a little test to see if it's a dshow stream */
1015 if( input_Peek( p_input, &p_peek, 8 ) < 8 )
1017 msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
1018 return( VLC_EGENERIC );
1021 if( strcmp( (const char *)p_peek, ".dsh" ) ||
1022 GetDWBE( &p_peek[4] ) <= 0 )
1024 msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
1025 return VLC_EGENERIC;
1028 /* create one program */
1029 vlc_mutex_lock( &p_input->stream.stream_lock );
1030 if( input_InitStream( p_input, 0 ) == -1)
1032 vlc_mutex_unlock( &p_input->stream.stream_lock );
1033 msg_Err( p_input, "cannot init stream" );
1034 return( VLC_EGENERIC );
1036 if( input_AddProgram( p_input, 0, 0) == NULL )
1038 vlc_mutex_unlock( &p_input->stream.stream_lock );
1039 msg_Err( p_input, "cannot add program" );
1040 return( VLC_EGENERIC );
1043 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
1044 p_input->stream.i_mux_rate = 0;
1046 i_streams = GetDWBE( &p_peek[4] );
1047 if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
1048 < 8 + 20 * i_streams )
1050 msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
1051 return( VLC_EGENERIC );
1055 for( i = 0; i < i_streams; i++ )
1057 es_descriptor_t *p_es;
1059 if( !strncmp( (const char *)p_peek, "auds", 4 ) )
1061 #define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
1062 p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
1063 i + 1, AUDIO_ES, NULL, 0 );
1064 p_es->i_stream_id = i + 1;
1066 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
1068 p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
1070 wf->wFormatTag = 0;//WAVE_FORMAT_UNKNOWN;
1071 wf->nChannels = GetDWBE( &p_peek[8] );
1072 wf->nSamplesPerSec = GetDWBE( &p_peek[12] );
1073 wf->wBitsPerSample = GetDWBE( &p_peek[16] );
1074 wf->nBlockAlign = wf->wBitsPerSample * wf->nChannels / 8;
1075 wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
1078 msg_Dbg( p_input, "added new audio es %d channels %dHz",
1079 wf->nChannels, wf->nSamplesPerSec );
1081 input_SelectES( p_input, p_es );
1084 else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
1086 #define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
1087 p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
1088 i + 1, VIDEO_ES, NULL, 0 );
1089 p_es->i_stream_id = i + 1;
1091 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
1093 p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
1095 bih->biSize = sizeof( BITMAPINFOHEADER );
1096 bih->biWidth = GetDWBE( &p_peek[8] );
1097 bih->biHeight = GetDWBE( &p_peek[12] );
1099 bih->biBitCount = 0;
1100 bih->biCompression = 0;
1101 bih->biSizeImage= 0;
1102 bih->biXPelsPerMeter = 0;
1103 bih->biYPelsPerMeter = 0;
1105 bih->biClrImportant = 0;
1107 msg_Dbg( p_input, "added new video es %4.4s %dx%d",
1108 (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
1110 input_SelectES( p_input, p_es );
1117 p_input->stream.p_selected_program->b_is_ok = 1;
1118 vlc_mutex_unlock( &p_input->stream.stream_lock );
1120 if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
1122 input_DeletePacket( p_input->p_method_data, p_pk );
1125 p_input->pf_demux = Demux;
1129 static void DemuxClose( vlc_object_t *p_this )
1134 static int Demux( input_thread_t *p_input )
1136 es_descriptor_t *p_es;
1137 pes_packet_t *p_pes;
1144 if( input_Peek( p_input, &p_peek, 16 ) < 16 )
1146 msg_Warn( p_input, "cannot peek (EOF ?)" );
1150 i_stream = GetDWBE( &p_peek[0] );
1151 i_size = GetDWBE( &p_peek[4] );
1152 i_pcr = GetQWBE( &p_peek[8] );
1154 //msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
1155 //p_es = input_FindES( p_input, i_stream );
1157 p_es = p_input->stream.p_selected_program->pp_es[i_stream];
1160 msg_Err( p_input, "cannot find ES" );
1163 p_pes = input_NewPES( p_input->p_method_data );
1166 msg_Warn( p_input, "cannot allocate PES" );
1173 data_packet_t *p_data;
1176 if( (i_read = input_SplitBuffer( p_input, &p_data,
1177 __MIN( i_size, 10000 ) ) ) <= 0 )
1179 input_DeletePES( p_input->p_method_data, p_pes );
1182 if( !p_pes->p_first )
1184 p_pes->p_first = p_data;
1185 p_pes->i_nb_data = 1;
1186 p_pes->i_pes_size = i_read;
1190 p_pes->p_last->p_next = p_data;
1192 p_pes->i_pes_size += i_read;
1194 p_pes->p_last = p_data;
1198 p_pes->p_first->p_payload_start += 16;
1199 p_pes->i_pes_size -= 16;
1201 if( p_es && p_es->p_decoder_fifo )
1203 /* Call the pace control. */
1204 input_ClockManageRef( p_input, p_input->stream.p_selected_program,
1207 p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
1208 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
1211 input_DecodePES( p_es->p_decoder_fifo, p_pes );
1215 input_DeletePES( p_input->p_method_data, p_pes );