none
Generic Network Provider not working with ATSC RRS feed

  • Question

  • I am having difficulty getting the Generic Network Provider to work when tuning.  The ATSC Network Provider works fine, but I cannot use that to tune QAM.  TV Tuner devices seem to require the the Generic Network Provider be used to tune ATSC QAM.

    My first task, I would imagine, would be to take code that works with an ATSC Antenna and use the Generic Network Provider instead of the ATSC Network Provider.  I really don't see any documention about extra things the Generic Network Provider requires, so I thought it would be as easy as swapping them out.

    That is not so.  When I attempt to use any of the put functions in a ITuner (IScanningTuner specifically) that is gotten from the Generic Network Provider, an error code of 87 (dec) is returned that states that I am passing an invalid parameter.  I do not understand why it would return this.  Are there extra prerequisites to using the Generic Network Provider?

    Here is the complete code for a test application that I wrote.  I have commented the areas of interest.  If you change CLSID_NetworkProvider to CLSID_ATSCNetworkProvider, then you will be able to tune channels just fine.  Though, change it back to CLSID_NetworkProvider, and it will fail.

    I would love to hear if anyone has gotten the Generic Network Provider to work.

    #include <iostream>
    #include <vector>
    #include <windows.h>
    #include <atlbase.h>
    #include <atlcom.h>
    #include <initguid.h>
    #include <comdef.h>
    #include <tuner.h>
    #include <dshow.h>
    #include <Ks.h>
    #include <Ksmedia.h>
    #include <Bdamedia.h>
    #include <Bdatif.h>
    #include <mpeg2data.h>
    #include <mpeg2bits.h>
    
    
    HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath);
    IBaseFilter* loadFilter(IGraphBuilder* iGraphBuilder, REFCLSID id, IBaseFilter* filter, IBaseFilter* connectionFilter);
    bool connectFilters(IGraphBuilder* iGraphBuilder, IBaseFilter* fromFilter, IBaseFilter* toFilter);
    IBaseFilter* renderDemuxPins(IGraphBuilder* iGraphBuilder, IBaseFilter* demux);
    
    HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) 
    {
        const WCHAR wszStreamName[] = L"ActiveMovieGraph"; 
        HRESULT hr;
        
        IStorage *pStorage = NULL;
        hr = StgCreateDocfile(
            wszPath,
            STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
            0, &pStorage);
        if(FAILED(hr)) 
        {
            return hr;
        }
    
        IStream *pStream;
        hr = pStorage->CreateStream(
            wszStreamName,
            STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
            0, 0, &pStream);
        if (FAILED(hr)) 
        {
            pStorage->Release();    
            return hr;
        }
    
        IPersistStream *pPersist = NULL;
        pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
        hr = pPersist->Save(pStream, TRUE);
        pStream->Release();
        pPersist->Release();
        if (SUCCEEDED(hr)) 
        {
            hr = pStorage->Commit(STGC_DEFAULT);
        }
        pStorage->Release();
        return hr;
    }
    
    IBaseFilter* loadFilter(IGraphBuilder* iGraphBuilder, REFCLSID id, IBaseFilter* filter, IBaseFilter* connectionFilter)
    {
    	CComPtr< ICreateDevEnum > iCreateDevEnum;
    	if(FAILED(iCreateDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC)))
    		throw std::exception("Could not create device enumerator.");
    	CComPtr< IEnumMoniker > iEnumMoniker;
    	if(FAILED(iCreateDevEnum->CreateClassEnumerator(id, &iEnumMoniker, 0)))
    		throw std::exception("Could not create class enumerator.");
    	CComPtr< IMoniker > iMoniker;
    	while(iEnumMoniker->Next(1, &iMoniker, 0) == S_OK)
    	{
    		CComPtr< IPropertyBag > iPropertyBag;
    		if(FAILED(iMoniker->BindToStorage(NULL, NULL, IID_IPropertyBag, (void**)&iPropertyBag)))
    			throw std::exception("Could not bind property bag storage");
    		CComVariant str;
    		if(FAILED(iPropertyBag->Read(L"FriendlyName", &str, NULL)))
    		{
    			iMoniker = NULL;
    			continue;
    		}
    		CComPtr< IBaseFilter > iFilter;
    		if(FAILED(iMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)(&iFilter))))
    		{
    			iMoniker = NULL;
    			continue;
    		}			
    		if(SUCCEEDED(iGraphBuilder->AddFilter(iFilter, str.bstrVal)))
    		{
    			if(connectionFilter)
    			{
    				if(FAILED(iFilter.QueryInterface(&filter)))
    					throw std::exception("Could not query tuner interface.");
    				if(connectFilters(iGraphBuilder, connectionFilter, filter))
    					return filter;
    				else
    					iGraphBuilder->RemoveFilter(iFilter);
    			}
    			else
    				return filter;
    		}
    		iMoniker = NULL;
    	}
    	return 0;
    }
    
    bool connectFilters(IGraphBuilder* iGraphBuilder, IBaseFilter* fromFilter, IBaseFilter* toFilter)
    {
    	PIN_INFO fromPinInfo;
    	PIN_INFO toPinInfo;
    	CComPtr< IPin > fromPin;
    	CComPtr< IEnumPins > fromIEnumPins;
    	if(FAILED(fromFilter->EnumPins(&fromIEnumPins)))
    		throw std::exception("Could not retrieve filter's enumerator");
    	while(fromIEnumPins->Next(1, &fromPin, 0) == S_OK)
    	{
    		if(FAILED(fromPin->QueryPinInfo(&fromPinInfo)))
    			throw std::exception("Could not query pin info.");
    		CComPtr< IPin > connectedPin;
    		fromPin->ConnectedTo(&connectedPin);
    		if(fromPinInfo.dir == PINDIR_OUTPUT && connectedPin == NULL)
    		{
    			CComPtr< IPin > toPin;
    			CComPtr< IEnumPins > toIEnumPins;
    			if(FAILED(toFilter->EnumPins(&toIEnumPins)))
    				throw std::exception("Could not retrieve filter's enumerator");
    			while(toIEnumPins->Next(1, &toPin, 0) == S_OK)
    			{
    				if(FAILED(toPin->QueryPinInfo(&toPinInfo)))
    					throw std::exception("Could not query pin info.");
    				toPin->ConnectedTo(&connectedPin);
    				if(toPinInfo.dir == PINDIR_INPUT && connectedPin == NULL)
    				{
    					if(SUCCEEDED(iGraphBuilder->Connect(fromPin, toPin)))
    					{
    						toPinInfo.pFilter->Release();
    						fromPinInfo.pFilter->Release();
    						return true;
    					}
    				}
    			toPinInfo.pFilter->Release();
    			toPin = NULL;
    			}
    		}
    		fromPinInfo.pFilter->Release();
    		fromPin = NULL;
    	}
    	return false;
    }
    
    IBaseFilter* renderDemuxPins(IGraphBuilder* iGraphBuilder, IBaseFilter* demux)
    {
    	PIN_INFO demuxPinInfo;
    	CComPtr< IPin > demuxPin;
    	CComPtr< IEnumPins > demuxIEnumPins;
    	if(FAILED(demux->EnumPins(&demuxIEnumPins)))
    		throw std::exception("Could not retrieve filter's enumerator");
    	while(demuxIEnumPins->Next(1, &demuxPin, 0) == S_OK)
    	{
    		if(FAILED(demuxPin->QueryPinInfo(&demuxPinInfo)))
    			throw std::exception("Could not query pin info.");
    		if(demuxPinInfo.dir == PINDIR_OUTPUT)
    			iGraphBuilder->Render(demuxPin);
    		demuxPinInfo.pFilter->Release();
    		demuxPin = NULL;
    	}
    	return demux;
    }
    
    
    int main()
    {
    	CoInitialize(NULL);
    	
    	long currentPhysical = 47;
    	
    	CComPtr< IScanningTuner > iTuner;
    	CComPtr< ITuningSpaceContainer > iTuningSpaceContainer;
    	CComPtr< IEnumTuningSpaces > iEnumTuningSpaces;
    	CComPtr< ITuningSpace > iEnumTuningSpace;
    	CComPtr< ITuneRequest > iTuneRequest;
    	CComPtr< IATSCTuningSpace > iATSCTuningSpace;
    	CComPtr< IATSCLocator > iATSCLocator;
    	CComPtr< IATSCChannelTuneRequest > iATSCTuneRequest;
    	CComPtr< ITuningSpace > iTuningSpace;
    	CComPtr< IBaseFilter > iNetworkProvider;
    	CComPtr< IBaseFilter > iTunerDevice;
    	CComPtr< IBaseFilter > iCaptureFilter;
    	CComPtr< IBaseFilter > iDemux;
    	CComPtr< IGraphBuilder > iGraphBuilder;
    	CComPtr< IMediaControl > iMediaControl;
    	
    	try
    	{
    		if(FAILED(iTuningSpaceContainer.CoCreateInstance(CLSID_SystemTuningSpaces, NULL, CLSCTX_INPROC_SERVER)))
    			throw std::exception("Could not create tuning space container.");
    		CComBSTR atscStr(L"ATSC");
    		if(FAILED(iTuningSpaceContainer->get_EnumTuningSpaces(&iEnumTuningSpaces)))
    			throw std::exception("Could not get enum tuning spaces.");
    		while(S_OK == iEnumTuningSpaces->Next(1, &iEnumTuningSpace, NULL))
    		{
    			CComBSTR tempStr;
    			iEnumTuningSpace->get_UniqueName(&tempStr);
    			if(tempStr == atscStr)
    				break;
    			iEnumTuningSpace = NULL;
    		}
    		if(!iEnumTuningSpace)
    			throw std::exception("Could not enumerate tuning space.");
    		if(FAILED(iEnumTuningSpace.QueryInterface(&iATSCTuningSpace)))
    			throw std::exception("Could not query ATSC tuning space");
    		iATSCTuningSpace->put_MaxPhysicalChannel(999);	
    		if(FAILED(iATSCTuningSpace->CreateTuneRequest(&iTuneRequest)))
    			throw std::exception("Could not create tune request.");
    		if(FAILED(iATSCLocator.CoCreateInstance(CLSID_ATSCLocator, NULL, CLSCTX_INPROC_SERVER)))
    			throw std::exception("Could not create ATSC locator.");
    		if(FAILED(iATSCLocator->put_PhysicalChannel(currentPhysical)))
    			throw std::exception("Could not set physical channel.");
    		if(FAILED(iTuneRequest->QueryInterface(&iATSCTuneRequest)))
    			throw std::exception("Could not query ATSC tune request.");
    		iATSCTuneRequest->put_Channel(-1);
    		iATSCTuneRequest->put_MinorChannel(-1);
    		iATSCTuneRequest->put_Locator(iATSCLocator);	
    		if(FAILED(iTuneRequest->get_TuningSpace(&iTuningSpace)))
    			throw std::exception("Could not find tuning space.");
    		///////////////////////////////////////////////////////////////////////
    		// Try CLSID_ATSCNetworkProvider and CLSID_NetworkProvider
    		if(FAILED(iNetworkProvider.CoCreateInstance(CLSID_NetworkProvider)))
    			throw std::exception("Could not create network provider.");
    		///////////////////////////////////////////////////////////////////////
    		if(FAILED(iGraphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC)))
    			throw std::exception("Could not create graph.");
    		if(FAILED(iGraphBuilder->AddFilter(iNetworkProvider, L"Network Provider")))
    			throw std::exception("Could not add network provider to graph.");
    		if(FAILED(iNetworkProvider.QueryInterface(&iTuner)))
    			throw std::exception("Could not query iTuner interface.");
    		/////////////////////////////////////////////////////////////////////////////
    		// Does not tune with Generic Network Provider, but will tune with ATSC Network Provider.
    		HRESULT hr = iTuner->put_TuneRequest(iATSCTuneRequest);
    		if(FAILED(hr))
    		{
    			std::cout << HRESULT_CODE(hr) << ": ";
    			throw std::exception("Could not submit tune request to network provider.");
    		}
    		/////////////////////////////////////////////////////////////////////////////
    		if((iTunerDevice = loadFilter(iGraphBuilder, KSCATEGORY_BDA_NETWORK_TUNER, iTunerDevice, iNetworkProvider)) == NULL)
    			throw std::exception("Could not load BDA Network Tuner filter.");
    		if((iCaptureFilter = loadFilter(iGraphBuilder, KSCATEGORY_BDA_RECEIVER_COMPONENT, iCaptureFilter, iTunerDevice)) == NULL)
    			throw std::exception("Could not load BDA Network Tuner filter.");
    		if(FAILED(iDemux.CoCreateInstance(CLSID_MPEG2Demultiplexer, NULL, CLSCTX_INPROC_SERVER)))
    			throw std::exception("Could not create demux.");
    		if(FAILED(iGraphBuilder->AddFilter(iDemux, L"Demux")))
    			throw std::exception("Could not add Demux filer.");
    		if(!connectFilters(iGraphBuilder, iCaptureFilter, iDemux))
    			throw std::exception("Could not connect Capture filter to Demux filter.");
    		iDemux = renderDemuxPins(iGraphBuilder, iDemux);
    		SaveGraphFile(iGraphBuilder, L"C:\\Temp\\test.grf");
    		iGraphBuilder.QueryInterface(&iMediaControl);
    		if(FAILED(iMediaControl->Run()))
    			throw std::exception("Could not run Media Control.");	
    	}
    	catch(const std::exception& ex)
    	{
    		std::cout << ex.what() << std::endl;
    	}
    	std::cin.get();
    	CoUninitialize();
    	return 0;
    }
    
    
    Friday, April 2, 2010 2:16 PM

