VDR constantly tries to change transponder frequency

Message ID 44777651.1030906@gmail.com
State New
Headers

Commit Message

Anssi Hannula May 26, 2006, 9:42 p.m. UTC
  Klaus Schmidinger wrote:
> Anssi Hannula wrote:
> 
>> I've now had time to debug this bug more, too.
>>
>>>> Anssi Hannula wrote:
>>>>
>>>>> Hi!
>>>>>
>>>>> VDR constantly changes the frequency of one multiplex in DVB-T.
>>>>>
>>>>> Here's an example:
>>>>> Correct:
>>>>> Urheilukanava;Suomen Urheilutelevisio
>>>>> Oy:770000000:C23D23M64B8T8G8Y0:T:27500:417+130:673=fin:929:0:113:8438:12289:0
>>>>>
>>>>>
>>>>>
>>>>> But then VDR decides to change it:
>>>>>
>>>>> Dec 29 18:32:48 delta vdr[18069]: changing transponder data of channel
>>>>> 22 from T:770000000:0:3:0:2:2:2:1 to T:674000000:0:3:0:2:2:2:1
>>>>>
>>>>> And then of course the channels stop being watchable.
>>>>>

>>
>> The NIT data (pid 16) of Finnish DVB-T operated by Digita apparently
>> confuses VDR:
>>
>> The center frequency advertised in the
>> terrestrial_delivery_system_descriptor is not necessarily the real
>> frequency, but other_frequency_flag is set to "1" and there is provided
>> a frequency_list_descriptor which contains all the possible frequencies
>> of this mux (probably nation-wide), and the correct frequency is one of
>> those.
>>
>> Digita also sends NITs of all muxes in all muxes, and as VDR relies on
>> frequencies to detect which on of those is the correct one, the
>> detection fails and VDR always selects the NIT of mux 3, explaining why
>> it that mux is the only one affected by the frequency-changing.
>>

>>
>> After a quick look it seems that libsi has support for
>> frequency_list_descriptor.
>>
>> If you want to see the actual NIT data, it's there:
>> http://stuff.onse.fi/digita-nit/
>>
>> Note that the other_frequency_flag is DVB-T-specific.

> 
> Well, I guess it would be best if you give it a shot, since you
> have the data stream necessary for testing this.

Okay, attached is a patch for nit.c that checks for all the frequencies
in frequency_list_descriptor for the channel's frequency and if found,
use it so that channel's frequency is not changed.

Also in the detection of new transponders all frequencies are added for
the EITscanner.

I tested it by removing a transponder from channels.conf, and VDR found
it again (though it took a while, as there are *many* frequencies in the
frequency_list_descriptor). This too hasn't been working before on the
DVB-T network of Finland.

Note that the patch uses list from C++ STL. If you wish to implement the
list with something else, it should be trivial to modify.
  

Comments

