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 $
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>
44 # define _I64_MAX LONG_LONG_MAX
45 # define LONGLONG long long
52 /*****************************************************************************
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 );
59 static int DemuxOpen ( vlc_object_t * );
60 static void DemuxClose ( vlc_object_t * );
61 static int Demux ( input_thread_t * );
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,
69 /*****************************************************************************
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." )
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 );
87 set_description( _("DirectShow demuxer") );
88 add_shortcut( "dshow" );
89 set_capability( "demux", 200 );
90 set_callbacks( DemuxOpen, DemuxClose );
94 /****************************************************************************
96 ****************************************************************************/
102 * fcc "auds"|"vids" 0
119 static void SetDWBE( uint8_t *p, uint32_t dw )
121 p[0] = (dw >> 24)&0xff;
122 p[1] = (dw >> 16)&0xff;
123 p[2] = (dw >> 8)&0xff;
127 static void SetQWBE( uint8_t *p, uint64_t qw )
129 SetDWBE( p, (qw >> 32)&0xffffffff );
130 SetDWBE( &p[4], qw&0xffffffff );
133 /****************************************************************************
134 * DirectShow elementary stream descriptor
135 ****************************************************************************/
136 typedef struct dshow_stream_t
139 IBaseFilter *p_device_filter;
140 CaptureFilter *p_capture_filter;
146 VIDEOINFOHEADER video;
151 VLCMediaSample sample;
158 /****************************************************************************
159 * Access descriptor declaration
160 ****************************************************************************/
163 IFilterGraph *p_graph;
164 IMediaControl *p_control;
171 /* list of elementary streams */
172 dshow_stream_t **pp_streams;
174 int i_current_stream;
177 /*****************************************************************************
178 * Open: open direct show device
179 *****************************************************************************/
180 static int AccessOpen( vlc_object_t *p_this )
182 input_thread_t *p_input = (input_thread_t *)p_this;
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;
191 while( *psz_parser && *psz_parser != ':' )
196 if( *psz_parser == ':' )
203 *psz_parser++ = '\0';
204 if( !strncmp( psz_parser, "vdev=", strlen( "vdev=" ) ) )
206 psz_parser += strlen( "vdev=" );
207 if( strchr( psz_parser, ':' ) )
209 i_len = strchr( psz_parser, ':' ) - psz_parser;
213 i_len = strlen( psz_parser );
216 vdevname = string( psz_parser, i_len );
220 else if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) ) )
222 psz_parser += strlen( "adev=" );
223 if( strchr( psz_parser, ':' ) )
225 i_len = strchr( psz_parser, ':' ) - psz_parser;
229 i_len = strlen( psz_parser );
232 adevname = string( psz_parser, i_len );
238 msg_Warn( p_input, "unknown option" );
241 while( *psz_parser && *psz_parser != ':' )
246 if( *psz_parser == '\0' )
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;
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;
269 /* Initialize OLE/COM */
270 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
272 /* create access private data */
273 p_input->p_access_data = p_sys =
274 (access_sys_t *)malloc( sizeof( access_sys_t ) );
276 /* Initialize some data */
277 p_sys->i_streams = 0;
278 p_sys->pp_streams = (dshow_stream_t **)malloc( 1 );
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;
287 /* Build directshow graph */
288 CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
289 (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
291 p_sys->p_graph->QueryInterface( IID_IMediaControl,
292 (void **)&p_sys->p_control );
294 if( OpenDevice( p_input, vdevname, 0 ) != VLC_SUCCESS )
296 msg_Err( p_input, "can't open video");
299 if( OpenDevice( p_input, adevname, 1 ) != VLC_SUCCESS )
301 msg_Err( p_input, "can't open audio");
304 if( !p_sys->i_streams )
306 /* Release directshow objects */
307 p_sys->p_control->Release();
308 p_sys->p_graph->Release();
310 /* Uninitialize OLE/COM */
313 free( p_sys->p_header );
318 /* Initialize some data */
319 p_sys->i_current_stream = 0;
320 p_sys->i_header_pos = 0;
322 /* Everything is ready. Let's rock baby */
323 p_sys->p_control->Run();
328 /*****************************************************************************
329 * AccessClose: close device
330 *****************************************************************************/
331 static void AccessClose( vlc_object_t *p_this )
333 input_thread_t *p_input = (input_thread_t *)p_this;
334 access_sys_t *p_sys = p_input->p_access_data;
336 /* Stop capturing stuff */
337 p_sys->p_control->Stop();
338 p_sys->p_control->Release();
340 /* Remove filters from graph */
341 for( int i = 0; i < p_sys->i_streams; i++ )
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();
348 p_sys->p_graph->Release();
350 /* Uninitialize OLE/COM */
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 );
359 /****************************************************************************
361 ****************************************************************************/
362 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
365 IEnumPins *p_enumpins;
369 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
371 while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
373 if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
375 p_enumpins->Release();
380 p_enumpins->Release();
384 static int OpenDevice( input_thread_t *p_input, string devicename,
387 access_sys_t *p_sys = p_input->p_access_data;
388 list<string> list_devices;
390 /* Enumerate audio devices and display their names */
391 FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );
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() );
397 /* If no device name was specified, pick the 1st one */
398 if( devicename.size() == 0 )
400 devicename = *list_devices.begin();
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,
408 if( p_device_filter )
409 msg_Dbg( p_input, "using device: %s", devicename.c_str() );
412 msg_Err( p_input, "can't use device: %s", devicename.c_str() );
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 );
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 );
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() ) )
430 dshow_stream_t dshow_stream;
432 p_capture_filter->CustomGetPin()->CustomGetMediaType();
434 if( dshow_stream.mt.majortype == MEDIATYPE_Video )
436 msg_Dbg( p_input, "MEDIATYPE_Video");
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' );
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' );
467 dshow_stream.header.video =
468 *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
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;
485 else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&
486 dshow_stream.mt.formattype == FORMAT_WaveFormatEx )
488 msg_Dbg( p_input, "MEDIATYPE_Audio");
490 if( dshow_stream.mt.subtype == MEDIASUBTYPE_PCM )
491 dshow_stream.i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
493 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_IEEE_FLOAT )
494 dshow_stream.i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );
498 dshow_stream.header.audio =
499 *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
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;
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;
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 );
537 /* Remove filters from graph */
538 p_sys->p_graph->RemoveFilter( p_device_filter );
539 p_sys->p_graph->RemoveFilter( p_capture_filter );
541 /* Release objects */
542 p_device_filter->Release();
543 p_capture_filter->Release();
549 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
550 list<string> *p_listdevices, vlc_bool_t b_audio )
552 IBaseFilter *p_base_filter = NULL;
553 IMoniker *p_moniker = NULL;
557 /* Create the system device enumerator */
558 ICreateDevEnum *p_dev_enum = NULL;
560 hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
561 IID_ICreateDevEnum, (void **)&p_dev_enum );
564 msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
568 /* Create an enumerator for the video capture devices */
569 IEnumMoniker *p_class_enum = NULL;
571 hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
574 hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
576 p_dev_enum->Release();
579 msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
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 )
587 msg_Err( p_this, "no capture device was detected." );
591 /* Enumerate the devices */
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. */
597 while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
599 /* Getting the property page to get the device name */
601 hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
607 hr = p_bag->Read( L"FriendlyName", &var, NULL );
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);
617 if( p_listdevices ) p_listdevices->push_back( p_buf );
619 if( p_devicename && *p_devicename == string(p_buf) )
621 /* Bind Moniker to a filter object */
622 hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
623 (void **)&p_base_filter );
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();
632 p_moniker->Release();
633 p_class_enum->Release();
634 return p_base_filter;
639 p_moniker->Release();
642 p_class_enum->Release();
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
651 *****************************************************************************/
652 static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
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];
659 msg_Info( p_input, "access read data_size %i, data_pos %i",
660 p_sys->i_data_size, p_sys->i_data_pos );
665 /* First copy header if any */
666 if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
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;
680 /* Then copy stream data if any */
681 if( i_len > 0 && p_stream->i_data_pos < p_stream->i_data_size )
683 int i_copy = __MIN( p_stream->i_data_size -
684 p_stream->i_data_pos, (int)i_len );
686 memcpy( p_buffer, &p_stream->p_data[p_stream->i_data_pos],
688 p_stream->i_data_pos += i_copy;
695 /* The caller got what he wanted */
696 if( i_len <= 0 ) return i_data;
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 )
702 p_stream->i_data_pos = p_stream->i_data_size = 0;
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 )
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 );
720 REFERENCE_TIME i_pts, i_end_date;
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;
727 /* Use our data timestamp */
728 i_pts = p_stream->sample.i_timestamp;
732 msg_Dbg( p_input, "Read() PTS: "I64Fd, i_pts );
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 );
742 else msleep( 10000 );
748 /****************************************************************************
750 ****************************************************************************/
751 static int DemuxOpen( vlc_object_t *p_this )
753 input_thread_t *p_input = (input_thread_t *)p_this;
761 /* Initialize access plug-in structures. */
762 if( p_input->i_mtu == 0 )
765 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
768 /* a little test to see if it's a dshow stream */
769 if( input_Peek( p_input, &p_peek, 8 ) < 8 )
771 msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
772 return( VLC_EGENERIC );
775 if( strcmp( (const char *)p_peek, ".dsh" ) ||
776 GetDWBE( &p_peek[4] ) <= 0 )
778 msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
782 /* create one program */
783 vlc_mutex_lock( &p_input->stream.stream_lock );
784 if( input_InitStream( p_input, 0 ) == -1)
786 vlc_mutex_unlock( &p_input->stream.stream_lock );
787 msg_Err( p_input, "cannot init stream" );
788 return( VLC_EGENERIC );
790 if( input_AddProgram( p_input, 0, 0) == NULL )
792 vlc_mutex_unlock( &p_input->stream.stream_lock );
793 msg_Err( p_input, "cannot add program" );
794 return( VLC_EGENERIC );
797 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
798 p_input->stream.i_mux_rate = 0;
800 i_streams = GetDWBE( &p_peek[4] );
801 if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
802 < 8 + 20 * i_streams )
804 msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
805 return( VLC_EGENERIC );
809 for( i = 0; i < i_streams; i++ )
811 es_descriptor_t *p_es;
813 if( !strncmp( (const char *)p_peek, "auds", 4 ) )
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;
820 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
822 p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
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;
832 msg_Dbg( p_input, "added new audio es %d channels %dHz",
833 wf->nChannels, wf->nSamplesPerSec );
835 input_SelectES( p_input, p_es );
838 else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
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;
845 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
847 p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
849 bih->biSize = sizeof( BITMAPINFOHEADER );
850 bih->biWidth = GetDWBE( &p_peek[8] );
851 bih->biHeight = GetDWBE( &p_peek[12] );
854 bih->biCompression = 0;
856 bih->biXPelsPerMeter = 0;
857 bih->biYPelsPerMeter = 0;
859 bih->biClrImportant = 0;
861 msg_Dbg( p_input, "added new video es %4.4s %dx%d",
862 (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
864 input_SelectES( p_input, p_es );
871 p_input->stream.p_selected_program->b_is_ok = 1;
872 vlc_mutex_unlock( &p_input->stream.stream_lock );
874 if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
876 input_DeletePacket( p_input->p_method_data, p_pk );
879 p_input->pf_demux = Demux;
883 static void DemuxClose( vlc_object_t *p_this )
888 static int Demux( input_thread_t *p_input )
890 es_descriptor_t *p_es;
898 if( input_Peek( p_input, &p_peek, 16 ) < 16 )
900 msg_Warn( p_input, "cannot peek (EOF ?)" );
904 i_stream = GetDWBE( &p_peek[0] );
905 i_size = GetDWBE( &p_peek[4] );
906 i_pcr = GetQWBE( &p_peek[8] );
908 //msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
909 //p_es = input_FindES( p_input, i_stream );
911 p_es = p_input->stream.p_selected_program->pp_es[i_stream];
914 msg_Err( p_input, "cannot find ES" );
917 p_pes = input_NewPES( p_input->p_method_data );
920 msg_Warn( p_input, "cannot allocate PES" );
927 data_packet_t *p_data;
930 if( (i_read = input_SplitBuffer( p_input, &p_data,
931 __MIN( i_size, 10000 ) ) ) <= 0 )
933 input_DeletePES( p_input->p_method_data, p_pes );
936 if( !p_pes->p_first )
938 p_pes->p_first = p_data;
939 p_pes->i_nb_data = 1;
940 p_pes->i_pes_size = i_read;
944 p_pes->p_last->p_next = p_data;
946 p_pes->i_pes_size += i_read;
948 p_pes->p_last = p_data;
952 p_pes->p_first->p_payload_start += 16;
953 p_pes->i_pes_size -= 16;
955 if( p_es && p_es->p_decoder_fifo )
957 /* Call the pace control. */
958 input_ClockManageRef( p_input, p_input->stream.p_selected_program,
961 p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
962 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
965 input_DecodePES( p_es->p_decoder_fifo, p_pes );
969 input_DeletePES( p_input->p_method_data, p_pes );