1 /*****************************************************************************
2 * dshow.c : DirectShow access module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: dshow.cpp,v 1.1 2003/08/24 11:17:39 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 );
64 static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
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", 10 );
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 * Access descriptor declaration
135 ****************************************************************************/
138 IFilterGraph *p_graph;
139 IBaseFilter *p_device_filter;
140 CaptureFilter *p_capture_filter;
141 IMediaControl *p_control;
146 char *psz_video_device;
150 VIDEOINFOHEADER vid_header;
157 uint8_t *p_header; // at lest 8 bytes allocated
164 VLCMediaSample sample;
167 /*****************************************************************************
168 * Open: open direct show device
169 *****************************************************************************/
170 static int AccessOpen( vlc_object_t *p_this )
172 input_thread_t *p_input = (input_thread_t *)p_this;
176 /* parse url and open device(s) */
177 char *psz_dup, *psz_parser;
178 psz_dup = strdup( p_input->psz_name );
179 psz_parser = psz_dup;
181 while( *psz_parser && *psz_parser != ':' )
187 p_input->pf_read = Read;
188 p_input->pf_seek = NULL;
189 p_input->pf_set_area = NULL;
190 p_input->pf_set_program = NULL;
192 vlc_mutex_lock( &p_input->stream.stream_lock );
193 p_input->stream.b_pace_control = 0;
194 p_input->stream.b_seekable = 0;
195 p_input->stream.p_selected_area->i_size = 0;
196 p_input->stream.p_selected_area->i_tell = 0;
197 p_input->stream.i_method = INPUT_METHOD_FILE;
198 vlc_mutex_unlock( &p_input->stream.stream_lock );
200 /* Update default_pts to a suitable value for access */
201 p_input->i_pts_delay = config_GetInt( p_input, "dshow-caching" ) * 1000;
203 /* Initialize OLE/COM */
204 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
206 /* create access private data */
207 p_input->p_access_data = p_sys =
208 (access_sys_t *)malloc( sizeof( access_sys_t ) );
209 memset( p_sys, 0, sizeof( access_sys_t ) );
211 /* Initialize some data */
212 p_sys->psz_video_device = NULL;
213 p_sys->sample.p_sample = NULL;
214 p_sys->i_data_size = 0;
215 p_sys->i_data_pos = 0;
217 if( OpenDevice( p_input, p_input->psz_name ) != VLC_SUCCESS )
219 /* Uninitialize OLE/COM */
229 /*****************************************************************************
230 * AccessClose: close device
231 *****************************************************************************/
232 static void AccessClose( vlc_object_t *p_this )
234 input_thread_t *p_input = (input_thread_t *)p_this;
235 access_sys_t *p_sys = p_input->p_access_data;
237 /* Stop capturing stuff */
238 p_sys->p_control->Stop();
239 p_sys->p_control->Release();
241 /* Remove filters from graph */
242 //p_sys->p_graph->RemoveFilter( p_sys->p_capture_filter );
243 //p_sys->p_graph->RemoveFilter( p_sys->p_device_filter );
245 /* Release objects */
246 //p_sys->p_device_filter->Release();
247 //p_sys->p_capture_filter->Release();
248 //p_sys->p_graph->Release();
250 /* Uninitialize OLE/COM */
256 /****************************************************************************
258 ****************************************************************************/
259 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
262 IEnumPins *p_enumpins;
266 if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
268 while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
270 if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
272 p_enumpins->Release();
277 p_enumpins->Release();
281 static int OpenDevice( input_thread_t *p_input, string devicename )
283 access_sys_t *p_sys = p_input->p_access_data;
284 list<string> list_devices;
287 // Enum devices and display their names
288 FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices );
290 list<string>::iterator iter;
291 for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
292 msg_Err( p_input, "found device: %s", iter->c_str() );
295 /* If no device name was specified, pick the 1st one */
296 if( devicename.size() == 0 )
298 devicename = *list_devices.begin();
301 // Use the system device enumerator and class enumerator to find
302 // a video capture/preview device, such as a desktop USB video camera.
303 p_sys->p_device_filter =
304 FindCaptureDevice( (vlc_object_t *)p_input, &devicename, NULL );
306 if( p_sys->p_device_filter )
307 msg_Dbg( p_input, "found device: %s", devicename.c_str() );
310 CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
311 (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
313 p_sys->p_graph->QueryInterface( IID_IMediaControl,
314 (void **)&p_sys->p_control );
316 /* Create and add our capture filter */
317 p_sys->p_capture_filter = new CaptureFilter( p_input );
318 p_sys->p_graph->AddFilter( p_sys->p_capture_filter, 0 );
320 /* Add the device filter to the graph (seems necessary with VfW before
321 * accessing pin attributes). */
322 p_sys->p_graph->AddFilter( p_sys->p_device_filter, 0 );
324 // Attempt to connect one of this device's capture output pins
325 msg_Dbg( p_input, "connecting filters" );
326 if( ConnectFilters( p_sys->p_graph, p_sys->p_device_filter,
327 p_sys->p_capture_filter->CustomGetPin() ) )
330 int i_fourcc = VLC_FOURCC( ' ', ' ', ' ', ' ' );
331 AM_MEDIA_TYPE *pmt = &p_sys->mt;
332 p_sys->mt = p_sys->p_capture_filter->CustomGetPin()->
333 CustomGetMediaType();
335 if( pmt->majortype == MEDIATYPE_Video )
337 if( pmt->subtype == MEDIASUBTYPE_RGB8 )
339 i_fourcc = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
341 else if( pmt->subtype == MEDIASUBTYPE_RGB555 )
343 i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
345 else if( pmt->subtype == MEDIASUBTYPE_RGB565 )
347 i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
349 else if( pmt->subtype == MEDIASUBTYPE_RGB24 )
351 i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
353 else if( pmt->subtype == MEDIASUBTYPE_RGB32 )
355 i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
357 else if( pmt->subtype == MEDIASUBTYPE_ARGB32 )
359 i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
362 else if( pmt->subtype == MEDIASUBTYPE_YUYV )
364 i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
366 else if( pmt->subtype == MEDIASUBTYPE_Y411 )
368 i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
370 else if( pmt->subtype == MEDIASUBTYPE_Y41P )
372 i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
374 else if( pmt->subtype == MEDIASUBTYPE_YUY2 )
376 i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
378 else if( pmt->subtype == MEDIASUBTYPE_YVYU )
380 i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
382 else if( pmt->subtype == MEDIASUBTYPE_Y411 )
384 i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
386 else if( pmt->subtype == MEDIASUBTYPE_YV12 )
388 i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
391 p_sys->i_fourcc = i_fourcc;
392 p_sys->vid_header = *(VIDEOINFOHEADER *)pmt->pbFormat;
396 p_sys->i_header_size = 8 + 20;
397 p_sys->i_header_pos = 0;
398 p_sys->p_header = (uint8_t *)malloc( p_sys->i_header_size );
400 memcpy( &p_sys->p_header[0], ".dsh", 4 );
401 SetDWBE( &p_sys->p_header[4], 1 );
402 memcpy( &p_sys->p_header[ 8], "vids", 4 );
403 memcpy( &p_sys->p_header[12], &i_fourcc, 4 );
404 SetDWBE( &p_sys->p_header[16], p_sys->vid_header.bmiHeader.biWidth );
405 SetDWBE( &p_sys->p_header[20], p_sys->vid_header.bmiHeader.biHeight );
406 SetDWBE( &p_sys->p_header[24], 0 );
408 p_sys->p_control->Run();
414 /* Remove filters from graph */
415 p_sys->p_graph->RemoveFilter( p_sys->p_device_filter );
416 p_sys->p_graph->RemoveFilter( p_sys->p_capture_filter );
418 /* Release objects */
419 p_sys->p_device_filter->Release();
420 p_sys->p_capture_filter->Release();
421 p_sys->p_control->Release();
422 p_sys->p_graph->Release();
428 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
429 list<string> *p_listdevices )
431 IBaseFilter *pBaseFilter = NULL;
432 IMoniker *pMoniker = NULL;
436 /* Create the system device enumerator */
437 ICreateDevEnum *pDevEnum = NULL;
439 hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
440 IID_ICreateDevEnum, (void **)&pDevEnum );
443 msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
447 /* Create an enumerator for the video capture devices */
448 IEnumMoniker *pClassEnum = NULL;
449 hr = pDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
453 msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
457 /* If there are no enumerators for the requested type, then
458 * CreateClassEnumerator will succeed, but pClassEnum will be NULL */
459 if( pClassEnum == NULL )
461 msg_Err( p_this, "no video capture device was detected." );
465 /* Enumerate the devices */
467 /* Note that if the Next() call succeeds but there are no monikers,
468 * it will return S_FALSE (which is not a failure). Therefore, we check
469 * that the return code is S_OK instead of using SUCCEEDED() macro. */
471 while( pClassEnum->Next( 1, &pMoniker, &lFetched ) == S_OK )
473 /* Getting the property page to get the device name */
475 hr = pMoniker->BindToStorage( 0, 0, IID_IPropertyBag,
476 reinterpret_cast<PVOID *>( &pBag ) );
481 hr = pBag->Read( L"FriendlyName", &var, NULL );
485 int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
486 char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
487 WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
488 i_convert, NULL, NULL );
489 SysFreeString(var.bstrVal);
491 if( p_listdevices ) p_listdevices->push_back( p_buf );
493 if( p_devicename && *p_devicename == string(p_buf) )
495 /* Bind Moniker to a filter object */
496 hr = pMoniker->BindToObject( 0, 0, IID_IBaseFilter,
497 reinterpret_cast<LPVOID *>(&pBaseFilter) );
500 msg_Err( p_this, "couldn't bind moniker to filter "
501 "object (0x%x)", hr );
513 /*****************************************************************************
514 * Read: reads from the device into PES packets.
515 *****************************************************************************
516 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
518 *****************************************************************************/
519 static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
521 access_sys_t *p_sys = p_input->p_access_data;
525 msg_Info( p_input, "access read data_size %i, data_pos %i",
526 p_sys->i_data_size, p_sys->i_data_pos );
531 /* First copy header if any */
532 if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
536 i_copy = __MIN( p_sys->i_header_size -
537 p_sys->i_header_pos, (int)i_len );
538 memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );
539 p_sys->i_header_pos += i_copy;
547 if( i_len > 0 && p_sys->i_data_pos < p_sys->i_data_size )
551 i_copy = __MIN( p_sys->i_data_size -
552 p_sys->i_data_pos, (int)i_len );
554 memcpy( p_buffer, &p_sys->p_data[p_sys->i_data_pos], i_copy );
555 p_sys->i_data_pos += i_copy;
562 /* The caller got what he wanted */
568 /* Read no more than one frame at a time, otherwise we kill latency */
569 if( p_sys->i_data_size && i_data &&
570 p_sys->i_data_pos == p_sys->i_data_size )
572 p_sys->i_data_pos = 0; p_sys->i_data_size = 0;
576 /* Start new audio/video frame */
577 if( p_sys->sample.p_sample )
579 //p_sys->sample.p_sample->Release();
582 if( p_sys->p_capture_filter->CustomGetPin()
583 ->CustomGetSample( &p_sys->sample ) == S_OK )
585 p_sys->i_data_pos = 0;
586 p_sys->i_data_size = p_sys->sample.p_sample->GetActualDataLength();
587 p_sys->sample.p_sample->GetPointer( &p_sys->p_data );
589 REFERENCE_TIME i_pts, i_end_date;
590 HRESULT hr = p_sys->sample.p_sample
591 ->GetTime( &i_pts, &i_end_date );
592 if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
596 /* Use our data timestamp */
597 i_pts = p_sys->sample.i_timestamp;
601 msg_Dbg( p_input, "Read() PTS: "I64Fd, i_pts );
604 /* create pseudo header */
605 p_sys->i_header_size = 16;
606 p_sys->i_header_pos = 0;
607 SetDWBE( &p_sys->p_header[0], 0 /*i_stream*/ );
608 SetDWBE( &p_sys->p_header[4], p_sys->i_data_size );
609 SetQWBE( &p_sys->p_header[8], i_pts * 9 / 1000 );
611 else msleep( 10000 );
617 /****************************************************************************
619 ****************************************************************************/
620 static int DemuxOpen( vlc_object_t *p_this )
622 input_thread_t *p_input = (input_thread_t *)p_this;
630 /* Initialize access plug-in structures. */
631 if( p_input->i_mtu == 0 )
634 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
637 /* a little test to see if it's a v4l stream */
638 if( input_Peek( p_input, &p_peek, 8 ) < 8 )
640 msg_Warn( p_input, "v4l plugin discarded (cannot peek)" );
641 return( VLC_EGENERIC );
644 if( strcmp( (const char *)p_peek, ".dsh" ) ||
645 GetDWBE( &p_peek[4] ) <= 0 )
647 msg_Warn( p_input, "v4l plugin discarded (not a valid stream)" );
651 /* create one program */
652 vlc_mutex_lock( &p_input->stream.stream_lock );
653 if( input_InitStream( p_input, 0 ) == -1)
655 vlc_mutex_unlock( &p_input->stream.stream_lock );
656 msg_Err( p_input, "cannot init stream" );
657 return( VLC_EGENERIC );
659 if( input_AddProgram( p_input, 0, 0) == NULL )
661 vlc_mutex_unlock( &p_input->stream.stream_lock );
662 msg_Err( p_input, "cannot add program" );
663 return( VLC_EGENERIC );
666 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
667 p_input->stream.i_mux_rate = 0;
669 i_streams = GetDWBE( &p_peek[4] );
670 if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
671 < 8 + 20 * i_streams )
673 msg_Err( p_input, "v4l plugin discarded (cannot peek)" );
674 return( VLC_EGENERIC );
678 for( i = 0; i < i_streams; i++ )
680 es_descriptor_t *p_es;
682 if( !strncmp( (const char *)p_peek, "auds", 4 ) )
684 #define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
685 p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
686 i + 1, AUDIO_ES, NULL, 0 );
687 p_es->i_stream_id = i + 1;
689 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
691 p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
693 wf->wFormatTag = 0;//WAVE_FORMAT_UNKNOWN;
694 wf->nChannels = GetDWBE( &p_peek[8] );
695 wf->nSamplesPerSec = GetDWBE( &p_peek[12] );
696 wf->wBitsPerSample = GetDWBE( &p_peek[16] );
697 wf->nBlockAlign = wf->wBitsPerSample * wf->nChannels / 8;
698 wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
701 msg_Dbg( p_input, "added new audio es %d channels %dHz",
702 wf->nChannels, wf->nSamplesPerSec );
704 input_SelectES( p_input, p_es );
707 else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
709 #define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
710 p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
711 i + 1, VIDEO_ES, NULL, 0 );
712 p_es->i_stream_id = i + 1;
714 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
716 p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
718 bih->biSize = sizeof( BITMAPINFOHEADER );
719 bih->biWidth = GetDWBE( &p_peek[8] );
720 bih->biHeight = GetDWBE( &p_peek[12] );
723 bih->biCompression = 0;
725 bih->biXPelsPerMeter = 0;
726 bih->biYPelsPerMeter = 0;
728 bih->biClrImportant = 0;
730 msg_Dbg( p_input, "added new video es %4.4s %dx%d",
731 (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
733 input_SelectES( p_input, p_es );
740 p_input->stream.p_selected_program->b_is_ok = 1;
741 vlc_mutex_unlock( &p_input->stream.stream_lock );
743 if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
745 input_DeletePacket( p_input->p_method_data, p_pk );
748 p_input->pf_demux = Demux;
752 static void DemuxClose( vlc_object_t *p_this )
757 static int Demux( input_thread_t *p_input )
759 es_descriptor_t *p_es;
767 if( input_Peek( p_input, &p_peek, 16 ) < 16 )
769 msg_Warn( p_input, "cannot peek (EOF ?)" );
773 i_stream = GetDWBE( &p_peek[0] );
774 i_size = GetDWBE( &p_peek[4] );
775 i_pcr = GetQWBE( &p_peek[8] );
777 //msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
778 //p_es = input_FindES( p_input, i_stream );
780 p_es = p_input->stream.p_selected_program->pp_es[i_stream];
783 msg_Err( p_input, "cannot find ES" );
786 p_pes = input_NewPES( p_input->p_method_data );
789 msg_Warn( p_input, "cannot allocate PES" );
796 data_packet_t *p_data;
799 if( (i_read = input_SplitBuffer( p_input, &p_data,
800 __MIN( i_size, 10000 ) ) ) <= 0 )
802 input_DeletePES( p_input->p_method_data, p_pes );
805 if( !p_pes->p_first )
807 p_pes->p_first = p_data;
808 p_pes->i_nb_data = 1;
809 p_pes->i_pes_size = i_read;
813 p_pes->p_last->p_next = p_data;
815 p_pes->i_pes_size += i_read;
817 p_pes->p_last = p_data;
821 p_pes->p_first->p_payload_start += 16;
822 p_pes->i_pes_size -= 16;
824 if( p_es && p_es->p_decoder_fifo )
826 /* Call the pace control. */
827 input_ClockManageRef( p_input, p_input->stream.p_selected_program,
830 p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
831 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
834 input_DecodePES( p_es->p_decoder_fifo, p_pes );
838 input_DeletePES( p_input->p_method_data, p_pes );