Answers

All replies

  • Ok, an update.  It seems that I need to put the "put_tuneRequest" after the iMediaControl->Run() function for it to work.  I will continue to update this thread on getting QAM tuning to work, because I have seen quite a few people have issues with it.
    Friday, April 2, 2010 2:28 PM
  • Well, I suppose the next thing I'm stuck on is the ILocator.  Submitting a locator to a tune request doesn't seem to do anything.  I can put junk values in the locator, and it doesn't mess up the tune request.

    What does it take to have a locator effect a tune request?  I need to be able to change the modulation to BDA_MOD_256QAM, but doing this does not seem to have an effect on the tune request.  It still seems to use BDA_MOD_8VSB.

    Friday, April 2, 2010 3:27 PM
  • It's the tuner's driver that determines which network provider you need to use.  Look here http://www.silicondust.com/hdhomerun/hdhomerun_development.pdf under "BDA Demodulator type:"

     

    • Marked as answer by Keywest2010 Tuesday, April 6, 2010 1:37 PM
    Friday, April 2, 2010 4:30 PM
  • That is correct.  It seems to get QAM to work, you must pass a cable freqency in the locator, and it will switch to QAM when submitting the request to the tuner.  The device will automatically switch.  I found it helpful to use a Happauge device since it comes with a program called Signal Monitor which displays whether the tuner is in ATSC or QAM mode.
    Tuesday, April 6, 2010 1:33 PM
  • Unfortunately it doesn't switch for me to QAM so easily.  Looks like it continues to use BDA_MOD_8VSB regardless of what I assign in the locator object.

    May be the problem is in the Tuning Space? Vista and later have IDigitalCableTuningSpace, but I need to run it on Win XP.

    Should I create my own Tuning Space object in such case (can't find any sample)? Is it possible to modify ATSC Antenna default Tuning Space?

     

    Thank you!

    Friday, July 2, 2010 6:45 PM