
#if 0
/* GUID struct: sizeof(GUID) = 16 */
typedef struct {
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char  Data4[ 8 ];
} GUID; 

/* KSPROPERTY struct: sizeof(KSPROPERTY) = 24 */
typedef struct {
    union {
        struct {
            GUID    Set;
            ULONG   Id;
            ULONG   Flags;
        } Data;
        LONGLONG    Alignment;
    };
} KSIDENTIFIER, *PKSIDENTIFIER, KSPROPERTY, *PKSPROPERTY;

/* KSPROPERTY_TUNER_FREQUENCY_S: sizeof(KSPROPERTY_TUNER_FREQUENCY_S) = 52 */
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;
#endif


/*
Norm:		Audio Carrier	Video Bandwidth

SECAM_DKK1L	6.5MHz			6.0Mhz
PAL_D		6.5MHz			6.0MHz

PAL_I		6.0Mhz			5.5MHz

PAL_BGH		5.5Mhz			5.0MHz
PAL_N		5.5MHz			5.0MHz
SECAM_BG	5.5MHz			5.0MHz

NTSC_M		4.5Mhz			4.2MHz
PAL_M		4.5Mhz			4.2MHz
PAL_NC		4.5Mhz			4.2MHz

 */

// Ntsc50 is unsupported, we use NTSC433 to create it!
#ifndef AnalogVideo_NTSC_50
#define AnalogVideo_NTSC_50 AnalogVideo_NTSC_433
#endif

#define TN_CCIR_DKL \
	AnalogVideo_PAL_D | \
	AnalogVideo_SECAM_D | \
	AnalogVideo_SECAM_K | \
	AnalogVideo_SECAM_L

#define TN_CCIR_I \
	AnalogVideo_PAL_I 

#define TN_CCIR_BGHN \
	AnalogVideo_PAL_B | \
	AnalogVideo_PAL_G | \
	AnalogVideo_PAL_H | \
	AnalogVideo_PAL_N | \
	AnalogVideo_PAL_60 | \
	AnalogVideo_SECAM_B | \
	AnalogVideo_SECAM_G

#define TN_CCIR_MC \
	AnalogVideo_NTSC_M | \
	AnalogVideo_NTSC_M_J | \
	AnalogVideo_PAL_M | \
	AnalogVideo_PAL_NC | \
	AnalogVideo_NTSC_50 

// Our access macros to get to the instance data of the property
#define INSTANCE_DATA_OF_PROPERTY_PTR(x) ( (PKSPROPERTY((x)) ) + 1 )
#define INSTANCE_DATA_OF_PROPERTY_SIZE(x) ( sizeof((x)) - sizeof(KSPROPERTY) )

// Fixed function: This is the correct implementation (the one that Microsoft is using)

// Method:
//	SetFrequency
// Parameters:
//	double				ffreq	= frequency to set in Megahertz
//	AMTunerModeType		lMode	= Tuner mode to use (AMTUNER_MODE_TV, AMTUNER_MODE_FM_RADIO, AMTUNER_MODE_AM_RADIO )
//	ULONG				Input	= RF input to use (0 should be ok for most tuners)
//	AnalogVideoStandard TVstd	= The analog video standard we are trying to use.
// Returns:
//	TRUE if signal was found.