Klaus Schmidinger May 27, 2006, 12:47 p.m. UTC | #1
Anssi Hannula wrote:
> ...
> Okay, attached is a patch for nit.c that checks for all the frequencies
> in frequency_list_descriptor for the channel's frequency and if found,
> use it so that channel's frequency is not changed.
> 
> Also in the detection of new transponders all frequencies are added for
> the EITscanner.
> 
> I tested it by removing a transponder from channels.conf, and VDR found
> it again (though it took a while, as there are *many* frequencies in the
> frequency_list_descriptor). This too hasn't been working before on the
> DVB-T network of Finland.
> 
> Note that the patch uses list from C++ STL. If you wish to implement the
> list with something else, it should be trivial to modify.
> 
> 
> 
> ------------------------------------------------------------------------
> 
> --- vdr-vanilla/nit.c	2006-04-15 17:10:42.000000000 +0300
> +++ vdr-vanilla/nit.c.new	2006-05-27 00:14:16.000000000 +0300
> @@ -7,6 +7,7 @@
>   * $Id: nit.c 1.11 2006/04/15 14:10:42 kls Exp $
>   */
>  
> +#include <list>
>  #include "nit.h"
>  #include <linux/dvb/frontend.h>
>  #include "channels.h"
> @@ -95,39 +96,75 @@ void cNitFilter::Process(u_short Pid, u_
>    SI::NIT::TransportStream ts;
>    for (SI::Loop::Iterator it; nit.transportStreamLoop.getNext(ts, it); ) {
>        SI::Descriptor *d;
> +      std::list<int> Frequencies;
> +      std::list<int>::iterator frequency;
> +      for (SI::Loop::Iterator it2; (d = ts.transportStreamDescriptors.getNext(it2, SI::FrequencyListDescriptorTag)); ) {
> +          SI::FrequencyListDescriptor *fld = (SI::FrequencyListDescriptor *)d;
> +          int coding_type = fld->getCodingType();
> +          switch (coding_type) {
> +            case 1: // Satellite
> +                 for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); )
> +                     Frequencies.push_back(BCD2INT(fld->frequencies.getNext(it3)) / 100);
> +                 break;
> +            case 2: // Cable
> +                 for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); )
> +                     Frequencies.push_back(BCD2INT(fld->frequencies.getNext(it3)) / 10);
> +                 break;
> +            case 3: // Terrestrial
> +                 for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); )
> +                     Frequencies.push_back(fld->frequencies.getNext(it3) * 10);
> +                 break;
> +            default: ;
> +            }

I believe there is a 'delete d' missing here.

> +          }

I guess it's fair to assume that each TransportStream can contain
at most one FrequencyListDescriptor, right? Otherwise the above
loop could mix frequencies from different coding types, which would
lead to confusion later on.

Klaus
  
Anssi Hannula May 27, 2006, 3:56 p.m. UTC | #2
On 5/27/06, Klaus Schmidinger <Klaus.Schmidinger@cadsoft.de> wrote:
> Anssi Hannula wrote:
> > ...
> > Okay, attached is a patch for nit.c that checks for all the frequencies
> > in frequency_list_descriptor for the channel's frequency and if found,
> > use it so that channel's frequency is not changed.
> >
> > Also in the detection of new transponders all frequencies are added for
> > the EITscanner.
> >
> > I tested it by removing a transponder from channels.conf, and VDR found
> > it again (though it took a while, as there are *many* frequencies in the
> > frequency_list_descriptor). This too hasn't been working before on the
> > DVB-T network of Finland.

Just to be clear, of course it worked before in the Digita's (operator
of the Finnish DVB-T) network too if you happened to be one of lucky
ones whose center_frequency in delivery_descriptor happens to be the
correct one.

> I guess it's fair to assume that each TransportStream can contain
> at most one FrequencyListDescriptor, right? Otherwise the above
> loop could mix frequencies from different coding types, which would
> lead to confusion later on.

I guess it is.

I can think of only one possible usage case when there could be
multiple FrequencyLists: If the same multiplex is transmitted in
multiple mediums in multiple frequencies, e.g. DVB-T and DVB-C,
multiple lists could be used. But yes, that wouldn't make much sense
as the bandwidth of DVB-T and DVB-C differs.
  

Patch

--- vdr-vanilla/nit.c	2006-04-15 17:10:42.000000000 +0300
+++ vdr-vanilla/nit.c.new	2006-05-27 00:14:16.000000000 +0300
@@ -7,6 +7,7 @@ 
  * $Id: nit.c 1.11 2006/04/15 14:10:42 kls Exp $
  */
 
+#include <list>
 #include "nit.h"
 #include <linux/dvb/frontend.h>
 #include "channels.h"
