>From 45148641d9c743e1c591527f7cd1da6d9ef24c2f Mon Sep 17 00:00:00 2001 From: Manol Manolov Date: Wed, 4 Aug 2010 10:59:44 -0400 Subject: [PATCH] Add frequency and video standard in dshow module The new options are dshow-tuner-frequency and dshow-tuner-standard --- modules/access/dshow/common.h | 113 +++++++++++++++++++++++++++ modules/access/dshow/dshow.cpp | 164 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 272 insertions(+), 5 deletions(-) diff --git a/modules/access/dshow/common.h b/modules/access/dshow/common.h index 6a3f2b5..d71fcbf 100644 --- a/modules/access/dshow/common.h +++ b/modules/access/dshow/common.h @@ -97,3 +97,116 @@ struct access_sys_t int i_chroma; bool b_chroma; /* Force a specific chroma on the dshow input */ }; + + +#define INSTANCEDATA_OF_PROPERTY_PTR(x) ((PKSPROPERTY((x))) + 1) +#define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY)) + +/**************************************************************************** + * The following should be in ks.h and ksmedia.h, + * but since they are not in the current version of Mingw32, + * they will be defined here. They are exact copy from Windows SDK. + ****************************************************************************/ +typedef enum { + KS_AnalogVideo_None = 0x00000000, + KS_AnalogVideo_NTSC_M = 0x00000001, + KS_AnalogVideo_NTSC_M_J = 0x00000002, + KS_AnalogVideo_NTSC_433 = 0x00000004, + KS_AnalogVideo_PAL_B = 0x00000010, + KS_AnalogVideo_PAL_D = 0x00000020, + KS_AnalogVideo_PAL_G = 0x00000040, + KS_AnalogVideo_PAL_H = 0x00000080, + KS_AnalogVideo_PAL_I = 0x00000100, + KS_AnalogVideo_PAL_M = 0x00000200, + KS_AnalogVideo_PAL_N = 0x00000400, + KS_AnalogVideo_PAL_60 = 0x00000800, + KS_AnalogVideo_SECAM_B = 0x00001000, + KS_AnalogVideo_SECAM_D = 0x00002000, + KS_AnalogVideo_SECAM_G = 0x00004000, + KS_AnalogVideo_SECAM_H = 0x00008000, + KS_AnalogVideo_SECAM_K = 0x00010000, + KS_AnalogVideo_SECAM_K1 = 0x00020000, + KS_AnalogVideo_SECAM_L = 0x00040000, + KS_AnalogVideo_SECAM_L1 = 0x00080000, + KS_AnalogVideo_PAL_N_COMBO = 0x00100000 +} KS_AnalogVideoStandard; + +typedef enum { + KSPROPERTY_TUNER_CAPS, // R -overall device capabilities + KSPROPERTY_TUNER_MODE_CAPS, // R -capabilities in this mode + KSPROPERTY_TUNER_MODE, // RW -set a mode (TV, FM, AM, DSS) + KSPROPERTY_TUNER_STANDARD, // R -get TV standard (only if TV mode) + KSPROPERTY_TUNER_FREQUENCY, // RW -set/get frequency + KSPROPERTY_TUNER_INPUT, // RW -select an input + KSPROPERTY_TUNER_STATUS, // R -tuning status + KSPROPERTY_TUNER_IF_MEDIUM, // R O-Medium for IF or Transport Pin + KSPROPERTY_TUNER_SCAN_CAPS, // R -overall device capabilities for scanning + KSPROPERTY_TUNER_SCAN_STATUS, // R -status of scan + KSPROPERTY_TUNER_STANDARD_MODE, // RW -autodetect mode for signal standard + KSPROPERTY_TUNER_NETWORKTYPE_SCAN_CAPS // R -network type specific tuner capabilities +} KSPROPERTY_TUNER; + +// Describes how the device tunes. Only one of these flags may be set +// in KSPROPERTY_TUNER_MODE_CAPS_S.Strategy + +// Describe how the driver should attempt to tune: +// EXACT: just go to the frequency specified (no fine tuning) +// FINE: (slow) do an exhaustive search for the best signal +// COARSE: (fast) use larger frequency jumps to just determine if any signal + +typedef enum { + KS_TUNER_TUNING_EXACT = 1, // No fine tuning + KS_TUNER_TUNING_FINE, // Fine grained search + KS_TUNER_TUNING_COARSE, // Coarse search +}KS_TUNER_TUNING_FLAGS; + +typedef enum { + KS_TUNER_STRATEGY_PLL = 0X01, // Tune by PLL offset + KS_TUNER_STRATEGY_SIGNAL_STRENGTH = 0X02, // Tune by signal strength + KS_TUNER_STRATEGY_DRIVER_TUNES = 0X04, // Driver does fine tuning +}KS_TUNER_STRATEGY; + +typedef struct { + union { +#if defined( _KS_NO_ANONYMOUS_STRUCTURES_ ) + struct _IDENTIFIER { +#else + struct { +#endif + GUID Set; + ULONG Id; + ULONG Flags; + }; + LONGLONG Alignment; + }; +} KSIDENTIFIER, *PKSIDENTIFIER; + +typedef KSIDENTIFIER KSPROPERTY, *PKSPROPERTY; + +typedef struct { + KSPROPERTY Property; + ULONG Mode; // IN: KSPROPERTY_TUNER_MODE + ULONG StandardsSupported; // KS_AnalogVideo_* (if TV or DSS) + ULONG MinFrequency; // Hz + ULONG MaxFrequency; // Hz + ULONG TuningGranularity; // Hz + ULONG NumberOfInputs; // count of inputs + ULONG SettlingTime; // milliSeconds + ULONG Strategy; // KS_TUNER_STRATEGY +} KSPROPERTY_TUNER_MODE_CAPS_S, *PKSPROPERTY_TUNER_MODE_CAPS_S; + +typedef struct { + KSPROPERTY Property; + ULONG Frequency; // Hz + ULONG LastFrequency; // Hz (last known good) + ULONG TuningFlags; // KS_TUNER_TUNING_FLAGS + ULONG VideoSubChannel; // DSS + ULONG AudioSubChannel; // DSS + ULONG Channel; // VBI decoders + ULONG Country; // VBI decoders +} KSPROPERTY_TUNER_FREQUENCY_S, *PKSPROPERTY_TUNER_FREQUENCY_S; + +typedef struct { + KSPROPERTY Property; + ULONG Standard; // KS_AnalogVideo_* +} KSPROPERTY_TUNER_STANDARD_S, *PKSPROPERTY_TUNER_STANDARD_S; diff --git a/modules/access/dshow/dshow.cpp b/modules/access/dshow/dshow.cpp index d2ad8cf..2ebb720 100644 --- a/modules/access/dshow/dshow.cpp +++ b/modules/access/dshow/dshow.cpp @@ -136,6 +136,13 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"), #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 " \ @@ -176,6 +183,31 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"), #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 * ); @@ -218,9 +250,16 @@ vlc_module_begin () 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 ) @@ -260,6 +299,13 @@ vlc_module_begin () vlc_module_end () + +/***************************************************************************** + * DirectShow GUIDs. + * Easier to define them here as mingw doesn't provide them all. + *****************************************************************************/ +const GUID PROPSETID_TUNER = {0x6a2e0605, 0x28e4, 0x11d0, {0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56}}; + /***************************************************************************** * DirectShow elementary stream descriptor *****************************************************************************/ @@ -426,6 +472,10 @@ static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys, 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", @@ -2216,7 +2266,7 @@ static void ShowTunerProperties( vlc_object_t *p_this, 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; @@ -2227,11 +2277,15 @@ static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph, 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_frequency && !i_country && !i_input ) return; /* Nothing to do */ - if( !i_channel && !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, @@ -2266,7 +2320,107 @@ static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph, 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(); } -- 1.7.0.2.msysgit.0