⬆️ ⬇️

Applications for receiving digital broadcasting by means of DirectShow

The application is written under Windows7, DirectX 9, tuner model - AverTV Duo Hybrid PCI-E2, C # language



Microsoft TV Technologies Internals . This article describes a graph for receiving digital TV broadcasting, as well as filters that are used when constructing a graph.



To create an application you need:

1. Build a graph.

In my column I use the following filters:

• Microsoft DVB-T Network Provider

• AVerMedia 716x BDA DVBT Tuner (depending on your Tuner model)

• AVerMedia 716x BDA Digital Capture (depending on your Tuner model)

• MPEG2 Demultiplexer

• BDA MPEG2 Transport Information Filter

• MPEG-2 Sections and Tables

• Microsoft DTV-DVD Video Decoder

• Video Mixing Renderer 9



2. Configure Network Provider:

Provider settings include creating an instance of the DVBTuningSpace class, setting up this object in accordance with the DVB-T standard. Through an instance of the DVBTuningSpace class, a TuneRequest object is created, which must be transferred to the provider.

')

3. Adjust the locator to the desired frequency.

Locator is an instance of the DVBTLocator class, which is used to set

carrier frequency. (Some tuners are able to independently scan frequencies and if you set the wrong carrier frequency, the graph will receive and display the channels).

Now let's deal with each filter separately:

1. BDA Network Provider is a filter source for graphs working with digital television. There are several filters in this category:

o For DVB-S (Satellite TV) standard: Microsoft DVB-S Network Provider

o For DVB-T (Terrestrial TV) standard: Microsoft DVB-T Network Provider

o For DVB-C (Cable TV) standard: Microsoft DVB-C Network Provider

o For ATSC (American Standard Digital TV) standard: Microsoft ATSC Network Provider

In our case, we use the filter Microsoft DVB-T Network Provider



To obtain the channels corresponding to the carrier frequency, the MPEG-2 Sections and Tables filter is used. Through it, you can get the PAT table, which contains the SIDs of the available channels.

The IDVBTuneRequest interface is used to display a specific channel. Using the put_SID method, you can transfer the SID of the channel you need.

Note: After updating the provider, for example, setting a new frequency, it is necessary to start the graph, if it is not already running. If the graph is stopped, then when you try to get data from the filters, for example, getting the PAT table from the MPEG-2 Sections and Tables filter, you will get a result inconsistent with the new provider settings.



DVB-T graph in GraphEditPlus:

image



Add filters to graph:



#region add filters methods int IGraphDVBT.AddNetworkProvider() { pNetworkProvider = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(typeof(DVBTNetworkProvider).GUID)); return pGraph.AddFilter(pNetworkProvider, "Network Provider"); } int IGraphDVBT.AddTuner() { pDVBTTuner = DirectShowTools.CreateFilter(FilterCategory.BDASourceFiltersCategory, "AVerMedia 716x BDA DVBT Tuner"); return pGraph.AddFilter(pDVBTTuner, "DVBT Tuner"); } int IGraphDVBT.AddCapture() { pDigitalCapture = DirectShowTools.CreateFilter(FilterCategory.BDAReceiverComponentsCategory, "AVerMedia 716x BDA Digital Capture"); return pGraph.AddFilter(pDigitalCapture, "Digital Capture"); } int IGraphDVBT.AddMPEG2Demultiplexer() { pMPEGDemux = (IBaseFilter)new MPEG2Demultiplexer(); return pGraph.AddFilter(pMPEGDemux, "MPEG2 Demultiplexer"); } int IGraphDVBT.AddBDAMPEG2TIF() { pBDAMPEGTIF = DirectShowTools.CreateFilter(FilterCategory.LegacyAmFilterCategory, "BDA MPEG2 Transport Information Filter"); return pGraph.AddFilter(pBDAMPEGTIF, "BDA MPEG2 TIF"); } int IGraphDVBT.AddMPEG2SectAndTables() { pMPEGSectAndTables = DirectShowTools.CreateFilter(FilterCategory.LegacyAmFilterCategory, "MPEG-2 Sections and Tables"); return pGraph.AddFilter(pMPEGSectAndTables, "MPEG2 Section and Tables"); } int IGraphDVBT.AddVideoDecoder() { pVideoDecoder = DirectShowTools.CreateFilter(FilterCategory.LegacyAmFilterCategory, "Microsoft DTV-DVD Video Decoder"); return pGraph.AddFilter(pVideoDecoder, "DTV-DVD Video Decode"); } int IGraphDVBT.AddVideoRenderer() { pVideoRenderer = (IBaseFilter)new VideoMixingRenderer9(); return pGraph.AddFilter(pVideoRenderer, "Video Renderer"); } int IGraphDVBT.AddAudioDecoder() { pAudioDecoder = DirectShowTools.CreateFilter(FilterCategory.LegacyAmFilterCategory, "Microsoft DTV-DVD Audio Decoder"); return pGraph.AddFilter(pAudioDecoder, "DTV-DVD Audio Decode"); } int IGraphDVBT.AddAudioRenderer() { pAudioRenderer = DirectShowTools.CreateFilter(FilterCategory.AudioRendererCategory, "Default DirectSound Device"); return pGraph.AddFilter(pAudioRenderer, "Audio Renderer"); } #endregion 