@@ -95,39 +96,75 @@  void cNitFilter::Process(u_short Pid, u_
   SI::NIT::TransportStream ts;
   for (SI::Loop::Iterator it; nit.transportStreamLoop.getNext(ts, it); ) {
       SI::Descriptor *d;
+      std::list<int> Frequencies;
+      std::list<int>::iterator frequency;
+      for (SI::Loop::Iterator it2; (d = ts.transportStreamDescriptors.getNext(it2, SI::FrequencyListDescriptorTag)); ) {
+          SI::FrequencyListDescriptor *fld = (SI::FrequencyListDescriptor *)d;
+          int coding_type = fld->getCodingType();
+          switch (coding_type) {
+            case 1: // Satellite
+                 for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); )
+                     Frequencies.push_back(BCD2INT(fld->frequencies.getNext(it3)) / 100);
+                 break;
+            case 2: // Cable
+                 for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); )
+                     Frequencies.push_back(BCD2INT(fld->frequencies.getNext(it3)) / 10);
+                 break;
+            case 3: // Terrestrial
+                 for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); )
+                     Frequencies.push_back(fld->frequencies.getNext(it3) * 10);
+                 break;
+            default: ;
+            }
+          }
       for (SI::Loop::Iterator it2; (d = ts.transportStreamDescriptors.getNext(it2)); ) {
           switch (d->getDescriptorTag()) {
             case SI::SatelliteDeliverySystemDescriptorTag: {
                  SI::SatelliteDeliverySystemDescriptor *sd = (SI::SatelliteDeliverySystemDescriptor *)d;
                  int Source = cSource::FromData(cSource::stSat, BCD2INT(sd->getOrbitalPosition()), sd->getWestEastFlag());
                  int Frequency = BCD2INT(sd->getFrequency()) / 100;
+                 Frequencies.push_front(Frequency);
                  static char Polarizations[] = { 'h', 'v', 'l', 'r' };
                  char Polarization = Polarizations[sd->getPolarization()];
                  static int CodeRates[] = { FEC_NONE, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_NONE };
                  int CodeRate = CodeRates[sd->getFecInner()];
                  int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10;
                  if (ThisNIT >= 0) {
-                    if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) {
-                       nits[ThisNIT].hasTransponder = true;
-                       //printf("has transponder %d\n", Transponder());
-                       }
+                    for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                        if (ISTRANSPONDER(cChannel::Transponder(*frequency, Polarization), Transponder())) {
+                          nits[ThisNIT].hasTransponder = true;
+                          //printf("has transponder %d\n", Transponder());
+                          break;
+                          }
+                        }
                     break;
                     }
                  bool found = false;
                  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                      if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
-                        if (Setup.UpdateChannels >= 5)
+                        if (Setup.UpdateChannels >= 5) {
+                           if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Channel->Transponder())) {
+                              for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                                  if (ISTRANSPONDER(cChannel::Transponder(*frequency, Polarization), Channel->Transponder())) {
+                                     Frequency = *frequency;
+                                     break;
+                                     }
+                                  }
+                              }
                            Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate);
+                           }
                         found = true;
                         }
                      }
                  if (!found && Setup.UpdateChannels >= 5) {
-                    cChannel *Channel = new cChannel;
-                    Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
-                    if (Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate))
-                       EITScanner.AddTransponder(Channel);
-                    else
-                       delete Channel;
+                    for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                        cChannel *Channel = new cChannel;
+                        Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
+                        if (Channel->SetSatTransponderData(Source, *frequency, Polarization, SymbolRate, CodeRate))
+                          EITScanner.AddTransponder(Channel);
+                        else
+                          delete Channel;
+                        }
                     }
                  }
                  break;
@@ -135,6 +172,7 @@  void cNitFilter::Process(u_short Pid, u_
                  SI::CableDeliverySystemDescriptor *sd = (SI::CableDeliverySystemDescriptor *)d;
                  int Source = cSource::FromData(cSource::stCable);
                  int Frequency = BCD2INT(sd->getFrequency()) / 10;
+                 Frequencies.push_front(Frequency);
                  //XXX FEC_outer???
                  static int CodeRates[] = { FEC_NONE, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_NONE };
                  int CodeRate = CodeRates[sd->getFecInner()];
@@ -142,27 +180,41 @@  void cNitFilter::Process(u_short Pid, u_
                  int Modulation = Modulations[min(sd->getModulation(), 6)];
                  int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10;
                  if (ThisNIT >= 0) {
-                    if (ISTRANSPONDER(Frequency / 1000, Transponder())) {
-                       nits[ThisNIT].hasTransponder = true;
-                       //printf("has transponder %d\n", Transponder());
-                       }
+                    for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                        if (ISTRANSPONDER(*frequency / 1000, Transponder())) {
+                          nits[ThisNIT].hasTransponder = true;
+                          //printf("has transponder %d\n", Transponder());
+                          break;
+                          }
+                        }
                     break;
                     }
                  bool found = false;
                  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                      if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
-                        if (Setup.UpdateChannels >= 5)
+                        if (Setup.UpdateChannels >= 5) {
+                           if (!ISTRANSPONDER(Frequency / 1000, Channel->Transponder())) {
+                              for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                                  if (ISTRANSPONDER(*frequency / 1000, Channel->Transponder())) {
+                                     Frequency = *frequency;
+                                     break;
+                                     }
+                                  }
+                              }
                            Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate);
