/*****************************************************************************
* dshow.cpp : DirectShow access module for vlc
*****************************************************************************
- * Copyright (C) 2002, 2003 the VideoLAN team
+ * Copyright (C) 2002-2004, 2006, 2008, 2010 the VideoLAN team
* $Id$
*
* Author: Gildas Bazin <gbazin@videolan.org>
"Size of the video that will be displayed by the " \
"DirectShow plugin. If you don't specify anything the default size for " \
"your device will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>.")
+#define ASPECT_TEXT N_("Picture aspect-ratio n:m")
+#define ASPECT_LONGTEXT N_("Define input picture aspect-ratio to use. Default is 4:3" )
#define CHROMA_TEXT N_("Video input chroma format")
#define CHROMA_LONGTEXT N_( \
"Force the DirectShow video input to use a specific chroma format " \
#define CHANNEL_LONGTEXT N_( \
"Set the TV channel the tuner will set to " \
"(0 means default)." )
+#define TVFREQ_TEXT N_("Tuner Frequency")
+#define TVFREQ_LONGTEXT N_( "This overrides the channel. Measured in Hz." )
+#define STANDARD_TEXT N_( "Standard" )
+#define STANDARD_LONGTEXT N_( "Video standard (Default, SECAM_D, PAL_B, NTSC_M, etc...)." )
#define COUNTRY_TEXT N_("Tuner country code")
#define COUNTRY_LONGTEXT N_( \
"Set the tuner country code that establishes the current " \
#define AUDIO_BITSPERSAMPLE_LONGTEXT N_( \
"Select audio input format with the given bits/sample (if non 0)" )
+static const int i_standards_list[] =
+ {
+ KS_AnalogVideo_None,
+ KS_AnalogVideo_NTSC_M, KS_AnalogVideo_NTSC_M_J, KS_AnalogVideo_NTSC_433,
+ KS_AnalogVideo_PAL_B, KS_AnalogVideo_PAL_D, KS_AnalogVideo_PAL_G,
+ KS_AnalogVideo_PAL_H, KS_AnalogVideo_PAL_I, KS_AnalogVideo_PAL_M,
+ KS_AnalogVideo_PAL_N, KS_AnalogVideo_PAL_60,
+ KS_AnalogVideo_SECAM_B, KS_AnalogVideo_SECAM_D, KS_AnalogVideo_SECAM_G,
+ KS_AnalogVideo_SECAM_H, KS_AnalogVideo_SECAM_K, KS_AnalogVideo_SECAM_K1,
+ KS_AnalogVideo_SECAM_L, KS_AnalogVideo_SECAM_L1,
+ KS_AnalogVideo_PAL_N_COMBO
+ };
+static const char *const ppsz_standards_list_text[] =
+ {
+ N_("Default"),
+ "NTSC_M", "NTSC_M_J", "NTSC_443",
+ "PAL_B", "PAL_D", "PAL_G",
+ "PAL_H", "PAL_I", "PAL_M",
+ "PAL_N", "PAL_60",
+ "SECAM_B", "SECAM_D", "SECAM_G",
+ "SECAM_H", "SECAM_K", "SECAM_K1",
+ "SECAM_L", "SECAM_L1",
+ "PAL_N_COMBO"
+ };
+
static int CommonOpen ( vlc_object_t *, access_sys_t *, bool );
static void CommonClose( vlc_object_t *, access_sys_t * );
add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, false)
+ add_string( "dshow-aspect-ratio", "4:3", NULL, ASPECT_TEXT, ASPECT_LONGTEXT, false)
+
add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
add_float( "dshow-fps", 0.0f, NULL, FPS_TEXT, FPS_LONGTEXT, true )
add_integer( "dshow-tuner-channel", 0, NULL, CHANNEL_TEXT, CHANNEL_LONGTEXT,
true )
+ add_integer( "dshow-tuner-frequency", 0, NULL, TVFREQ_TEXT, TVFREQ_LONGTEXT,
+ true )
+
add_integer( "dshow-tuner-country", 0, NULL, COUNTRY_TEXT, COUNTRY_LONGTEXT,
true )
+ add_integer( "dshow-tuner-standard", 0, NULL, STANDARD_TEXT, STANDARD_LONGTEXT,
+ false )
+ change_integer_list( i_standards_list, ppsz_standards_list_text, NULL )
+
add_integer( "dshow-tuner-input", 0, NULL, TUNER_INPUT_TEXT,
TUNER_INPUT_LONGTEXT, true )
change_integer_list( pi_tuner_input, ppsz_tuner_input_text, NULL )
vlc_module_end ()
+
/*****************************************************************************
* DirectShow elementary stream descriptor
*****************************************************************************/
static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
bool b_access_demux )
{
- vlc_value_t val;
int i;
+ char *psz_val;
/* Get/parse options and open device(s) */
string vdevname, adevname;
var_Create( p_this, "dshow-config", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_this, "dshow-tuner", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Create( p_this, "dshow-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_this, "dshow-vdev", &val );
- if( val.psz_string )
+ psz_val = var_CreateGetString( p_this, "dshow-vdev" );
+ if( psz_val )
{
- msg_Dbg( p_this, "dshow-vdev: %s", val.psz_string ) ;
+ msg_Dbg( p_this, "dshow-vdev: %s", psz_val ) ;
/* skip none device */
- if ( strncasecmp( val.psz_string, "none", 4 ) != 0 )
- vdevname = string( val.psz_string );
+ if ( strncasecmp( psz_val, "none", 4 ) != 0 )
+ vdevname = string( psz_val );
else
b_use_video = false ;
}
- free( val.psz_string );
+ free( psz_val );
- var_Create( p_this, "dshow-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_this, "dshow-adev", &val );
- if( val.psz_string )
+ psz_val = var_CreateGetString( p_this, "dshow-adev" );
+ if( psz_val )
{
- msg_Dbg( p_this, "dshow-adev: %s", val.psz_string ) ;
+ msg_Dbg( p_this, "dshow-adev: %s", psz_val ) ;
/* skip none device */
- if ( strncasecmp( val.psz_string, "none", 4 ) != 0 )
- adevname = string( val.psz_string );
+ if ( strncasecmp( psz_val, "none", 4 ) != 0 )
+ adevname = string( psz_val );
else
b_use_audio = false ;
}
- free( val.psz_string );
+ free( psz_val );
static struct {const char *psz_size; int i_width; int i_height;} size_table[] =
{ { "subqcif", 128, 96 }, { "qsif", 160, 120 }, { "qcif", 176, 144 },
{ 0, 0, 0 },
};
- var_Create( p_this, "dshow-size", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_this, "dshow-size", &val );
- if( val.psz_string && *val.psz_string )
+ psz_val = var_CreateGetString( p_this, "dshow-size" );
+ if( !EMPTY_STR(psz_val) )
{
for( i = 0; size_table[i].psz_size; i++ )
{
- if( !strcmp( val.psz_string, size_table[i].psz_size ) )
+ if( !strcmp( psz_val, size_table[i].psz_size ) )
{
i_width = size_table[i].i_width;
i_height = size_table[i].i_height;
if( !size_table[i].psz_size ) /* Try to parse "WidthxHeight" */
{
char *psz_parser;
- i_width = strtol( val.psz_string, &psz_parser, 0 );
+ i_width = strtol( psz_val, &psz_parser, 0 );
if( *psz_parser == 'x' || *psz_parser == 'X')
{
i_height = strtol( psz_parser + 1, &psz_parser, 0 );
msg_Dbg( p_this, "width x height %dx%d", i_width, i_height );
}
}
- free( val.psz_string );
+ free( psz_val );
- p_sys->b_chroma = false;
- var_Create( p_this, "dshow-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_this, "dshow-chroma", &val );
-
- i_chroma = vlc_fourcc_GetCodecFromString( UNKNOWN_ES, val.psz_string );
+ psz_val = var_CreateGetString( p_this, "dshow-chroma" );
+ i_chroma = vlc_fourcc_GetCodecFromString( UNKNOWN_ES, psz_val );
p_sys->b_chroma = i_chroma != 0;
- free( val.psz_string );
+ free( psz_val );
var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
var_Create( p_this, "dshow-tuner-channel",
VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Create( p_this, "dshow-tuner-frequency",
+ VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Create( p_this, "dshow-tuner-standard",
+ VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_this, "dshow-tuner-country",
VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_this, "dshow-tuner-input",
var_Create( p_this, "dshow-video-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_this, "dshow-audio-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+
/* Initialize some data */
p_sys->i_streams = 0;
p_sys->pp_streams = NULL;
return VLC_EGENERIC;
}
- var_Get( p_this, "dshow-tuner", &val );
- if( val.b_bool )
+ if( var_GetBool( p_this, "dshow-tuner" ) )
{
/* FIXME: we do MEDIATYPE_Stream here so we don't do
* it twice. */
for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
{
- var_Get( p_this, "dshow-video-input", &val );
- if( val.i_int >= 0 )
- p_sys->crossbar_routes[i].VideoInputIndex=val.i_int;
- var_Get( p_this, "dshow-video-output", &val );
- if( val.i_int >= 0 )
- p_sys->crossbar_routes[i].VideoOutputIndex=val.i_int;
- var_Get( p_this, "dshow-audio-input", &val );
- if( val.i_int >= 0 )
- p_sys->crossbar_routes[i].AudioInputIndex=val.i_int;
- var_Get( p_this, "dshow-audio-output", &val );
- if( val.i_int >= 0 )
- p_sys->crossbar_routes[i].AudioOutputIndex=val.i_int;
+ int i_val = var_GetInteger( p_this, "dshow-video-input" );
+ if( i_val >= 0 )
+ p_sys->crossbar_routes[i].VideoInputIndex = i_val;
+ i_val = var_GetInteger( p_this, "dshow-video-output" );
+ if( i_val >= 0 )
+ p_sys->crossbar_routes[i].VideoOutputIndex = i_val;
+ i_val = var_GetInteger( p_this, "dshow-audio-input" );
+ if( i_val >= 0 )
+ p_sys->crossbar_routes[i].AudioInputIndex = i_val;
+ i_val = var_GetInteger( p_this, "dshow-audio-output" );
+ if( i_val >= 0 )
+ p_sys->crossbar_routes[i].AudioOutputIndex = i_val;
IAMCrossbar *pXbar = p_sys->crossbar_routes[i].pXbar;
LONG VideoInputIndex = p_sys->crossbar_routes[i].VideoInputIndex;
/*
** Show properties pages from other filters in graph
*/
- var_Get( p_this, "dshow-config", &val );
- if( val.b_bool )
+ if( var_GetBool( p_this, "dshow-config" ) )
{
for( i = p_sys->i_crossbar_route_depth-1; i >= 0 ; --i )
{
if( p_stream->mt.majortype == MEDIATYPE_Video )
{
+ char *psz_aspect = var_CreateGetString( p_this, "dshow-aspect-ratio" );
+ char *psz_delim = !EMPTY_STR( psz_aspect ) ? strchr( psz_aspect, ':' ) : NULL;
+
es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
fmt.video.i_width = p_stream->header.video.bmiHeader.biWidth;
fmt.video.i_height = p_stream->header.video.bmiHeader.biHeight;
- fmt.video.i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
+
+ if( psz_delim )
+ {
+ fmt.video.i_sar_num = atoi( psz_aspect ) * fmt.video.i_height;
+ fmt.video.i_sar_den = atoi( psz_delim + 1 ) * fmt.video.i_width;
+ }
+ else
+ {
+ fmt.video.i_sar_num = 4 * fmt.video.i_height;
+ fmt.video.i_sar_den = 3 * fmt.video.i_width;
+ }
+ free( psz_aspect );
if( !p_stream->header.video.bmiHeader.biCompression )
{
/* Setup rgb mask for RGB formats */
if( p_stream->i_fourcc == VLC_CODEC_RGB24 )
{
- /* This is in BGR format */
- fmt.video.i_bmask = 0x00ff0000;
+ /* This is in RGB format
+ http://msdn.microsoft.com/en-us/library/dd407253%28VS.85%29.aspx?ppud=4
+ */
+ fmt.video.i_rmask = 0x00ff0000;
fmt.video.i_gmask = 0x0000ff00;
- fmt.video.i_rmask = 0x000000ff;
+ fmt.video.i_bmask = 0x000000ff;
}
if( p_stream->header.video.AvgTimePerFrame )
/* Show Device properties. Done here so the VLC stream is setup with
* the proper parameters. */
- vlc_value_t val;
- var_Get( p_this, "dshow-config", &val );
- if( val.b_bool )
+ if( var_GetBool( p_this, "dshow-config" ) )
{
ShowDeviceProperties( p_this, p_sys->p_capture_graph_builder2,
p_device_filter, b_audio );
ConfigTuner( p_this, p_sys->p_capture_graph_builder2,
p_device_filter );
- var_Get( p_this, "dshow-tuner", &val );
- if( val.b_bool && dshow_stream.mt.majortype != MEDIATYPE_Stream )
+ if( var_GetBool( p_this, "dshow-tuner" ) &&
+ dshow_stream.mt.majortype != MEDIATYPE_Stream )
{
/* FIXME: we do MEDIATYPE_Stream later so we don't do it twice. */
ShowTunerProperties( p_this, p_sys->p_capture_graph_builder2,
dshow_stream.p_device_filter = p_device_filter;
dshow_stream.p_capture_filter = p_capture_filter;
- p_sys->pp_streams = (dshow_stream_t **)realloc( p_sys->pp_streams,
- sizeof(dshow_stream_t *) * (p_sys->i_streams + 1) );
+ p_sys->pp_streams = (dshow_stream_t **)xrealloc( p_sys->pp_streams,
+ sizeof(dshow_stream_t *) * (p_sys->i_streams + 1) );
p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;
*p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;
while( 1 )
{
- if( !vlc_object_alive (p_access) || p_access->b_error ) return 0;
+ if( !vlc_object_alive (p_access) ) return NULL;
/* Get new sample/frame from the elementary stream (blocking). */
vlc_mutex_lock( &p_sys->lock );
*****************************************************************************/
static int AccessControl( access_t *p_access, int i_query, va_list args )
{
- bool *pb_bool;
- int *pi_int;
- int64_t *pi_64;
+ bool *pb_bool;
+ int64_t *pi_64;
switch( i_query )
{
/* */
case ACCESS_GET_PTS_DELAY:
pi_64 = (int64_t*)va_arg( args, int64_t * );
- *pi_64 = (int64_t)var_GetInteger( p_access, "dshow-caching" ) * 1000;
+ *pi_64 = var_GetInteger( p_access, "dshow-caching" ) * 1000;
break;
/* */
****************************************************************************/
static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
{
- bool *pb;
- int64_t *pi64;
+ bool *pb;
+ int64_t *pi64;
switch( i_query )
{
case DEMUX_GET_PTS_DELAY:
pi64 = (int64_t*)va_arg( args, int64_t * );
- *pi64 = (int64_t)var_GetInteger( p_demux, "dshow-caching" ) * 1000;
+ *pi64 = var_GetInteger( p_demux, "dshow-caching" ) * 1000;
return VLC_SUCCESS;
case DEMUX_GET_TIME:
/* Uninitialize OLE/COM */
CoUninitialize();
- if( !list_devices.size() ) return VLC_SUCCESS;
+ if( list_devices.empty() ) return VLC_SUCCESS;
- p_item->ppsz_list =
- (char **)realloc( p_item->ppsz_list,
+ p_item->ppsz_list = (char**)xrealloc( p_item->ppsz_list,
(list_devices.size()+3) * sizeof(char *) );
- p_item->ppsz_list_text =
- (char **)realloc( p_item->ppsz_list_text,
+ p_item->ppsz_list_text = (char**)xrealloc( p_item->ppsz_list_text,
(list_devices.size()+3) * sizeof(char *) );
list<string>::iterator iter;
/* Enumerate devices */
FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
- if( !list_devices.size() )
+ if( list_devices.empty() )
{
CoUninitialize();
return VLC_EGENERIC;
static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph,
IBaseFilter *p_device_filter )
{
- int i_channel, i_country, i_input, i_amtuner_mode;
+ int i_channel, i_country, i_input, i_amtuner_mode, i_standard, i_frequency;
long l_modes = 0;
IAMTVTuner *p_TV;
HRESULT hr;
i_country = var_GetInteger( p_this, "dshow-tuner-country" );
i_input = var_GetInteger( p_this, "dshow-tuner-input" );
i_amtuner_mode = var_GetInteger( p_this, "dshow-amtuner-mode" );
+ i_frequency = var_GetInteger( p_this, "dshow-tuner-frequency" );
+ i_standard =
+ i_standards_list[var_CreateGetInteger( p_this, "dshow-tuner-standard" )];
- if( !i_channel && !i_country && !i_input ) return; /* Nothing to do */
+ if( !i_channel && !i_frequency && !i_country && !i_input ) return; /* Nothing to do */
+
+ msg_Dbg( p_this, "tuner config: channel %i, frequency %i, country %i, input type %i, standard %s",
+ i_channel, i_frequency, i_country, i_input, ppsz_standards_list_text[i_standard] );
- msg_Dbg( p_this, "tuner config: channel %i, country %i, input type %i",
- i_channel, i_country, i_input );
hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved,
p_device_filter, IID_IAMTVTuner,
else if( i_input == 2 ) p_TV->put_InputType( 0, TunerInputAntenna );
p_TV->put_CountryCode( i_country );
- p_TV->put_Channel( i_channel, AMTUNER_SUBCHAN_NO_TUNE,
+
+ if( i_frequency <= 0 ) p_TV->put_Channel( i_channel, AMTUNER_SUBCHAN_NO_TUNE,
AMTUNER_SUBCHAN_NO_TUNE );
+
+ if( i_frequency > 0 || i_standard > 0) {
+ IKsPropertySet *pKs = NULL;
+ DWORD dw_supported = 0;
+ KSPROPERTY_TUNER_MODE_CAPS_S ModeCaps;
+ KSPROPERTY_TUNER_FREQUENCY_S Frequency;
+ KSPROPERTY_TUNER_STANDARD_S Standard;
+
+ hr = p_TV->QueryInterface(IID_IKsPropertySet,(void **)&pKs);
+ if (FAILED(hr))
+ {
+ msg_Dbg( p_this, "Couldn't QI for IKsPropertySet" );
+ return;
+ }
+
+ memset(&ModeCaps,0,sizeof(KSPROPERTY_TUNER_MODE_CAPS_S));
+ memset(&Frequency,0,sizeof(KSPROPERTY_TUNER_FREQUENCY_S));
+ memset(&Standard,0,sizeof(KSPROPERTY_TUNER_STANDARD_S));
+ ModeCaps.Mode = AMTUNER_MODE_TV;
+
+ hr = pKs->QuerySupported(PROPSETID_TUNER,
+ KSPROPERTY_TUNER_MODE_CAPS,&dw_supported);
+ if(SUCCEEDED(hr) && dw_supported&KSPROPERTY_SUPPORT_GET)
+ {
+ DWORD cbBytes=0;
+ hr = pKs->Get(PROPSETID_TUNER,KSPROPERTY_TUNER_MODE_CAPS,
+ INSTANCEDATA_OF_PROPERTY_PTR(&ModeCaps),
+ INSTANCEDATA_OF_PROPERTY_SIZE(ModeCaps),
+ &ModeCaps,
+ sizeof(ModeCaps),
+ &cbBytes);
+ }
+ else
+ {
+ msg_Dbg( p_this, "KSPROPERTY_TUNER_MODE_CAPS not supported!" );
+ return;
+ }
+
+ msg_Dbg( p_this, "Frequency range supproted from %d to %d.", ModeCaps.MinFrequency, ModeCaps.MaxFrequency);
+ msg_Dbg( p_this, "Video standards supproted by the tuner: ");
+ for(int i = 0 ; i < ARRAY_SIZE(ppsz_standards_list_text); i++) {
+ if(ModeCaps.StandardsSupported & i_standards_list[i])
+ msg_Dbg( p_this, "%s, ", ppsz_standards_list_text[i]);
+ }
+
+ if(i_frequency > 0) {
+ Frequency.Frequency=i_frequency;
+ if(ModeCaps.Strategy==KS_TUNER_STRATEGY_DRIVER_TUNES)
+ Frequency.TuningFlags=KS_TUNER_TUNING_FINE;
+ else
+ Frequency.TuningFlags=KS_TUNER_TUNING_EXACT;
+
+ if(i_frequency>=ModeCaps.MinFrequency && i_frequency<=ModeCaps.MaxFrequency)
+ {
+
+ hr = pKs->Set(PROPSETID_TUNER,
+ KSPROPERTY_TUNER_FREQUENCY,
+ INSTANCEDATA_OF_PROPERTY_PTR(&Frequency),
+ INSTANCEDATA_OF_PROPERTY_SIZE(Frequency),
+ &Frequency,
+ sizeof(Frequency));
+ if(FAILED(hr))
+ {
+ msg_Dbg( p_this, "Couldn't set KSPROPERTY_TUNER_FREQUENCY!" );
+ return;
+ }
+ }
+ else
+ {
+ msg_Dbg( p_this, "Requested frequency exceeds the supported range!" );
+ return;
+ }
+ }
+
+ if(i_standard > 0) {
+ if(i_standard & ModeCaps.StandardsSupported )
+ {
+ Standard.Standard = i_standard;
+ hr = pKs->Set(PROPSETID_TUNER,
+ KSPROPERTY_TUNER_STANDARD,
+ INSTANCEDATA_OF_PROPERTY_PTR(&Standard),
+ INSTANCEDATA_OF_PROPERTY_SIZE(Standard),
+ &Standard,
+ sizeof(Standard));
+ if(FAILED(hr))
+ {
+ msg_Dbg( p_this, "Couldn't set KSPROPERTY_TUNER_STANDARD!" );
+ return;
+ }
+ }
+ else
+ {
+ msg_Dbg( p_this, "Requested video standard is not supported by the tuner!" );
+ return;
+ }
+ }
+ pKs->Release();
+ }
+
p_TV->Release();
}