The filter pins must be interconnected (Note that the pin names in your case may be completely different) :



 int IGraphDVBT.ConnectFilters() { int hr; IPin outPin; IPin inPin; outPin = DirectShowTools.FindPin(pNetworkProvider, new string[] { "Antenna Out" }); inPin = DirectShowTools.FindPin(pDVBTTuner, new string[] { "0" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pDVBTTuner, new string[] { "1" }); inPin = DirectShowTools.FindPin(pDigitalCapture, new string[] { "0" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pDigitalCapture, new string[] { "1" }); inPin = DirectShowTools.FindPin(pMPEGDemux, new string[] { "MPEG-2 Stream" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pMPEGDemux, new string[] { "001" }); inPin = DirectShowTools.FindPin(pBDAMPEGTIF, new string[] { "IB Input" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pMPEGDemux, new string[] { "002" }); inPin = DirectShowTools.FindPin(pMPEGSectAndTables, new string[] { "In" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pMPEGDemux, new string[] { "003" }); inPin = DirectShowTools.FindPin(pVideoDecoder, new string[] { "Video Input" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pMPEGDemux, new string[] { "007" }); inPin = DirectShowTools.FindPin(pAudioDecoder, new string[] { "In" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pVideoDecoder, new string[] { "Video Output 1" }); inPin = DirectShowTools.FindPin(pVideoRenderer, new string[] { "VMR Input0" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; outPin = DirectShowTools.FindPin(pAudioDecoder, new string[] { "Out" }); inPin = DirectShowTools.FindPin(pAudioRenderer, new string[] { "Audio Input pin (rendered)" }); hr = pGraph.Connect(outPin, inPin); if (hr < 0) return hr; return 0; } 









Now we are setting up DVB-T Network Provider. To do this, you must specify the appropriate DVB-T types for an instance of the DVBTuningSpace class. By the method put_TuneRequest we activate the configured object in the provider.



 int IGraphDVBT.SetNetworkProvider() { int hr; IDVBTuningSpace tuningSpace = (IDVBTuningSpace)new DVBTuningSpace(); hr = tuningSpace.put_UniqueName("DVBT TuningSpace"); if (hr < 0) return hr; hr = tuningSpace.put_FriendlyName("DVBT TuningSpace"); if (hr < 0) return hr; hr = tuningSpace.put_NetworkType("{" + typeof(DVBTNetworkProvider).GUID.ToString() + "}"); if (hr < 0) return hr; hr = tuningSpace.put_SystemType(DVBSystemType.Terrestrial); if (hr < 0) return hr; ITuneRequest tr; hr = tuningSpace.CreateTuneRequest(out tr); if (hr < 0) return hr; IDVBTuneRequest tuneRequest = (IDVBTuneRequest)tr; hr = (pNetworkProvider as ITuner).put_TuneRequest(tuneRequest); if (hr < 0) return hr; return 0; } 









In order for the connected graph to make it work, it must be tuned to the desired frequency. For this, there is an IDVBTLocator interface, with which we will set the carrier frequency. We do not need all the other parameters, so we give them the appropriate values:



 private int SetDVBTLocator(int frequency, out IDVBTLocator locator) { int hr = 0; // -- LOCATOR -- locator = (IDVBTLocator)new DVBTLocator(); //set frequency hr = locator.put_CarrierFrequency(frequency); /* kGz */ if (hr < 0) return hr; //Not set parameters hr = locator.put_Bandwidth(-1); /* in Mgz */ if (hr < 0) return hr; hr = locator.put_SymbolRate(-1); if (hr < 0) return hr; hr = locator.put_OtherFrequencyInUse(false); if (hr < 0) return hr; hr = locator.put_LPInnerFEC(FECMethod.MethodNotSet); if (hr < 0) return hr; hr = locator.put_LPInnerFECRate(BinaryConvolutionCodeRate.RateNotSet); if (hr < 0) return hr; hr = locator.put_HAlpha(HierarchyAlpha.HAlphaNotSet); if (hr < 0) return hr; hr = locator.put_Mode(TransmissionMode.ModeNotSet); if (hr < 0) return hr; hr = locator.put_InnerFEC(FECMethod.MethodNotSet); if (hr < 0) return hr; hr = locator.put_InnerFECRate(BinaryConvolutionCodeRate.RateNotSet); if (hr < 0) return hr; hr = locator.put_OuterFEC(FECMethod.MethodNotSet); if (hr < 0) return hr; hr = locator.put_OuterFECRate(BinaryConvolutionCodeRate.RateNotSet); if (hr < 0) return hr; hr = locator.put_Modulation(ModulationType.ModNotSet); if (hr < 0) return hr; return 0; } 









Now you can set the carrier frequency and see which channels are on it. To do this, we get tuneRequest from the provider, set up our locator with the specified frequency, update our provider with new settings, and, through the IMpeg2Data interface, retrieve the PAT table from the MPEG-2 Sections and Tables filter, which will contain the corresponding carrier frequency . If you choose the wrong frequency, the GetPAT method will return you a negative HRESULT.



 public string[] SetFrequency(int frequency) { if (((IGraphDVBT)ConcreteGraph).NetworkProvider == null || ((IGraphDVBT)ConcreteGraph).TablesAndSections == null) { return null; } int hr = 0; IPAT PAT; //Table with SID IDVB_SDT SDT; IDVB_SIT SIT; int channelCount = 0; short pwVal = 0; ITuneRequest tuneRequest = null; //get tune request hr = (((IGraphDVBT)ConcreteGraph).NetworkProvider as ITuner).get_TuneRequest(out tuneRequest); if (hr < 0 || tuneRequest == null) { return null; } IDVBTuneRequest DVBtuneRequest = tuneRequest as IDVBTuneRequest; IDVBTLocator locator; //set locator with necessary frequency hr = SetDVBTLocator(frequency, out locator); if (hr < 0 || locator == null) { return null; } hr = DVBtuneRequest.put_Locator(locator); if (hr < 0) { return null; } //mediaControl.Stop(); hr = (((IGraphDVBT)ConcreteGraph).NetworkProvider as ITuner).put_TuneRequest(DVBtuneRequest); if (hr < 0) { return null; } //mediaControl.Run(); //value is channel SID IDvbSiParser parser = (IDvbSiParser)new DvbSiParser(); hr = parser.Initialize(((IGraphDVBT)ConcreteGraph).TablesAndSections as IMpeg2Data); if (hr < 0) { return null; } //get table with channels hr = parser.GetPAT(out PAT); if (hr < 0) { //DsError.ThrowExceptionForHR(hr); return null; } //get count of channels hr = PAT.GetCountOfRecords(out channelCount); if (hr < 0) { return null; } string[] channelsDVBT = new string[channelCount]; //put channels number in the list for (int i = 0; i < channelCount; i++) { PAT.GetRecordProgramNumber(i,out pwVal); channelsDVBT[i] = "Channel_" + pwVal.ToString(); } return channelsDVBT; } 









Note: After you update the provider, be sure to start the graph (if it is not already running). This is done using the IMediaControl interface.

To set up a provider for a specific channel, use the IDVBTuneRequest interface. Using the put_SID method, you can transfer the SID of the channel you need.



 /// <summary> /// Take tune request from Network Provider /// Set New SID and put tune request on the Network Provider /// </summary> /// <param name="SID">channel SID</param> public void SetDVBTChannels(int SID) { int hr = 0; ITuneRequest tuneRequest = null; //get tune request hr = (((IGraphDVBT)ConcreteGraph).NetworkProvider as ITuner).get_TuneRequest(out tuneRequest); if (tuneRequest == null) { return; } IDVBTuneRequest DVBtuneRequest = tuneRequest as IDVBTuneRequest; //set new channel hr = DVBtuneRequest.put_SID(SID); //put tune request hr = (((IGraphDVBT)ConcreteGraph).NetworkProvider as ITuner).put_TuneRequest(DVBtuneRequest); } 








image



The full code of the program is available at the following link: Code

Source: https://habr.com/ru/post/127913/



All Articles