+                           }
                         found = true;
                         }
                      }
                  if (!found && Setup.UpdateChannels >= 5) {
-                    cChannel *Channel = new cChannel;
-                    Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
-                    if (Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate))
-                       EITScanner.AddTransponder(Channel);
-                    else
-                       delete Channel;
+                    for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                        cChannel *Channel = new cChannel;
+                        Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
+                        if (Channel->SetCableTransponderData(Source, *frequency, Modulation, SymbolRate, CodeRate))
+                          EITScanner.AddTransponder(Channel);
+                        else
+                          delete Channel;
+                        }
                     }
                  }
                  break;
@@ -170,6 +222,7 @@  void cNitFilter::Process(u_short Pid, u_
                  SI::TerrestrialDeliverySystemDescriptor *sd = (SI::TerrestrialDeliverySystemDescriptor *)d;
                  int Source = cSource::FromData(cSource::stTerr);
                  int Frequency = sd->getFrequency() * 10;
+                 Frequencies.push_front(Frequency);
                  static int Bandwidths[] = { BANDWIDTH_8_MHZ, BANDWIDTH_7_MHZ, BANDWIDTH_6_MHZ, BANDWIDTH_AUTO, BANDWIDTH_AUTO, BANDWIDTH_AUTO, BANDWIDTH_AUTO, BANDWIDTH_AUTO };
                  int Bandwidth = Bandwidths[sd->getBandwidth()];
                  static int Constellations[] = { QPSK, QAM_16, QAM_64, QAM_AUTO };
@@ -184,27 +237,41 @@  void cNitFilter::Process(u_short Pid, u_
                  static int TransmissionModes[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO };
                  int TransmissionMode = TransmissionModes[sd->getTransmissionMode()];
                  if (ThisNIT >= 0) {
-                    if (ISTRANSPONDER(Frequency / 1000000, Transponder())) {
-                       nits[ThisNIT].hasTransponder = true;
-                       //printf("has transponder %d\n", Transponder());
-                       }
+                    for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                        if (ISTRANSPONDER(*frequency / 1000000, Transponder())) {
+                            nits[ThisNIT].hasTransponder = true;
+                            //printf("has transponder %d\n", Transponder());
+                            break;
+                            }
+                        }
                     break;
                     }
                  bool found = false;
                  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                      if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
-                        if (Setup.UpdateChannels >= 5)
+                        if (Setup.UpdateChannels >= 5) {
+                           if (!ISTRANSPONDER(Frequency / 1000000, Channel->Transponder())) {
+                              for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                                  if (ISTRANSPONDER(*frequency / 1000000, Channel->Transponder())) {
+                                     Frequency = *frequency;
+                                     break;
+                                     }
+                                  }
+                              }
                            Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode);
+                           }
                         found = true;
                         }
                      }
                  if (!found && Setup.UpdateChannels >= 5) {
-                    cChannel *Channel = new cChannel;
-                    Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
-                    if (Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode))
-                       EITScanner.AddTransponder(Channel);
-                    else
-                       delete Channel;
+                    for (frequency = Frequencies.begin(); frequency != Frequencies.end(); frequency++) {
+                        cChannel *Channel = new cChannel;
+                        Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
+                        if (Channel->SetTerrTransponderData(Source, *frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode))
+                          EITScanner.AddTransponder(Channel);
+                        else
+                          delete Channel;
+                        }
                     }
                  }
                  break;