BOOL CTuner::SetFrequency(double ffreq,AMTunerModeType lMode , ULONG Input, AnalogVideoStandard TVstd)
{
	DWORD	Freq = ffreq * 1000000.;
	DWORD	ret = 0;
	BOOL	SignalFound = FALSE; // We start assuming signal is NOT present

	// We should set Frequency, and we should do it using automatic fine tuning if
	// possible... And we should check if a signal is present there... All this with the help
	// of Microsoft Apis... Here we go!
	
	IKsPropertySet *kps;
	HRESULT hr = pTVTuner->QueryInterface(IID_IKsPropertySet,(void **)&kps);
	if(FAILED(hr)) {
		Log(__FUNC__,__LINE__,"QueryInterface",hr);
		return FALSE;
	}
	
	// We query the capabilities of the tuner...
	KSPROPERTY_TUNER_CAPS_S tc;
	ZeroMemory(&tc,sizeof(tc));
	ret = 0;
	hr=kps->Get(PSET_TUNER,
				KSPROPERTY_TUNER_CAPS,
				INSTANCE_DATA_OF_PROPERTY_PTR(&tc),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
				INSTANCE_DATA_OF_PROPERTY_SIZE(tc),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
				&tc,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
				sizeof(tc),								// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
				&ret);

	// If failed, log it (but all WDM drivers should support it, because it is a required property!)
	if(FAILED(hr)) {
		Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_CAPS",hr);
		tc.ModesSupported = AMTUNER_MODE_TV; // at least, TV should be supported!
	}

	// Be sure the requested mode is supported!
	if ((tc.ModesSupported & lMode) == 0) {

		Log(__FUNC__,__LINE__,"Requested mode is not supported",hr);

		// Release the interface, as we won't use it anymore.
		kps->Release(); 

		return FALSE;
	}
		
	// Get the capabilities of the tuner for the requested mode
	KSPROPERTY_TUNER_MODE_CAPS_S tmc;
	ZeroMemory(&tmc,sizeof(tmc));
	ret = 0;
	tmc.Mode = lMode; // We will query tuner caps for the mode we will set.
	hr=kps->Get(PSET_TUNER,
				KSPROPERTY_TUNER_MODE_CAPS,
				INSTANCE_DATA_OF_PROPERTY_PTR(&tmc),	// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
				INSTANCE_DATA_OF_PROPERTY_SIZE(tmc),	// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
				&tmc,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
				sizeof(tmc),							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
				&ret);

	// If failed, log it (but all WDM drivers should support it, because it is a required property!)
	if(FAILED(hr)) {
		Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_MODE_CAPS",hr);
		// Fake some values to be able to go on... (default capabilities should be close to this!)
		switch (lMode) {
			default:
			case AMTUNER_MODE_TV;
			// TV

				// We will support all Video Standards (The KS_AnalogVideo... kernel enum is the AnalogVideo DirectX enum! , the MUST match, by Microsoft Specs)
				tmc.StandardsSupported = 
					AnalogVideo_NTSC_M | AnalogVideo_NTSC_M_J |	AnalogVideo_NTSC_433 |
					AnalogVideo_PAL_B |	AnalogVideo_PAL_D |	AnalogVideo_PAL_H |
					AnalogVideo_PAL_I |	AnalogVideo_PAL_M |	AnalogVideo_PAL_N |
					AnalogVideo_PAL_60 | AnalogVideo_SECAM_B | AnalogVideo_SECAM_D |
					AnalogVideo_SECAM_G | AnalogVideo_SECAM_H | AnalogVideo_SECAM_K |
					AnalogVideo_SECAM_K1 | AnalogVideo_SECAM_L | AnalogVideo_SECAM_L1 |
					AnalogVideo_PAL_N_COMBO;
	
				// The lowest frequency supported by the tuner. This value is in hertz. 
				tmc.MinFrequency = 55250000L;
	
				// The highest frequency supported by the tuner. This value is in hertz. 
				tmc.MaxFrequency = 997250000L;
	    
				// What is the frequency step size?
				// The smallest possible step size between two settings of the tuning frequency. This value is in hertz. 
				tmc.TuningGranularity =  62500L;
	    
				// How many inputs are on the tuner? (some of them have more than 1 RF input)
				// The number of inputs on the tuner. 
				tmc.NumberOfInputs = 1;
		
				// What is the maximum settling time in milliseconds? (when you change frequency)
				// The time, in milliseconds, for a new frequency setting to become stable. 
				tmc.SettlingTime = 100;
	        
				//
				// Strategy defines how the tuner knows when it is in tune:
				// 
				// KS_TUNER_STRATEGY_PLL (Has PLL offset information,else NO PLLOffset )
				// KS_TUNER_STRATEGY_SIGNAL_STRENGTH (has signal strength info , else NO SignalStrength )
				// KS_TUNER_STRATEGY_DRIVER_TUNES (driver handles all fine tuning) (No way to detect if signal is present)
				//
				tmc.Strategy = KS_TUNER_STRATEGY_DRIVER_TUNES;
				break;

			case AMTUNER_MODE_FM_RADIO:
				tmc.StandardsSupported = 0;
				tmc.MinFrequency =  88100000L;
				tmc.MaxFrequency = 107900000L;

				// What is the frequency step size?
				tmc.TuningGranularity =  200000L;
				// How many inputs are on the tuner?
				tmc.NumberOfInputs = 1;
				// What is the maximum settling time in milliseconds?
				tmc.SettlingTime = 100;
				// Strategy defines how the tuner knows when it is in tune:
				tmc.Strategy = KS_TUNER_STRATEGY_DRIVER_TUNES;
				break;

			case KSPROPERTY_TUNER_MODE_AM_RADIO:
				tmc.StandardsSupported = 0;
				tmc.MinFrequency =  540000L;
				tmc.MaxFrequency = 1700000L;

				// What is the frequency step size?
				tmc.TuningGranularity =  1000L;
    			// How many inputs are on the tuner?
				tmc.NumberOfInputs = 1;
    			// What is the maximum settling time in milliseconds?
				tmc.SettlingTime = 100;
				// Strategy defines how the tuner knows when it is in tune:
				tmc.Strategy = KS_TUNER_STRATEGY_DRIVER_TUNES;
				break;
		}
	}		 

	// Some buggy drivers don't properly report all the tuner analog video standards a tuner can tune:
	// they only specify one of all the group: Fix that! - Some tuners need to be switched to the right 
	// video mode standard to be able to tune it.
	if (tmc.StandardsSupported & TN_CCIR_DKL) {	tmc.StandardsSupported |= TN_CCIR_DKL;	}
	if (tmc.StandardsSupported & TN_CCIR_I) { tmc.StandardsSupported |= TN_CCIR_I; }
	if (tmc.StandardsSupported & TN_CCIR_BGHN) { tmc.StandardsSupported |= TN_CCIR_BGHN; }
	if (tmc.StandardsSupported & TN_CCIR_MC) { tmc.StandardsSupported |= TN_CCIR_MC; }

	// We have the capabilities for the current requested mode... Now validate parameters!
	if (Freq < tmc.MinFrequency ||
		Freq > tmc.MaxFrequency ||
		(TVstd & tmc.StandardsSupported) == 0 ||
		Input >= tmc.NumberOfInputs ) {

		// Release the interface, as we won't use it anymore.
		kps->Release(); 

		// Frequency is out of tuner capabilities... Go out!
		Log(__FUNC__,__LINE__,"Frequency and/or video standard is out of specification",hr);

		// Out!
		return FALSE;
	}

	// 1)- Set the tuner mode required (you could use IAMTuner::put_Mode()
	// to do this; IAMTuner::put_Mode() uses this property to set the Tuner mode)
	// (this property can also be read if needed)
	KSPROPERTY_TUNER_MODE_S tm;
	ZeroMemory(&tm,sizeof(tm));
	tm.Mode = lMode;				// The current tuner mode
	hr=kps->Set(PSET_TUNER,
				KSPROPERTY_TUNER_MODE,
				INSTANCE_DATA_OF_PROPERTY_PTR(&tm),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
				INSTANCE_DATA_OF_PROPERTY_SIZE(tm),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
				&tm,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
				sizeof(tm));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.


	// 2)- Set the tuner Standard needed to tune to this
	// (this property can also be read if needed)
	KSPROPERTY_TUNER_STANDARD_S ts;
	ZeroMemory(&ts,sizeof(ts));
	ts.Standard = TVstd;		// The current TV standard to set
	hr=kps->Set(PSET_TUNER,
				KSPROPERTY_TUNER_STANDARD,
				INSTANCE_DATA_OF_PROPERTY_PTR(&ts),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
				INSTANCE_DATA_OF_PROPERTY_SIZE(ts),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
				&ts,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
				sizeof(ts));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
	
	// Accept failure... Some drivers are buggy and probably tuning will work even if this fails
	if(FAILED(hr))Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STANDARD",hr);

	// 3)- Set Tuner Input (this property can also be read if needed)
	KSPROPERTY_TUNER_INPUT_S ti;
	ZeroMemory(&ti,sizeof(ti));
	ti.InputIndex = Input;									// The input to use (0 based)
	hr=kps->Set(PSET_TUNER,
				KSPROPERTY_TUNER_INPUT,
				INSTANCE_DATA_OF_PROPERTY_PTR(&ti),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
				INSTANCE_DATA_OF_PROPERTY_SIZE(ti),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
				&ti,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
				sizeof(ti));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.

	// Accept failure... Some drivers are buggy and probably tuning will work even if this fails
	if(FAILED(hr))Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_INPUT",hr);

	// We are ready to set frequency... Based on Tuner Strategy,
	// try to fine tune to the requested channel and at the same time, try to find out if 
	// a signal is present there!
	switch (tmc.Strategy) {

		// Driver handles fine-tuning - Teoretically, no way to know if signal is present.
		// I suggest to use IAMAnalogVideoDecoder::get_HorizontalLocked to know it if it is a video
		// signal (Radio signals can't be autodetected this way!)

		default: 
		case KS_TUNER_STRATEGY_DRIVER_TUNES: 
			{
				// Set Frequency
				KSPROPERTY_TUNER_FREQUENCY_S tf;
				ZeroMemory(&tf,sizeof(tf));
				tf.Frequency = Freq;						// The frequency to set...
				tf.TuningFlags = KS_TUNER_TUNING_FINE;		// Let the driver do fine auto tuning.
				hr=kps->Set(PSET_TUNER,
						KSPROPERTY_TUNER_FREQUENCY,
						INSTANCE_DATA_OF_PROPERTY_PTR(&tf),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
						INSTANCE_DATA_OF_PROPERTY_SIZE(tf),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
						&tf,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
						sizeof(tf));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
		
				if(FAILED(hr)) {
					Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_FREQUENCY",hr);
					break;
				}

				// The following code is an undocumented way we could try to use to determie if a signal is present!
				KSPROPERTY_TUNER_STATUS_S ts;
				DWORD Tries;

				for (Tries = 0; Tries < 30 ; Tries++) {
					ZeroMemory(&ts,sizeof(ts));
					ts.PLLOffset = -100;
					ts.SignalStrength = 0;
					ret = 0;
					hr=kps->Get(PSET_TUNER,
								KSPROPERTY_TUNER_STATUS,
								INSTANCE_DATA_OF_PROPERTY_PTR(&ts),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
								INSTANCE_DATA_OF_PROPERTY_SIZE(ts),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
								&ts,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
								sizeof(ts),								// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
								&ret);

					if(FAILED(hr)) {
						Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STATUS",hr);
						break;
					}

					if (!ts.Busy && 
						(
							(ts.CurrentFrequency != 0 && ts.Currentfrequency != Freq) ||
							(ts.PllOffset != -100 && ts.PllOffset != 0) ||
							(ts.SignalStrength != 0 && SignalStrength != -1)
						)
					   )
					{
						SignalFound = TRUE;
						break;
					}
					Sleep(10); // Wait 10 milliseconds to let PLL stabilize
				}
			}
			break;

		// This means the driver won't do autotuning, but offers PLL Offset information to adjust freq.
		case KS_TUNER_STRATEGY_PLL:
			{
				// Set frequency.
				KSPROPERTY_TUNER_FREQUENCY_S tf;
				ZeroMemory(&tf,sizeof(tf));
				tf.Frequency = Freq;					// The frequency to set...
				hr=kps->Set(PSET_TUNER,
							KSPROPERTY_TUNER_FREQUENCY,
							INSTANCE_DATA_OF_PROPERTY_PTR(&tf),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
							INSTANCE_DATA_OF_PROPERTY_SIZE(tf),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
							&tf,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
							sizeof(tf));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
		
				if(FAILED(hr)) {
					Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_FREQUENCY",hr);
					break;
				}

				// Now, read the PLL offset information
				KSPROPERTY_TUNER_STATUS_S ts;

				DWORD Tries;
				for (Tries = 0; Tries < 30 ; Tries++) {
		            ZeroMemory(&ts,sizeof(ts));
					ret = 0;
					hr=kps->Get(PSET_TUNER,
								KSPROPERTY_TUNER_STATUS,
								INSTANCE_DATA_OF_PROPERTY_PTR(&ts),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
								INSTANCE_DATA_OF_PROPERTY_SIZE(ts),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
								&ts,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
								sizeof(ts),								// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
								&ret);

					if(FAILED(hr)) {
						Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STATUS",hr);
						break;
					}

					if (!ts.Busy) {
						break;
					}

					Sleep(10); // Wait 10 milliseconds to let PLL stabilize
				}
				if (Tries == 30) {
					Log(__FUNC__,__LINE__,"PLL didn't stabilize",hr);
					break;
				}

				// We have the PLLoffset information... Adjust freq and go on with tests!
				// Set Frequency
				ZeroMemory(&tf,sizeof(tf));
				tf.Frequency = Freq + ts.PLLOffset * tmc.TuningGranularity;
				hr=kps->Set(PSET_TUNER,
							KSPROPERTY_TUNER_FREQUENCY,
							INSTANCE_DATA_OF_PROPERTY_PTR(&tf),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
							INSTANCE_DATA_OF_PROPERTY_SIZE(tf),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
							&tf,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
							sizeof(tf));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
		
				if(FAILED(hr)) {
					Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_FREQUENCY",hr);
					break;
				}

				// Read the Status again...
				for (Tries = 0; Tries < 30 ; Tries++) {
		            ZeroMemory(&ts,sizeof(ts));
					ret = 0;
					hr=kps->Get(PSET_TUNER,
								KSPROPERTY_TUNER_STATUS,
								INSTANCE_DATA_OF_PROPERTY_PTR(&ts),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
								INSTANCE_DATA_OF_PROPERTY_SIZE(ts),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
								&ts,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
								sizeof(ts),								// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
								&ret);

					if(FAILED(hr)) {
						Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STATUS",hr);
						break;
					}

					if (!ts.Busy) {
						break;
					}

					Sleep(10); // Wait 10 milliseconds to let PLL stabilize
				}
				if (Tries == 30) {
					Log(__FUNC__,__LINE__,"PLL didn't stabilize",hr);
					break;
				} else {
					if (ts.PLLOffset == 0) {
						SignalFound = TRUE;
					}
					
				}
			}
			break;

		// This means the driver won't do autotuning, but offers SignalStrenght information to adjust freq.
		case KS_TUNER_STRATEGY_SIGNAL_STRENGTH:
			{
				KSPROPERTY_TUNER_FREQUENCY_S tf;
				KSPROPERTY_TUNER_STATUS_S ts;

				DWORD MaxSignalStrength = 0;
				DWORD MaxSSFreq = 1;

				DWORD f;
				for (
					f = Freq - 4 * tcm.TuningGranularity;
					f < Freq + 5 * tcm.TuningGranularity;
					f += tcm.TuningGranularity) {

					// Set frequency.
					ZeroMemory(&tf,sizeof(tf));
					tf.Frequency = f;							// The frequency to set...
					hr=kps->Set(PSET_TUNER,
							KSPROPERTY_TUNER_FREQUENCY,
							INSTANCE_DATA_OF_PROPERTY_PTR(&tf),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
							INSTANCE_DATA_OF_PROPERTY_SIZE(tf),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
							&tf,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
							sizeof(tf));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
		
					if(FAILED(hr)) {
						Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_FREQUENCY",hr);
						break;
					}

					// Now, read the SignalStrenght information
					DWORD Tries;
					for (Tries = 0; Tries < 30 ; Tries++) {

						ZeroMemory(&ts,sizeof(ts));
						ret = 0;
						hr=kps->Get(PSET_TUNER,
									KSPROPERTY_TUNER_STATUS,
									INSTANCE_DATA_OF_PROPERTY_PTR(&ts),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
									INSTANCE_DATA_OF_PROPERTY_SIZE(ts),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
									&ts,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
									sizeof(ts),								// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
									&ret);

						if(FAILED(hr)) {
							Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STATUS",hr);
							break;
						}

						if (!ts.Busy) {
							break;
						}

						Sleep(10); // Wait 10 milliseconds to let PLL stabilize
					}
					if (Tries == 30) {
						Log(__FUNC__,__LINE__,"PLL didn't stabilize",hr);
						break;
					}

					// Record the current freq. if the signal is greater 
					if (MaxSignalStrength < ts.SignalStrength) {
						MaxSignalStrength = ts.SignalStrength;
						MaxSSFreq = f;
					}
				}

				// We have the best signal... Hope!

				// Set the last selected freq.
				ZeroMemory(&tf,sizeof(tf));
				tf.Frequency = MaxSSFreq;						// The best frequency...
				hr=kps->Set(PSET_TUNER,
							KSPROPERTY_TUNER_FREQUENCY,
							INSTANCE_DATA_OF_PROPERTY_PTR(&tf),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
							INSTANCE_DATA_OF_PROPERTY_SIZE(tf),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
							&tf,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
							sizeof(tf));							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
		
				if(FAILED(hr)) {
					Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_FREQUENCY",hr);
				}

				// Decide if we have a signal present!
				SignalFound = (MaxSignalStrength != 0);
			}
			break;
	}	

	// Release the interface, as we won't use it anymore.
	kps->Release(); 
	
	// return if signal was found
	return SignalFound;		
}

