* dshow.cpp : DirectShow access module for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
- * $Id: dshow.cpp,v 1.14 2003/11/24 00:39:01 fenrir Exp $
+ * $Id: dshow.cpp,v 1.15 2003/11/24 19:30:54 fenrir Exp $
*
* Author: Gildas Bazin <gbazin@netcourrier.com>
*
#include "filter.h"
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int AccessOpen ( vlc_object_t * );
-static void AccessClose ( vlc_object_t * );
-static ssize_t Read ( input_thread_t *, byte_t *, size_t );
-static ssize_t ReadDV ( input_thread_t *, byte_t *, size_t );
-
-static int DemuxOpen ( vlc_object_t * );
-static void DemuxClose ( vlc_object_t * );
-static int Demux ( input_thread_t * );
-
-static int OpenDevice( input_thread_t *, string, vlc_bool_t );
-static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
- list<string> *, vlc_bool_t );
-static AM_MEDIA_TYPE EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
- int, int, int, int, int, int );
-static bool ConnectFilters( IFilterGraph *, IBaseFilter *, IPin * );
-
-static int FindDevicesCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-#if 0
- /* Debug only, use this to find out GUIDs */
- unsigned char p_st[];
- UuidToString( (IID *)&IID_IAMBufferNegotiation, &p_st );
- msg_Err( p_input, "BufferNegotiation: %s" , p_st );
-#endif
-
/*****************************************************************************
* Module descriptor
*****************************************************************************/
"Force the DirectShow video input to use a specific chroma format " \
"(eg. I420 (default), RV24, etc...)")
+static int AccessOpen ( vlc_object_t * );
+static void AccessClose( vlc_object_t * );
+
+static int DemuxOpen ( vlc_object_t * );
+static void DemuxClose ( vlc_object_t * );
+
vlc_module_begin();
set_description( _("DirectShow input") );
add_category_hint( N_("dshow"), NULL, VLC_TRUE );
vlc_module_end();
-/****************************************************************************
- * I. Access Part
- ****************************************************************************/
+
+/*****************************************************************************
+ * Access: local prototypes
+ *****************************************************************************/
+static ssize_t Read ( input_thread_t *, byte_t *, size_t );
+static ssize_t ReadDV ( input_thread_t *, byte_t *, size_t );
+
+static int OpenDevice( input_thread_t *, string, vlc_bool_t );
+static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
+ list<string> *, vlc_bool_t );
+static AM_MEDIA_TYPE EnumDeviceCaps( vlc_object_t *, IBaseFilter *,
+ int, int, int, int, int, int );
+static bool ConnectFilters( IFilterGraph *, IBaseFilter *, IPin * );
+
+static int FindDevicesCallback( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+#if 0
+ /* Debug only, use this to find out GUIDs */
+ unsigned char p_st[];
+ UuidToString( (IID *)&IID_IAMBufferNegotiation, &p_st );
+ msg_Err( p_input, "BufferNegotiation: %s" , p_st );
+#endif
/*
* header:
return 0; /* never reached */
}
+/*****************************************************************************
+ * Demux: local prototypes
+ *****************************************************************************/
+struct demux_sys_t
+{
+ int i_es;
+ es_out_id_t **es;
+};
+
+static int Demux ( input_thread_t * );
+
/****************************************************************************
- * I. Demux Part
+ * DemuxOpen:
****************************************************************************/
static int DemuxOpen( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
+ demux_sys_t *p_sys;
uint8_t *p_peek;
- int i_streams;
+ int i_es;
int i;
- data_packet_t *p_pk;
-
/* a little test to see if it's a dshow stream */
- if( input_Peek( p_input, &p_peek, 8 ) < 8 )
+ if( stream_Peek( p_input->s, &p_peek, 8 ) < 8 )
{
msg_Warn( p_input, "dshow plugin discarded (cannot peek)" );
return VLC_EGENERIC;
}
- if( strcmp( (const char *)p_peek, ".dsh" ) ||
- GetDWBE( &p_peek[4] ) <= 0 )
+ if( strncmp( p_peek, ".dsh", 4 ) ||
+ ( i_es = GetDWBE( &p_peek[4] ) ) <= 0 )
{
msg_Warn( p_input, "dshow plugin discarded (not a valid stream)" );
return VLC_EGENERIC;
}
- /* create one program */
vlc_mutex_lock( &p_input->stream.stream_lock );
if( input_InitStream( p_input, 0 ) == -1)
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
msg_Err( p_input, "cannot init stream" );
- return VLC_EGENERIC;
- }
- if( input_AddProgram( p_input, 0, 0) == NULL )
- {
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- msg_Err( p_input, "cannot add program" );
- return VLC_EGENERIC;
+ return( VLC_EGENERIC );
}
+ p_input->stream.i_mux_rate = 0 / 50;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
- p_input->stream.i_mux_rate = 0;
+ p_input->pf_demux = Demux;
+ p_input->pf_demux_control = demux_vaControlDefault;
+ p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
+ p_sys->i_es = 0;
+ p_sys->es = NULL;
- i_streams = GetDWBE( &p_peek[4] );
- if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
- < 8 + 20 * i_streams )
+ if( stream_Peek( p_input->s, &p_peek, 8 + 20 * i_es ) < 8 + 20 * i_es )
{
msg_Err( p_input, "dshow plugin discarded (cannot peek)" );
return VLC_EGENERIC;
}
p_peek += 8;
- for( i = 0; i < i_streams; i++ )
+ for( i = 0; i < i_es; i++ )
{
- es_descriptor_t *p_es;
+ es_format_t fmt;
- if( !strncmp( (const char *)p_peek, "auds", 4 ) )
+ if( !strncmp( p_peek, "auds", 4 ) )
{
-#define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
- p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
- i + 1, AUDIO_ES, NULL, 0 );
- p_es->i_stream_id = i + 1;
- p_es->i_fourcc =
- VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
-
- p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
-
- wf->wFormatTag = 0;//WAVE_FORMAT_UNKNOWN;
- wf->nChannels = GetDWBE( &p_peek[8] );
- wf->nSamplesPerSec = GetDWBE( &p_peek[12] );
- wf->wBitsPerSample = GetDWBE( &p_peek[16] );
- wf->nBlockAlign = wf->wBitsPerSample * wf->nChannels / 8;
- wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
- wf->cbSize = 0;
-
- msg_Dbg( p_input, "added new audio es %d channels %dHz",
- wf->nChannels, wf->nSamplesPerSec );
-
- input_SelectES( p_input, p_es );
-#undef wf
+ es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
+ p_peek[6], p_peek[7] ) );
+
+ fmt.audio.i_channels = GetDWBE( &p_peek[8] );
+ fmt.audio.i_rate = GetDWBE( &p_peek[12] );
+ fmt.audio.i_bitspersample = GetDWBE( &p_peek[16] );
+ fmt.audio.i_blockalign = fmt.audio.i_channels *
+ fmt.audio.i_bitspersample / 8;
+ fmt.i_bitrate = fmt.audio.i_channels *
+ fmt.audio.i_rate *
+ fmt.audio.i_bitspersample;
+
+ msg_Dbg( p_input, "new audio es %d channels %dHz",
+ fmt.audio.i_channels, fmt.audio.i_rate );
+
+ TAB_APPEND( p_sys->i_es, p_sys->es,
+ es_out_Add( p_input->p_es_out, &fmt ) );
}
- else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
+ else if( !strncmp( p_peek, "vids", 4 ) )
{
-#define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
- p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
- i + 1, VIDEO_ES, NULL, 0 );
- p_es->i_stream_id = i + 1;
- p_es->i_fourcc =
- VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
-
- p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
-
- bih->biSize = sizeof( BITMAPINFOHEADER );
- bih->biWidth = GetDWBE( &p_peek[8] );
- bih->biHeight = GetDWBE( &p_peek[12] );
- bih->biPlanes = 0;
- bih->biBitCount = 0;
- bih->biCompression = 0;
- bih->biSizeImage= 0;
- bih->biXPelsPerMeter = 0;
- bih->biYPelsPerMeter = 0;
- bih->biClrUsed = 0;
- bih->biClrImportant = 0;
+ es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
+ p_peek[6], p_peek[7] ) );
+ fmt.video.i_width = GetDWBE( &p_peek[8] );
+ fmt.video.i_height = GetDWBE( &p_peek[12] );
msg_Dbg( p_input, "added new video es %4.4s %dx%d",
- (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
-
- input_SelectES( p_input, p_es );
-#undef bih
+ (char*)&fmt.i_codec,
+ fmt.video.i_width, fmt.video.i_height );
+ TAB_APPEND( p_sys->i_es, p_sys->es,
+ es_out_Add( p_input->p_es_out, &fmt ) );
}
p_peek += 20;
}
- p_input->stream.p_selected_program->b_is_ok = 1;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ /* Skip header */
+ stream_Read( p_input->s, NULL, 8 + 20 * i_es );
- if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
- {
- input_DeletePacket( p_input->p_method_data, p_pk );
- }
-
- p_input->pf_demux = Demux;
- p_input->pf_demux_control = demux_vaControlDefault;
return VLC_SUCCESS;
}
+/****************************************************************************
+ * DemuxClose:
+ ****************************************************************************/
static void DemuxClose( vlc_object_t *p_this )
{
- return;
+ input_thread_t *p_input = (input_thread_t *)p_this;
+ demux_sys_t *p_sys = p_input->p_demux_data;
+
+ if( p_sys->i_es > 0 )
+ {
+ free( p_sys->es );
+ }
+ free( p_sys );
}
+/****************************************************************************
+ * Demux:
+ ****************************************************************************/
static int Demux( input_thread_t *p_input )
{
- es_descriptor_t *p_es;
- pes_packet_t *p_pes;
+ demux_sys_t *p_sys = p_input->p_demux_data;
+ block_t *p_block;
- int i_stream;
+ int i_es;
int i_size;
+
uint8_t *p_peek;
- mtime_t i_pcr;
+ mtime_t i_pts;
- if( input_Peek( p_input, &p_peek, 16 ) < 16 )
+ if( stream_Peek( p_input->s, &p_peek, 16 ) < 16 )
{
msg_Warn( p_input, "cannot peek (EOF ?)" );
return 0;
}
- i_stream = GetDWBE( &p_peek[0] );
- i_size = GetDWBE( &p_peek[4] );
- i_pcr = GetQWBE( &p_peek[8] );
-
- p_es = p_input->stream.p_selected_program->pp_es[i_stream];
- if( !p_es )
+ i_es = GetDWBE( &p_peek[0] );
+ if( i_es < 0 || i_es >= p_sys->i_es )
{
msg_Err( p_input, "cannot find ES" );
+ return -1;
}
- p_pes = input_NewPES( p_input->p_method_data );
- if( p_pes == NULL )
- {
- msg_Warn( p_input, "cannot allocate PES" );
- msleep( 1000 );
- return 1;
- }
- i_size += 16;
- while( i_size > 0 )
- {
- data_packet_t *p_data;
- int i_read;
+ i_size = GetDWBE( &p_peek[4] );
+ i_pts = GetQWBE( &p_peek[8] );
- if( (i_read = input_SplitBuffer( p_input, &p_data, i_size ) ) <= 0 )
- {
- input_DeletePES( p_input->p_method_data, p_pes );
- return 0;
- }
- if( !p_pes->p_first )
- {
- p_pes->p_first = p_data;
- p_pes->i_nb_data = 1;
- p_pes->i_pes_size = i_read;
- }
- else
- {
- p_pes->p_last->p_next = p_data;
- p_pes->i_nb_data++;
- p_pes->i_pes_size += i_read;
- }
- p_pes->p_last = p_data;
- i_size -= i_read;
+ if( ( p_block = stream_Block( p_input->s, 16 + i_size ) ) == NULL )
+ {
+ msg_Warn( p_input, "cannot read data" );
+ return 0;
}
- p_pes->p_first->p_payload_start += 16;
- p_pes->i_pes_size -= 16;
+ p_block->p_buffer += 16;
+ p_block->i_buffer -= 16;
- if( p_es && p_es->p_dec )
- {
- /* Call the pace control. */
- input_ClockManageRef( p_input, p_input->stream.p_selected_program,
- i_pcr );
+ /* Call the pace control. */
+ input_ClockManageRef( p_input, p_input->stream.p_selected_program,
+ i_pts );
- p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
- input_ClockGetTS( p_input, p_input->stream.p_selected_program,
- i_pcr );
+ p_block->i_dts =
+ p_block->i_pts = i_pcr <= 0 ? 0 :
+ input_ClockGetTS( p_input, p_input->stream.p_selected_program, i_pts );
- input_DecodePES( p_es->p_dec, p_pes );
- }
- else
- {
- input_DeletePES( p_input->p_method_data, p_pes );
- }
+ es_out_Send( p_input->p_es_out, p_sys->es[i_es], p_block );
return 1;
}
+
/*****************************************************************************
* config variable callback
*****************************************************************************/