1 /*****************************************************************************
2 * dshow.c : DirectShow access module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: dshow.cpp,v 1.3 2003/08/25 22:57:40 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 /* Uninitialize OLE/COM */
309 /* Release directshow objects */
310 p_sys->p_control->Release();
311 p_sys->p_graph->Release();
312 free( p_sys->p_header );
317 /* Initialize some data */
318 p_sys->i_current_stream = 0;
319 p_sys->i_header_pos = 0;
321 /* Everything is ready. Let's rock baby */
322 p_sys->p_control->Run();
327 /*****************************************************************************
328 * AccessClose: close device
329 *****************************************************************************/
330 static void AccessClose( vlc_object_t *p_this )
332 input_thread_t *p_input = (input_thread_t *)p_this;
333 access_sys_t *p_sys = p_input->p_access_data;
335 /* Stop capturing stuff */
336 p_sys->p_control->Stop();
337 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();
351 /* Uninitialize OLE/COM */
354 free( p_sys->p_header );
355 for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];
356 free( p_sys->pp_streams );
360 /****************************************************************************
362 ****************************************************************************/
363 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
366 IEnumPins *p_enumpins;
370 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
372 while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
374 if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
376 p_enumpins->Release();
381 p_enumpins->Release();
385 static int OpenDevice( input_thread_t *p_input, string devicename,
388 access_sys_t *p_sys = p_input->p_access_data;
389 list<string> list_devices;
391 /* Enumerate audio devices and display their names */
392 FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );
394 list<string>::iterator iter;
395 for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
396 msg_Dbg( p_input, "found device: %s", iter->c_str() );
398 /* If no device name was specified, pick the 1st one */
399 if( devicename.size() == 0 )
401 devicename = *list_devices.begin();
404 // Use the system device enumerator and class enumerator to find
405 // a capture/preview device, such as a desktop USB video camera.
406 IBaseFilter *p_device_filter =
407 FindCaptureDevice( (vlc_object_t *)p_input, &devicename,
409 if( p_device_filter )
410 msg_Dbg( p_input, "using device: %s", devicename.c_str() );
413 msg_Err( p_input, "can't use device: %s", devicename.c_str() );
417 /* Create and add our capture filter */
418 CaptureFilter *p_capture_filter = new CaptureFilter( p_input );
419 p_sys->p_graph->AddFilter( p_capture_filter, 0 );
421 /* Add the device filter to the graph (seems necessary with VfW before
422 * accessing pin attributes). */
423 p_sys->p_graph->AddFilter( p_device_filter, 0 );
425 /* Attempt to connect one of this device's capture output pins */
426 msg_Dbg( p_input, "connecting filters" );
427 if( ConnectFilters( p_sys->p_graph, p_device_filter,
428 p_capture_filter->CustomGetPin() ) )
431 dshow_stream_t dshow_stream;
433 p_capture_filter->CustomGetPin()->CustomGetMediaType();
435 if( dshow_stream.mt.majortype == MEDIATYPE_Video )
437 msg_Dbg( p_input, "MEDIATYPE_Video");
439 if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB8 )
440 dshow_stream.i_fourcc = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
441 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB555 )
442 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
443 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB565 )
444 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
445 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB24 )
446 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
447 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB32 )
448 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
449 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_ARGB32 )
450 dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
452 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUYV )
453 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
454 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )
455 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
456 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y41P )
457 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
458 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUY2 )
459 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
460 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVYU )
461 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
462 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )
463 dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
464 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YV12 )
465 dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
468 dshow_stream.header.video =
469 *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;
471 /* Add video stream to header */
472 p_sys->i_header_size += 20;
473 p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
474 p_sys->i_header_size );
475 memcpy( &p_sys->p_header[p_sys->i_header_pos], "vids", 4 );
476 memcpy( &p_sys->p_header[p_sys->i_header_pos + 4],
477 &dshow_stream.i_fourcc, 4 );
478 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
479 dshow_stream.header.video.bmiHeader.biWidth );
480 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],
481 dshow_stream.header.video.bmiHeader.biHeight );
482 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16], 0 );
483 p_sys->i_header_pos = p_sys->i_header_size;
486 else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&
487 dshow_stream.mt.formattype == FORMAT_WaveFormatEx )
489 msg_Dbg( p_input, "MEDIATYPE_Audio");
491 if( dshow_stream.mt.subtype == MEDIASUBTYPE_PCM )
492 dshow_stream.i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
494 else if( dshow_stream.mt.subtype == MEDIASUBTYPE_IEEE_FLOAT )
495 dshow_stream.i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );
499 dshow_stream.header.audio =
500 *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;
502 /* Add audio stream to header */
503 p_sys->i_header_size += 20;
504 p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,
505 p_sys->i_header_size );
506 memcpy( &p_sys->p_header[p_sys->i_header_pos], "auds", 4 );
507 memcpy( &p_sys->p_header[p_sys->i_header_pos + 4],
508 &dshow_stream.i_fourcc, 4 );
509 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],
510 dshow_stream.header.audio.nChannels );
511 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],
512 dshow_stream.header.audio.nSamplesPerSec );
513 SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16],
514 dshow_stream.header.audio.wBitsPerSample );
515 p_sys->i_header_pos = p_sys->i_header_size;
519 /* Add directshow elementary stream to our list */
520 dshow_stream.sample.p_sample = NULL;
521 dshow_stream.i_data_size = 0;
522 dshow_stream.i_data_pos = 0;
523 dshow_stream.p_device_filter = p_device_filter;
524 dshow_stream.p_capture_filter = p_capture_filter;
527 (dshow_stream_t **)realloc( p_sys->pp_streams,
528 sizeof(dshow_stream_t *)
529 * (p_sys->i_streams + 1) );
530 p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
531 *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
532 SetDWBE( &p_sys->p_header[4], (uint32_t)p_sys->i_streams );
538 /* Remove filters from graph */
539 p_sys->p_graph->RemoveFilter( p_device_filter );
540 p_sys->p_graph->RemoveFilter( p_capture_filter );
542 /* Release objects */
543 p_device_filter->Release();
544 p_capture_filter->Release();
550 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
551 list<string> *p_listdevices, vlc_bool_t b_audio )
553 IBaseFilter *p_base_filter = NULL;
554 IMoniker *p_moniker = NULL;
558 /* Create the system device enumerator */
559 ICreateDevEnum *p_dev_enum = NULL;
561 hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
562 IID_ICreateDevEnum, (void **)&p_dev_enum );
565 msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
569 /* Create an enumerator for the video capture devices */
570 IEnumMoniker *p_class_enum = NULL;
572 hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
575 hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,
577 p_dev_enum->Release();
580 msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
584 /* If there are no enumerators for the requested type, then
585 * CreateClassEnumerator will succeed, but p_class_enum will be NULL */
586 if( p_class_enum == NULL )
588 msg_Err( p_this, "no capture device was detected." );
592 /* Enumerate the devices */
594 /* Note that if the Next() call succeeds but there are no monikers,
595 * it will return S_FALSE (which is not a failure). Therefore, we check
596 * that the return code is S_OK instead of using SUCCEEDED() macro. */
598 while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK )
600 /* Getting the property page to get the device name */
602 hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag,
608 hr = p_bag->Read( L"FriendlyName", &var, NULL );
612 int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
613 char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
614 WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
615 i_convert, NULL, NULL );
616 SysFreeString(var.bstrVal);
618 if( p_listdevices ) p_listdevices->push_back( p_buf );
620 if( p_devicename && *p_devicename == string(p_buf) )
622 /* Bind Moniker to a filter object */
623 hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter,
624 (void **)&p_base_filter );
627 msg_Err( p_this, "couldn't bind moniker to filter "
628 "object (0x%x)", hr );
629 p_moniker->Release();
630 p_class_enum->Release();
633 p_moniker->Release();
634 p_class_enum->Release();
635 return p_base_filter;
640 p_moniker->Release();
643 p_class_enum->Release();
647 /*****************************************************************************
648 * Read: reads from the device into PES packets.
649 *****************************************************************************
650 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
652 *****************************************************************************/
653 static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
655 access_sys_t *p_sys = p_input->p_access_data;
656 dshow_stream_t *p_stream = p_sys->pp_streams[p_sys->i_current_stream];
660 msg_Info( p_input, "access read data_size %i, data_pos %i",
661 p_sys->i_data_size, p_sys->i_data_pos );
666 /* First copy header if any */
667 if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
671 i_copy = __MIN( p_sys->i_header_size -
672 p_sys->i_header_pos, (int)i_len );
673 memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );
674 p_sys->i_header_pos += i_copy;
681 /* Then copy stream data if any */
682 if( i_len > 0 && p_stream->i_data_pos < p_stream->i_data_size )
684 int i_copy = __MIN( p_stream->i_data_size -
685 p_stream->i_data_pos, (int)i_len );
687 memcpy( p_buffer, &p_stream->p_data[p_stream->i_data_pos],
689 p_stream->i_data_pos += i_copy;
696 /* The caller got what he wanted */
697 if( i_len <= 0 ) return i_data;
699 /* Read no more than one frame at a time, otherwise we kill latency */
700 if( p_stream->i_data_size && i_data &&
701 p_stream->i_data_pos == p_stream->i_data_size )
703 p_stream->i_data_pos = p_stream->i_data_size = 0;
707 /* Get new sample/frame from next stream */
708 //if( p_sream->sample.p_sample ) p_stream->sample.p_sample->Release();
709 p_sys->i_current_stream =
710 (p_sys->i_current_stream + 1) % p_sys->i_streams;
711 p_stream = p_sys->pp_streams[p_sys->i_current_stream];
712 if( p_stream->p_capture_filter &&
713 p_stream->p_capture_filter->CustomGetPin()
714 ->CustomGetSample( &p_stream->sample ) == S_OK )
716 p_stream->i_data_pos = 0;
717 p_stream->i_data_size =
718 p_stream->sample.p_sample->GetActualDataLength();
719 p_stream->sample.p_sample->GetPointer( &p_stream->p_data );
721 REFERENCE_TIME i_pts, i_end_date;
723 p_stream->sample.p_sample->GetTime( &i_pts, &i_end_date );
724 if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
728 /* Use our data timestamp */
729 i_pts = p_stream->sample.i_timestamp;
733 msg_Dbg( p_input, "Read() PTS: "I64Fd, i_pts );
736 /* Create pseudo header */
737 p_sys->i_header_size = 16;
738 p_sys->i_header_pos = 0;
739 SetDWBE( &p_sys->p_header[0], p_sys->i_current_stream );
740 SetDWBE( &p_sys->p_header[4], p_stream->i_data_size );
741 SetQWBE( &p_sys->p_header[8], i_pts * 9 / 1000 );
743 else msleep( 10000 );
749 /****************************************************************************
751 ****************************************************************************/
752 static int DemuxOpen( vlc_object_t *p_this )
754 input_thread_t *p_input = (input_thread_t *)p_this;
762 /* Initialize access plug-in structures. */
763 if( p_input->i_mtu == 0 )
766 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
769 /* a little test to see if it's a dshow stream */
770 if( input_Peek( p_input, &p_peek, 8 ) < 8 )
772 msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
773 return( VLC_EGENERIC );
776 if( strcmp( (const char *)p_peek, ".dsh" ) ||
777 GetDWBE( &p_peek[4] ) <= 0 )
779 msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
783 /* create one program */
784 vlc_mutex_lock( &p_input->stream.stream_lock );
785 if( input_InitStream( p_input, 0 ) == -1)
787 vlc_mutex_unlock( &p_input->stream.stream_lock );
788 msg_Err( p_input, "cannot init stream" );
789 return( VLC_EGENERIC );
791 if( input_AddProgram( p_input, 0, 0) == NULL )
793 vlc_mutex_unlock( &p_input->stream.stream_lock );
794 msg_Err( p_input, "cannot add program" );
795 return( VLC_EGENERIC );
798 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
799 p_input->stream.i_mux_rate = 0;
801 i_streams = GetDWBE( &p_peek[4] );
802 if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
803 < 8 + 20 * i_streams )
805 msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
806 return( VLC_EGENERIC );
810 for( i = 0; i < i_streams; i++ )
812 es_descriptor_t *p_es;
814 if( !strncmp( (const char *)p_peek, "auds", 4 ) )
816 #define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
817 p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
818 i + 1, AUDIO_ES, NULL, 0 );
819 p_es->i_stream_id = i + 1;
821 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
823 p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
825 wf->wFormatTag = 0;//WAVE_FORMAT_UNKNOWN;
826 wf->nChannels = GetDWBE( &p_peek[8] );
827 wf->nSamplesPerSec = GetDWBE( &p_peek[12] );
828 wf->wBitsPerSample = GetDWBE( &p_peek[16] );
829 wf->nBlockAlign = wf->wBitsPerSample * wf->nChannels / 8;
830 wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
833 msg_Dbg( p_input, "added new audio es %d channels %dHz",
834 wf->nChannels, wf->nSamplesPerSec );
836 input_SelectES( p_input, p_es );
839 else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
841 #define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
842 p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
843 i + 1, VIDEO_ES, NULL, 0 );
844 p_es->i_stream_id = i + 1;
846 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
848 p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
850 bih->biSize = sizeof( BITMAPINFOHEADER );
851 bih->biWidth = GetDWBE( &p_peek[8] );
852 bih->biHeight = GetDWBE( &p_peek[12] );
855 bih->biCompression = 0;
857 bih->biXPelsPerMeter = 0;
858 bih->biYPelsPerMeter = 0;
860 bih->biClrImportant = 0;
862 msg_Dbg( p_input, "added new video es %4.4s %dx%d",
863 (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
865 input_SelectES( p_input, p_es );
872 p_input->stream.p_selected_program->b_is_ok = 1;
873 vlc_mutex_unlock( &p_input->stream.stream_lock );
875 if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
877 input_DeletePacket( p_input->p_method_data, p_pk );
880 p_input->pf_demux = Demux;
884 static void DemuxClose( vlc_object_t *p_this )
889 static int Demux( input_thread_t *p_input )
891 es_descriptor_t *p_es;
899 if( input_Peek( p_input, &p_peek, 16 ) < 16 )
901 msg_Warn( p_input, "cannot peek (EOF ?)" );
905 i_stream = GetDWBE( &p_peek[0] );
906 i_size = GetDWBE( &p_peek[4] );
907 i_pcr = GetQWBE( &p_peek[8] );
909 //msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
910 //p_es = input_FindES( p_input, i_stream );
912 p_es = p_input->stream.p_selected_program->pp_es[i_stream];
915 msg_Err( p_input, "cannot find ES" );
918 p_pes = input_NewPES( p_input->p_method_data );
921 msg_Warn( p_input, "cannot allocate PES" );
928 data_packet_t *p_data;
931 if( (i_read = input_SplitBuffer( p_input, &p_data,
932 __MIN( i_size, 10000 ) ) ) <= 0 )
934 input_DeletePES( p_input->p_method_data, p_pes );
937 if( !p_pes->p_first )
939 p_pes->p_first = p_data;
940 p_pes->i_nb_data = 1;
941 p_pes->i_pes_size = i_read;
945 p_pes->p_last->p_next = p_data;
947 p_pes->i_pes_size += i_read;
949 p_pes->p_last = p_data;
953 p_pes->p_first->p_payload_start += 16;
954 p_pes->i_pes_size -= 16;
956 if( p_es && p_es->p_decoder_fifo )
958 /* Call the pace control. */
959 input_ClockManageRef( p_input, p_input->stream.p_selected_program,
962 p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
963 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
966 input_DecodePES( p_es->p_decoder_fifo, p_pes );
970 input_DeletePES( p_input->p_method_data, p_pes );