//---------------------------------------------------------------------------
double CTuner::GetFrequency(void)
{
	IKsPropertySet *kps;
	HRESULT hr = pTVTuner->QueryInterface(IID_IKsPropertySet,(void **)&kps);
    if(hr==NOERROR)
    {
		KSPROPERTY_TUNER_STATUS_S ts;
        ZeroMemory(&ts,sizeof(ts));
        DWORD ret=0;
        hr=kps->Get(PSET_TUNER,
					KSPROPERTY_TUNER_STATUS,
					INSTANCE_DATA_OF_PROPERTY_PTR(&ts),		// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
					INSTANCE_DATA_OF_PROPERTY_SIZE(ts),		// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
					&ts,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
					sizeof(ts),								// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
					&ret);

		// Release the interface, as we won't use it anymore.
		kps->Release(); 

        if(FAILED(hr))Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STATUS",hr);

		// Return the actual frequency of the tuner 
		// (this is NOT the frequency you have set, it is the driver-adjusted 
		// frequency of the current tuned channel (if driver implements the KS_TUNER_STRATEGY_DRIVER_TUNES strategy) 
        return tss.CurrentFrequency/1000000.;
    } else {
		Log(__FUNC__,__LINE__,"pTVTuner->QueryInterface IID_IKsPropertySet",hr);
	}
	return 0.;
}

3. And also I use IKsPropertySet for check signal... 


// There's no reliable way to check for a signal present... 
// pTVTuner->SignalPresent() uses internally KSPROPERTY_TUNER_STATUS  
// to check for that, or perhaps, uses a similar way as the one implemented in 
// CTuner::SetFrequency (so requires to use method pr_Channel to work.
// I suggest to to use IAMAnalogVideoDecoder::HorizontalLocking() to determine
// if a video signal is present, or trust in the returned value of SetFrequency.

int CTuner::CheckSignal(int method)
{
	HRESULT hr;
    if(method!=2)
    {
        IKsPropertySet *kps;
        KSPROPERTY_TUNER_STATUS_S tss;
        hr=pTVTuner->QueryInterface(IID_IKsPropertySet,(void **)&kps);
        if(hr==NOERROR)
        {
            ZeroMemory(&tss,sizeof(tss));
            DWORD ret=0;
            hr=kps->Get(PSET_TUNER,
						KSPROPERTY_TUNER_STATUS,
						INSTANCE_DATA_OF_PROPERTY_PTR(&tss),	// The KSPROPERTY first member of the struct is ADDED by the IKsPropertySet::Set method, so we must pass a pointer to the fisrt element following the KSPROPERTY struct member (this is called "the instance data in the DirectX SDK")
						INSTANCE_DATA_OF_PROPERTY_SIZE(tss),	// This is the size of the instance data (you must consider the size of the struct MINUS the size of the KSPROPERTY, that is ADDED by the IKsPropertySet::Set method )
						&tss,									// Here we need a pointer to the property (NOT instance) data, so the pointer to the full propertyt struct is required.
						sizeof(tss),							// Here we need the size of the property (NOT instance) data, so the size of rhe full property struct is required.
						&ret);


			// Release the interface, as we won't use it anymore.
			kps->Release(); 

            if(FAILED(hr))Log(__FUNC__,__LINE__,"KSPROPERTY_TUNER_STATUS",hr);
            return  tss.PLLOffset;
        }else Log(__FUNC__,__LINE__,"pTVTuner->QueryInterface IID_IKsPropertySet",hr);
    }
    else
    {
	    long SignalStrength = AMTUNER_NOSIGNAL;
		hr=pTVTuner->SignalPresent(&SignalStrength);
		if(FAILED(hr))Log(__FUNC__,__LINE__,"pTVTuner->SignalPresent failed",hr);
		return SignalStrength;
    }
}

