MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
eithelper.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // Std C headers
4 #include <time.h>
5 
6 // Std C++ headers
7 #include <algorithm>
8 using namespace std;
9 
10 // MythTV includes
11 #include "eithelper.h"
12 #include "eitfixup.h"
13 #include "eitcache.h"
14 #include "mythdb.h"
15 #include "atsctables.h"
16 #include "dvbtables.h"
17 #include "premieretables.h"
18 #include "dishdescriptors.h"
19 #include "premieredescriptors.h"
20 #include "channelutil.h" // for ChannelUtil
21 #include "mythdate.h"
22 #include "programdata.h"
23 #include "programinfo.h" // for subtitle types and audio and video properties
24 #include "scheduledrecording.h" // for ScheduledRecording
25 #include "compat.h" // for gmtime_r on windows.
26 
27 const uint EITHelper::kChunkSize = 20;
29 
30 static uint get_chan_id_from_db_atsc(uint sourceid,
31  uint atscmajor, uint atscminor);
32 static uint get_chan_id_from_db_dvb(uint sourceid, uint serviceid,
33  uint networkid, uint transportid);
34 static uint get_chan_id_from_db_dtv(uint sourceid,
35  uint programnumber, uint tunedchanid);
36 static void init_fixup(QMap<uint64_t,uint> &fix);
37 
38 #define LOC QString("EITHelper: ")
39 
41  eitfixup(new EITFixUp()),
42  gps_offset(-1 * GPS_LEAP_SECONDS),
43  sourceid(0), channelid(0),
44  maxStarttime(QDateTime()), seenEITother(false)
45 {
47 }
48 
50 {
51  QMutexLocker locker(&eitList_lock);
52  while (db_events.size())
53  delete db_events.dequeue();
54 
55  delete eitfixup;
56 }
57 
59 {
60  QMutexLocker locker(&eitList_lock);
61  return db_events.size();
62 }
63 
70 {
71  QMutexLocker locker(&eitList_lock);
72  uint insertCount = 0;
73 
74  if (db_events.empty())
75  return 0;
76 
78  for (uint i = 0; (i < kChunkSize) && (db_events.size() > 0); i++)
79  {
80  DBEventEIT *event = db_events.dequeue();
81  eitList_lock.unlock();
82 
83  eitfixup->Fix(*event);
84 
85  insertCount += event->UpdateDB(query, 1000);
86  maxStarttime = max (maxStarttime, event->starttime);
87 
88  delete event;
89  eitList_lock.lock();
90  }
91 
92  if (!insertCount)
93  return 0;
94 
95  if (incomplete_events.size() || unmatched_etts.size())
96  {
97  LOG(VB_EIT, LOG_INFO,
98  LOC + QString("Added %1 events -- complete(%2) "
99  "incomplete(%3) unmatched(%4)")
100  .arg(insertCount).arg(db_events.size())
101  .arg(incomplete_events.size()).arg(unmatched_etts.size()));
102  }
103  else
104  {
105  LOG(VB_EIT, LOG_INFO,
106  LOC + QString("Added %1 events").arg(insertCount));
107  }
108 
109  return insertCount;
110 }
111 
112 void EITHelper::SetFixup(uint atsc_major, uint atsc_minor, uint eitfixup)
113 {
114  QMutexLocker locker(&eitList_lock);
115  uint atsc_key = (atsc_major << 16) | atsc_minor;
116  fixup[atsc_key] = eitfixup;
117 }
118 
119 void EITHelper::SetLanguagePreferences(const QStringList &langPref)
120 {
121  QMutexLocker locker(&eitList_lock);
122 
123  uint priority = 1;
124  QStringList::const_iterator it;
125  for (it = langPref.begin(); it != langPref.end(); ++it)
126  {
127  if (!(*it).isEmpty())
128  {
129  uint language_key = iso639_str3_to_key(*it);
130  uint canonoical_key = iso639_key_to_canonical_key(language_key);
131  languagePreferences[canonoical_key] = priority++;
132  }
133  }
134 }
135 
137 {
138  QMutexLocker locker(&eitList_lock);
139  sourceid = _sourceid;
140 }
141 
143 {
144  QMutexLocker locker(&eitList_lock);
145  channelid = _channelid;
146 }
147 
148 void EITHelper::AddEIT(uint atsc_major, uint atsc_minor,
149  const EventInformationTable *eit)
150 {
151  uint atsc_key = (atsc_major << 16) | atsc_minor;
152  EventIDToATSCEvent &events = incomplete_events[atsc_key];
153  EventIDToETT &etts = unmatched_etts[atsc_key];
154 
155  for (uint i = 0; i < eit->EventCount(); i++)
156  {
157  ATSCEvent ev(eit->StartTimeRaw(i), eit->LengthInSeconds(i),
158  eit->ETMLocation(i),
160  eit->Descriptors(i), eit->DescriptorsLength(i));
161 
162  EventIDToETT::iterator it = etts.find(eit->EventID(i));
163 
164  if (it != etts.end())
165  {
166  CompleteEvent(atsc_major, atsc_minor, ev, *it);
167  etts.erase(it);
168  }
169  else if (!ev.etm)
170  {
171  CompleteEvent(atsc_major, atsc_minor, ev, QString::null);
172  }
173  else
174  {
175  unsigned char *tmp = new unsigned char[ev.desc_length];
176  memcpy(tmp, eit->Descriptors(i), ev.desc_length);
177  ev.desc = tmp;
178  events[eit->EventID(i)] = ev;
179  }
180  }
181 }
182 
183 void EITHelper::AddETT(uint atsc_major, uint atsc_minor,
184  const ExtendedTextTable *ett)
185 {
186  uint atsc_key = (atsc_major << 16) | atsc_minor;
187  // Try to complete an Event
188  ATSCSRCToEvents::iterator eits_it = incomplete_events.find(atsc_key);
189  if (eits_it != incomplete_events.end())
190  {
191  EventIDToATSCEvent::iterator it = (*eits_it).find(ett->EventID());
192  if (it != (*eits_it).end())
193  {
195  atsc_major, atsc_minor, *it,
197 
198  if ((*it).desc)
199  delete [] (*it).desc;
200 
201  (*eits_it).erase(it);
202 
203  return;
204  }
205  }
206 
207  // Couldn't find matching EIT. If not yet in unmatched ETT map, insert it.
208  EventIDToETT &elist = unmatched_etts[atsc_key];
209  if (elist.find(ett->EventID()) == elist.end())
210  {
211  elist[ett->EventID()] = ett->ExtendedTextMessage()
213  }
214 }
215 
217  QMap<uint,uint> languagePreferences,
218  QString &title, QString &subtitle,
219  QString &description)
220 {
221  const unsigned char *bestShortEvent =
223  list, DescriptorID::short_event, languagePreferences);
224 
225  // from EN 300 468, Appendix A.2 - Selection of character table
226  unsigned char enc_1[3] = { 0x10, 0x00, 0x01 };
227  unsigned char enc_9[3] = { 0x10, 0x00, 0x09 }; // could use { 0x05 } instead
228  unsigned char enc_15[3] = { 0x10, 0x00, 0x0f }; // could use { 0x0B } instead
229  int enc_len = 0;
230  const unsigned char *enc = NULL;
231 
232  // Is this BellExpressVU EIT (Canada) ?
233  // Use an encoding override of ISO 8859-1 (Latin1)
235  {
236  enc = enc_1;
237  enc_len = sizeof(enc_1);
238  }
239 
240  // Is this broken DVB provider in Western Europe?
241  // Use an encoding override of ISO 8859-9 (Latin5)
243  {
244  enc = enc_9;
245  enc_len = sizeof(enc_9);
246  }
247 
248  // Is this broken DVB provider in Western Europe?
249  // Use an encoding override of ISO 8859-15 (Latin6)
251  {
252  enc = enc_15;
253  enc_len = sizeof(enc_15);
254  }
255 
256  if (bestShortEvent)
257  {
258  ShortEventDescriptor sed(bestShortEvent);
259  if (enc)
260  {
261  title = sed.EventName(enc, enc_len);
262  subtitle = sed.Text(enc, enc_len);
263  }
264  else
265  {
266  title = sed.EventName();
267  subtitle = sed.Text();
268  }
269  }
270 
271  vector<const unsigned char*> bestExtendedEvents =
273  list, DescriptorID::extended_event, languagePreferences);
274 
275  description = "";
276  for (uint j = 0; j < bestExtendedEvents.size(); j++)
277  {
278  if (!bestExtendedEvents[j])
279  {
280  description = "";
281  break;
282  }
283 
284  ExtendedEventDescriptor eed(bestExtendedEvents[j]);
285  if (enc)
286  description += eed.Text(enc, enc_len);
287  else
288  description += eed.Text();
289  }
290 }
291 
293  unsigned char &subtitle_type,
294  unsigned char &audio_properties,
295  unsigned char &video_properties)
296 {
297  desc_list_t components =
299  for (uint j = 0; j < components.size(); j++)
300  {
301  ComponentDescriptor component(components[j]);
302  video_properties |= component.VideoProperties();
303  audio_properties |= component.AudioProperties();
304  subtitle_type |= component.SubtitleType();
305  }
306 }
307 
309 {
310  uint chanid = 0;
311  if ((eit->TableID() == TableID::PF_EIT) ||
312  ((eit->TableID() >= TableID::SC_EITbeg) && (eit->TableID() <= TableID::SC_EITend)))
313  {
314  // EITa(ctive)
315  chanid = GetChanID(eit->ServiceID());
316  }
317  else
318  {
319  // EITo(ther)
320  chanid = GetChanID(eit->ServiceID(), eit->OriginalNetworkID(), eit->TSID());
321  // do not reschedule if its only present+following
322  if (eit->TableID() != TableID::PF_EITo)
323  {
324  seenEITother = true;
325  }
326  }
327  if (!chanid)
328  return;
329 
330  uint descCompression = (eit->TableID() > 0x80) ? 2 : 1;
331  uint fix = fixup.value(eit->OriginalNetworkID() << 16);
332  fix |= fixup.value((((uint64_t)eit->TSID()) << 32) |
333  (eit->OriginalNetworkID() << 16));
334  fix |= fixup.value((eit->OriginalNetworkID() << 16) | eit->ServiceID());
335  fix |= fixup.value((((uint64_t)eit->TSID()) << 32) |
336  (uint64_t)(eit->OriginalNetworkID() << 16) |
337  (uint64_t)eit->ServiceID());
339 
340  uint tableid = eit->TableID();
341  uint version = eit->Version();
342  for (uint i = 0; i < eit->EventCount(); i++)
343  {
344  // Skip event if we have already processed it before...
345  if (!eitcache->IsNewEIT(chanid, tableid, version, eit->EventID(i),
346  eit->EndTimeUnixUTC(i)))
347  {
348  continue;
349  }
350 
351  QString title = QString("");
352  QString subtitle = QString("");
353  QString description = QString("");
354  QString category = QString("");
356  unsigned char subtitle_type=0, audio_props=0, video_props=0;
357 
358  // Parse descriptors
360  eit->Descriptors(i), eit->DescriptorsLength(i));
361 
362  const unsigned char *dish_event_name = NULL;
363  if (EITFixUp::kFixDish & fix)
364  {
365  dish_event_name = MPEGDescriptor::Find(
367  }
368 
369  if (dish_event_name)
370  {
371  DishEventNameDescriptor dend(dish_event_name);
372  if (dend.HasName())
373  title = dend.Name(descCompression);
374 
375  const unsigned char *dish_event_description =
378  if (dish_event_description)
379  {
380  DishEventDescriptionDescriptor dedd(dish_event_description);
381  if (dedd.HasDescription())
382  description = dedd.Description(descCompression);
383  }
384  }
385  else
386  {
388  title, subtitle, description);
389  }
390 
391  parse_dvb_component_descriptors(list, subtitle_type, audio_props,
392  video_props);
393 
394  QString programId = QString("");
395  QString seriesId = QString("");
396  QString rating = QString("");
397  QString rating_system = QString("");
398  QString advisory = QString("");
399  float stars = 0.0;
400  QDate originalairdate;
401 
402  if (EITFixUp::kFixDish & fix)
403  {
404  const unsigned char *mpaa_data = MPEGDescriptor::Find(
406  if (mpaa_data)
407  {
408  DishEventMPAADescriptor mpaa(mpaa_data);
409  stars = mpaa.stars();
410 
411  if (stars) // Only movies for now
412  {
413  rating = mpaa.rating();
414  rating_system = "MPAA";
415  advisory = mpaa.advisory();
416  }
417  }
418 
419  if (!stars) // Not MPAA rated, check VCHIP
420  {
421  const unsigned char *vchip_data = MPEGDescriptor::Find(
423  if (vchip_data)
424  {
425  DishEventVCHIPDescriptor vchip(vchip_data);
426  rating = vchip.rating();
427  rating_system = "VCHIP";
428  advisory = vchip.advisory();
429  }
430  }
431 
432  if (!advisory.isEmpty() && !rating.isEmpty())
433  rating += ", " + advisory;
434  else if (!advisory.isEmpty())
435  {
436  rating = advisory;
437  rating_system = "advisory";
438  }
439 
440  const unsigned char *tags_data = MPEGDescriptor::Find(
442  if (tags_data)
443  {
444  DishEventTagsDescriptor tags(tags_data);
445  seriesId = tags.seriesid();
446  programId = tags.programid();
447  originalairdate = tags.originalairdate(); // future use
448 
449  if (programId.startsWith("MV") || programId.startsWith("SP"))
450  seriesId = "";
451  }
452 
453  const unsigned char *properties_data = MPEGDescriptor::Find(
455  if (properties_data)
456  {
457  DishEventPropertiesDescriptor properties(properties_data);
458  subtitle_type |= properties.SubtitleProperties(descCompression);
459  audio_props |= properties.AudioProperties(descCompression);
460  }
461  }
462 
463  const unsigned char *content_data =
465  if (content_data)
466  {
467  if ((EITFixUp::kFixDish & fix) || (EITFixUp::kFixBell & fix))
468  {
469  DishContentDescriptor content(content_data);
470  switch (content.GetTheme())
471  {
472  case kThemeMovie :
473  category_type = ProgramInfo::kCategoryMovie;
474  break;
475  case kThemeSeries :
476  category_type = ProgramInfo::kCategorySeries;
477  break;
478  case kThemeSports :
479  category_type = ProgramInfo::kCategorySports;
480  break;
481  default :
482  category_type = ProgramInfo::kCategoryNone;
483  }
484  if (EITFixUp::kFixDish & fix)
485  category = content.GetCategory();
486  }
487  else if (EITFixUp::kFixAUDescription & fix)//AU Freeview assigned genres
488  {
489  ContentDescriptor content(content_data);
490  switch (content.Nibble1(0))
491  {
492  case 0x01:
493  category = "Movie";
494  break;
495  case 0x02:
496  category = "News";
497  break;
498  case 0x03:
499  category = "Entertainment";
500  break;
501  case 0x04:
502  category = "Sport";
503  break;
504  case 0x05:
505  category = "Children";
506  break;
507  case 0x06:
508  category = "Music";
509  break;
510  case 0x07:
511  category = "Arts/Culture";
512  break;
513  case 0x08:
514  category = "Current Affairs";
515  break;
516  case 0x09:
517  category = "Education";
518  break;
519  case 0x0A:
520  category = "Infotainment";
521  break;
522  case 0x0B:
523  category = "Special";
524  break;
525  case 0x0C:
526  category = "Comedy";
527  break;
528  case 0x0D:
529  category = "Drama";
530  break;
531  case 0x0E:
532  category = "Documentary";
533  break;
534  default:
535  category = "";
536  break;
537  }
538  category_type = content.GetMythCategory(0);
539  }
540  else
541  {
542  ContentDescriptor content(content_data);
543  category = content.GetDescription(0);
544  category_type = content.GetMythCategory(0);
545  }
546  }
547 
548  desc_list_t contentIds =
550  for (uint j = 0; j < contentIds.size(); j++)
551  {
552  DVBContentIdentifierDescriptor desc(contentIds[j]);
553  if (desc.ContentEncoding() == 0)
554  {
555  // The CRID is a URI. It could contain UTF8 sequences encoded
556  // as %XX but there's no advantage in decoding them.
557  // The BBC currently uses private types 0x31 and 0x32.
558  if (desc.ContentType() == 0x01 || desc.ContentType() == 0x31)
559  programId = desc.ContentId();
560  else if (desc.ContentType() == 0x02 || desc.ContentType() == 0x32)
561  {
562  seriesId = desc.ContentId();
563  category_type = ProgramInfo::kCategorySeries;
564  }
565  }
566  }
567 
568  QDateTime starttime = eit->StartTimeUTC(i);
569  // fix starttime only if the duration is a multiple of a minute
570  if (!(eit->DurationInSeconds(i) % 60))
571  EITFixUp::TimeFix(starttime);
572  QDateTime endtime = starttime.addSecs(eit->DurationInSeconds(i));
573 
574  DBEventEIT *event = new DBEventEIT(
575  chanid,
576  title, subtitle, description,
577  category, category_type,
578  starttime, endtime, fix,
579  subtitle_type,
580  audio_props,
581  video_props, stars,
582  seriesId, programId);
583 
584  db_events.enqueue(event);
585  }
586 }
587 
588 // This function gets special EIT data from the German provider Premiere
589 // for the option channels Premiere Sport and Premiere Direkt
591 {
592  // set fixup for Premiere
593  uint fix = fixup.value(133 << 16);
595 
596  QString title = QString("");
597  QString subtitle = QString("");
598  QString description = QString("");
599  QString category = QString("");
601  unsigned char subtitle_type=0, audio_props=0, video_props=0;
602 
603  // Parse descriptors
605  cit->Descriptors(), cit->DescriptorsLength());
606 
608  title, subtitle, description);
609 
610  parse_dvb_component_descriptors(list, subtitle_type, audio_props,
611  video_props);
612 
613  const unsigned char *content_data =
615  if (content_data)
616  {
617  ContentDescriptor content(content_data);
618  // fix events without real content data
619  if (content.Nibble(0)==0x00)
620  {
621  if(content.UserNibble(0)==0x1)
622  {
623  category_type = ProgramInfo::kCategoryMovie;
624  }
625  else if(content.UserNibble(0)==0x0)
626  {
627  category_type = ProgramInfo::kCategorySports;
628  category = QObject::tr("Sports");
629  }
630  }
631  else
632  {
633  category_type = content.GetMythCategory(0);
634  category = content.GetDescription(0);
635  }
636  }
637 
638  uint tableid = cit->TableID();
639  uint version = cit->Version();
640  uint contentid = cit->ContentID();
641  // fake endtime
642  uint endtime = MythDate::current().addDays(1).toTime_t();
643 
644  // Find Transmissions
645  desc_list_t transmissions =
648  for(uint j=0; j< transmissions.size(); j++)
649  {
650  PremiereContentTransmissionDescriptor transmission(transmissions[j]);
651  uint networkid = transmission.OriginalNetworkID();
652  uint tsid = transmission.TSID();
653  uint serviceid = transmission.ServiceID();
654 
655  uint chanid = GetChanID(serviceid, networkid, tsid);
656 
657  if (!chanid)
658  {
659  LOG(VB_EIT, LOG_INFO, LOC +
660  QString("Premiere EIT for NIT %1, TID %2, SID %3, "
661  "count %4, title: %5. Channel not found!")
662  .arg(networkid).arg(tsid).arg(serviceid)
663  .arg(transmission.TransmissionCount()).arg(title));
664  continue;
665  }
666 
667  // Skip event if we have already processed it before...
668  if (!eitcache->IsNewEIT(chanid, tableid, version, contentid, endtime))
669  {
670  continue;
671  }
672 
673  for (uint k=0; k<transmission.TransmissionCount(); ++k)
674  {
675  QDateTime starttime = transmission.StartTimeUTC(k);
676  // fix starttime only if the duration is a multiple of a minute
677  if (!(cit->DurationInSeconds() % 60))
678  EITFixUp::TimeFix(starttime);
679  QDateTime endtime = starttime.addSecs(cit->DurationInSeconds());
680 
681  DBEventEIT *event = new DBEventEIT(
682  chanid,
683  title, subtitle, description,
684  category, category_type,
685  starttime, endtime, fix,
686  subtitle_type,
687  audio_props,
688  video_props, 0.0,
689  "", "");
690 
691  db_events.enqueue(event);
692  }
693  }
694 }
695 
696 
698 {
699  eitcache->PruneOldEntries(timestamp);
700 }
701 
703 {
704  eitcache->WriteToDB();
705 }
706 
708 // private methods and functions below this line //
710 
711 void EITHelper::CompleteEvent(uint atsc_major, uint atsc_minor,
712  const ATSCEvent &event,
713  const QString &ett)
714 {
715  uint chanid = GetChanID(atsc_major, atsc_minor);
716  if (!chanid)
717  return;
718 
719  QDateTime starttime = MythDate::fromTime_t(
720  event.start_time + GPS_EPOCH + gps_offset);
721 
722  // fix starttime only if the duration is a multiple of a minute
723  if (!(event.length % 60))
724  EITFixUp::TimeFix(starttime);
725  QDateTime endtime = starttime.addSecs(event.length);
726 
727  desc_list_t list = MPEGDescriptor::Parse(event.desc, event.desc_length);
728  unsigned char subtitle_type =
731  unsigned char audio_properties = AUD_UNKNOWN;
732  unsigned char video_properties = VID_UNKNOWN;
733 
734  uint atsc_key = (atsc_major << 16) | atsc_minor;
735 
736  QMutexLocker locker(&eitList_lock);
737  QString title = event.title;
738  QString subtitle = ett;
739  db_events.enqueue(new DBEventEIT(chanid, title, subtitle,
740  starttime, endtime,
741  fixup.value(atsc_key), subtitle_type,
742  audio_properties, video_properties));
743 }
744 
745 uint EITHelper::GetChanID(uint atsc_major, uint atsc_minor)
746 {
747  uint64_t key;
748  key = ((uint64_t) sourceid);
749  key |= ((uint64_t) atsc_minor) << 16;
750  key |= ((uint64_t) atsc_major) << 32;
751 
752  ServiceToChanID::const_iterator it = srv_to_chanid.find(key);
753  if (it != srv_to_chanid.end())
754  return max(*it, 0u);
755 
756  uint chanid = get_chan_id_from_db_atsc(sourceid, atsc_major, atsc_minor);
757  srv_to_chanid[key] = chanid;
758 
759  return chanid;
760 }
761 
762 uint EITHelper::GetChanID(uint serviceid, uint networkid, uint tsid)
763 {
764  uint64_t key;
765  key = ((uint64_t) sourceid);
766  key |= ((uint64_t) serviceid) << 16;
767  key |= ((uint64_t) networkid) << 32;
768  key |= ((uint64_t) tsid) << 48;
769 
770  ServiceToChanID::const_iterator it = srv_to_chanid.find(key);
771  if (it != srv_to_chanid.end())
772  return max(*it, 0u);
773 
774  uint chanid = get_chan_id_from_db_dvb(sourceid, serviceid, networkid, tsid);
775  srv_to_chanid[key] = chanid;
776 
777  return chanid;
778 }
779 
781 {
782  uint64_t key;
783  key = ((uint64_t) sourceid);
784  key |= ((uint64_t) program_number) << 16;
785  key |= ((uint64_t) channelid) << 32;
786 
787  ServiceToChanID::const_iterator it = srv_to_chanid.find(key);
788  if (it != srv_to_chanid.end())
789  return max(*it, 0u);
790 
791  uint chanid = get_chan_id_from_db_dtv(sourceid, program_number, channelid);
792  srv_to_chanid[key] = chanid;
793 
794  return chanid;
795 }
796 
798  uint atsc_major, uint atsc_minor)
799 {
800  MSqlQuery query(MSqlQuery::InitCon());
801  query.prepare(
802  "SELECT chanid, useonairguide "
803  "FROM channel "
804  "WHERE atsc_major_chan = :MAJORCHAN AND "
805  " atsc_minor_chan = :MINORCHAN AND "
806  " sourceid = :SOURCEID");
807  query.bindValue(":MAJORCHAN", atsc_major);
808  query.bindValue(":MINORCHAN", atsc_minor);
809  query.bindValue(":SOURCEID", sourceid);
810 
811  if (!query.exec() || !query.isActive())
812  MythDB::DBError("Looking up chanid 1", query);
813  else if (query.next())
814  {
815  bool useOnAirGuide = query.value(1).toBool();
816  return (useOnAirGuide) ? query.value(0).toUInt() : 0;
817  }
818 
819  return 0;
820 }
821 
822 // Figure out the chanid for this channel
823 static uint get_chan_id_from_db_dvb(uint sourceid, uint serviceid,
824  uint networkid, uint transportid)
825 {
826  uint chanid = 0;
827  bool useOnAirGuide = false;
828  MSqlQuery query(MSqlQuery::InitCon());
829 
830  // DVB Link to chanid
831  QString qstr =
832  "SELECT chanid, useonairguide, channel.sourceid "
833  "FROM channel, dtv_multiplex "
834  "WHERE serviceid = :SERVICEID AND "
835  " networkid = :NETWORKID AND "
836  " transportid = :TRANSPORTID AND "
837  " channel.mplexid = dtv_multiplex.mplexid";
838 
839  query.prepare(qstr);
840  query.bindValue(":SERVICEID", serviceid);
841  query.bindValue(":NETWORKID", networkid);
842  query.bindValue(":TRANSPORTID", transportid);
843 
844  if (!query.exec() || !query.isActive())
845  MythDB::DBError("Looking up chanID", query);
846 
847  if (query.size() == 0) {
848  // Attempt fuzzy matching, by skipping the tsid
849  // DVB Link to chanid
850  QString qstr =
851  "SELECT chanid, useonairguide, channel.sourceid "
852  "FROM channel, dtv_multiplex "
853  "WHERE serviceid = :SERVICEID AND "
854  " networkid = :NETWORKID AND "
855  " channel.mplexid = dtv_multiplex.mplexid";
856 
857  query.prepare(qstr);
858  query.bindValue(":SERVICEID", serviceid);
859  query.bindValue(":NETWORKID", networkid);
860  if (!query.exec() || !query.isActive())
861  MythDB::DBError("Looking up chanID in fuzzy mode", query);
862  }
863 
864  while (query.next())
865  {
866  // Check to see if we are interested in this channel
867  chanid = query.value(0).toUInt();
868  useOnAirGuide = query.value(1).toBool();
869  if (sourceid == query.value(2).toUInt())
870  return useOnAirGuide ? chanid : 0;
871  }
872 
873  if (query.size() > 1)
874  {
875  LOG(VB_EIT, LOG_INFO,
876  LOC + QString("found %1 channels for networdid %2, "
877  "transportid %3, serviceid %4 but none "
878  "for current sourceid %5.")
879  .arg(query.size()).arg(networkid).arg(transportid)
880  .arg(serviceid).arg(sourceid));
881  }
882 
883  return useOnAirGuide ? chanid : 0;
884 }
885 
886 /* Figure out the chanid for this channel from the sourceid,
887  * program_number/service_id and the chanid of the channel we are tuned to
888  *
889  * TODO for SPTS (e.g. HLS / IPTV) it would be useful to match without an entry
890  * in dtv_multiplex
891  */
892 static uint get_chan_id_from_db_dtv(uint sourceid, uint serviceid,
893  uint tunedchanid)
894 {
895  uint chanid = 0;
896  bool useOnAirGuide = false;
897  MSqlQuery query(MSqlQuery::InitCon());
898 
899  // DVB Link to chanid
900  QString qstr =
901  "SELECT c1.chanid, c1.useonairguide, c1.sourceid "
902  "FROM channel c1, dtv_multiplex m, channel c2 "
903  "WHERE c1.serviceid = :SERVICEID AND "
904  " c1.mplexid = m.mplexid AND "
905  " m.mplexid = c2.mplexid AND "
906  " c2.chanid = :CHANID";
907 
908  query.prepare(qstr);
909  query.bindValue(":SERVICEID", serviceid);
910  query.bindValue(":CHANID", tunedchanid);
911 
912  if (!query.exec() || !query.isActive())
913  MythDB::DBError("Looking up chanID", query);
914 
915  while (query.next())
916  {
917  // Check to see if we are interested in this channel
918  chanid = query.value(0).toUInt();
919  useOnAirGuide = query.value(1).toBool();
920  if (sourceid == query.value(2).toUInt())
921  return useOnAirGuide ? chanid : 0;
922  }
923 
924  if (query.size() > 1)
925  {
926  LOG(VB_EIT, LOG_INFO,
927  LOC + QString("found %1 channels for multiplex of chanid %2, "
928  "serviceid %3 but none "
929  "for current sourceid %4.")
930  .arg(query.size()).arg(tunedchanid)
931  .arg(serviceid).arg(sourceid));
932  }
933 
934  return useOnAirGuide ? chanid : 0;
935 }
936 
937 static void init_fixup(QMap<uint64_t,uint> &fix)
938 {
940  // Fixups to make EIT provided listings more useful
941  // transport_id<<32 | netword_id<<16 | service_id
942 
943  // Bell Express VU Canada
944  fix[ 256U << 16] = EITFixUp::kFixBell;
945  fix[ 257U << 16] = EITFixUp::kFixBell;
946  fix[ 4100U << 16] = EITFixUp::kFixBell;
947  fix[ 4101U << 16] = EITFixUp::kFixBell;
948  fix[ 4102U << 16] = EITFixUp::kFixBell;
949  fix[ 4103U << 16] = EITFixUp::kFixBell;
950  fix[ 4104U << 16] = EITFixUp::kFixBell;
951  fix[ 4105U << 16] = EITFixUp::kFixBell;
952  fix[ 4106U << 16] = EITFixUp::kFixBell;
953  fix[ 4107U << 16] = EITFixUp::kFixBell;
954  fix[ 4097U << 16] = EITFixUp::kFixBell;
955  fix[ 4098U << 16] = EITFixUp::kFixBell;
956 
957  // United Kingdom
958  fix[ 9018U << 16] = EITFixUp::kFixUK;
959  // UK Freesat
960  fix[ 2013LL << 32 | 2U << 16] = EITFixUp::kFixUK;
961  fix[ 2017LL << 32 | 2U << 16] = EITFixUp::kFixUK;
962  fix[ 2018LL << 32 | 2U << 16] = EITFixUp::kFixUK;
963  fix[ 2026LL << 32 | 2U << 16] = EITFixUp::kFixUK;
964  fix[ 2041LL << 32 | 2U << 16] = EITFixUp::kFixUK;
965  fix[ 2042LL << 32 | 2U << 16] = EITFixUp::kFixUK;
966  fix[ 2043LL << 32 | 2U << 16] = EITFixUp::kFixUK;
967  fix[ 2044LL << 32 | 2U << 16] = EITFixUp::kFixUK;
968  fix[ 2045LL << 32 | 2U << 16] = EITFixUp::kFixUK;
969  fix[ 2046LL << 32 | 2U << 16] = EITFixUp::kFixUK;
970  fix[ 2047LL << 32 | 2U << 16] = EITFixUp::kFixUK;
971  fix[ 2048LL << 32 | 2U << 16] = EITFixUp::kFixUK;
972  fix[ 2049LL << 32 | 2U << 16] = EITFixUp::kFixUK;
973  fix[ 2050LL << 32 | 2U << 16] = EITFixUp::kFixUK;
974  fix[ 2051LL << 32 | 2U << 16] = EITFixUp::kFixUK;
975  fix[ 2053LL << 32 | 2U << 16] = EITFixUp::kFixUK;
976  fix[ 2054LL << 32 | 2U << 16] = EITFixUp::kFixUK;
977  fix[ 2056LL << 32 | 2U << 16] = EITFixUp::kFixUK;
978  fix[ 2057LL << 32 | 2U << 16] = EITFixUp::kFixUK;
979  fix[ 2063LL << 32 | 2U << 16] = EITFixUp::kFixUK;
980  fix[ 2068LL << 32 | 2U << 16] = EITFixUp::kFixUK;
981  fix[ 2301LL << 32 | 2U << 16] = EITFixUp::kFixUK;
982  fix[ 2302LL << 32 | 2U << 16] = EITFixUp::kFixUK;
983  fix[ 2303LL << 32 | 2U << 16] = EITFixUp::kFixUK;
984  fix[ 2304LL << 32 | 2U << 16] = EITFixUp::kFixUK;
985  fix[ 2305LL << 32 | 2U << 16] = EITFixUp::kFixUK;
986  fix[ 2306LL << 32 | 2U << 16] = EITFixUp::kFixUK;
987  fix[ 2311LL << 32 | 2U << 16] = EITFixUp::kFixUK;
988  fix[ 2312LL << 32 | 2U << 16] = EITFixUp::kFixUK;
989  fix[ 2313LL << 32 | 2U << 16] = EITFixUp::kFixUK;
990  fix[ 2314LL << 32 | 2U << 16] = EITFixUp::kFixUK;
991  fix[ 2401LL << 32 | 2U << 16] = EITFixUp::kFixUK;
992  fix[ 2412LL << 32 | 2U << 16] = EITFixUp::kFixUK;
993  fix[ 2413LL << 32 | 2U << 16] = EITFixUp::kFixUK;
994  fix[ 2602LL << 32 | 2U << 16] = EITFixUp::kFixUK;
995  fix[ 2612LL << 32 | 2U << 16] = EITFixUp::kFixUK;
996 
997  // ComHem Sweden
998  fix[40999U << 16 ] = EITFixUp::kFixComHem;
999  fix[40999U << 16 | 1070] = EITFixUp::kFixSubtitle;
1000  fix[40999U << 16 | 1308] = EITFixUp::kFixSubtitle;
1001  fix[40999U << 16 | 1041] = EITFixUp::kFixSubtitle;
1002  fix[40999U << 16 | 1306] = EITFixUp::kFixSubtitle;
1003  fix[40999U << 16 | 1307] = EITFixUp::kFixSubtitle;
1004  fix[40999U << 16 | 1030] = EITFixUp::kFixSubtitle;
1005  fix[40999U << 16 | 1016] = EITFixUp::kFixSubtitle;
1006  fix[40999U << 16 | 1131] = EITFixUp::kFixSubtitle;
1007  fix[40999U << 16 | 1068] = EITFixUp::kFixSubtitle;
1008  fix[40999U << 16 | 1069] = EITFixUp::kFixSubtitle;
1009 
1010  // Australia
1011  fix[ 4096U << 16] = EITFixUp::kFixAUStar;
1012  fix[ 4096U << 16] = EITFixUp::kFixAUStar;
1013  fix[ 4112U << 16] = EITFixUp::kFixAUDescription | EITFixUp::kFixAUFreeview; // ABC Brisbane
1014  fix[ 4114U << 16] = EITFixUp::kFixAUDescription | EITFixUp::kFixAUFreeview | EITFixUp::kFixAUNine;; // Nine Brisbane
1015  fix[ 4115U << 16] = EITFixUp::kFixAUDescription | EITFixUp::kFixAUSeven; //Seven
1016  fix[ 4116U << 16] = EITFixUp::kFixAUDescription; //Ten
1017  fix[ 12801U << 16] = EITFixUp::kFixAUFreeview | EITFixUp::kFixAUDescription; //ABC
1018  fix[ 12802U << 16] = EITFixUp::kFixAUDescription; //SBS
1020  fix[ 12842U << 16] = EITFixUp::kFixAUDescription; // 31 Brisbane
1021  fix[ 12862U << 16] = EITFixUp::kFixAUDescription; //WestTV
1022 
1023  // MultiChoice Africa
1024  fix[ 6144U << 16] = EITFixUp::kFixMCA;
1025 
1026  // RTL Subtitle parsing
1027  fix[ 1089LL << 32 | 1 << 16] = // DVB-S
1028  fix[ 773LL << 32 | 8468U << 16] = // DVB-T Berlin/Brandenburg
1029  fix[ 2819LL << 32 | 8468U << 16] = // DVB-T Niedersachsen + Bremen
1030  fix[ 8706LL << 32 | 8468U << 16] = // DVB-T NRW
1031  fix[ 12801LL << 32 | 8468U << 16] = // DVB-T Bayern
1033 
1034  // Premiere EIT processing
1035  fix[ 1LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1036  fix[ 2LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1037  fix[ 3LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1038  fix[ 4LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1039  fix[ 5LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1040  fix[ 6LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1041  fix[ 17LL << 32 | 133 << 16] = EITFixUp::kFixPremiere;
1042  // Mark Premiere HD and Discovery HD as HDTV
1043  fix[ 6LL << 32 | 133 << 16 | 129] = EITFixUp::kFixHDTV;
1044  fix[ 6LL << 32 | 133 << 16 | 130] = EITFixUp::kFixHDTV;
1045 
1046  // Netherlands DVB-C
1047  fix[ 1000U << 16] = EITFixUp::kFixNL;
1048  // Canal Digitaal DVB-S 19.2 Dutch/Belgian ONID 53 covers all CanalDigitaal TiD
1049  fix[ 53U << 16] = EITFixUp::kFixNL;
1050  // Canal Digitaal DVB-S 23.5 Dutch/Belgian
1051  fix[ 3202LL << 32 | 3U << 16] = EITFixUp::kFixNL;
1052  fix[ 3208LL << 32 | 3U << 16] = EITFixUp::kFixNL;
1053  fix[ 3211LL << 32 | 3U << 16] = EITFixUp::kFixNL;
1054  fix[ 3222LL << 32 | 3U << 16] = EITFixUp::kFixNL;
1055  fix[ 3225LL << 32 | 3U << 16] = EITFixUp::kFixNL;
1056 
1057  // Finland
1058  fix[ 8438U << 16] = // DVB-T Espoo
1059  fix[ 42249U << 16] = // DVB-C Welho
1060  fix[ 15U << 16] = // DVB-C Welho
1062 
1063  // DVB-C YouSee (Denmark)
1064  fix[65024U << 16] = EITFixUp::kFixDK;
1065 
1066  // DVB-S(2) Thor 0.8W Norwegian
1067  fix[70U << 16] = EITFixUp::kFixNO;
1068 
1069  // DVB-T NTV/NRK (Norway)
1070  fix[910LL << 32 | 8770U << 16 | 0x006f] = EITFixUp::kFixNRK_DVBT; //NRK Folkemusikk
1071  fix[910LL << 32 | 8770U << 16 | 0x0070] = EITFixUp::kFixNRK_DVBT; //NRK Stortinget
1072  fix[910LL << 32 | 8770U << 16 | 0x0071] = EITFixUp::kFixNRK_DVBT; //NRK Super
1073  fix[910LL << 32 | 8770U << 16 | 0x0072] = EITFixUp::kFixNRK_DVBT; //NRK Sport
1074  fix[910LL << 32 | 8770U << 16 | 0x0073] = EITFixUp::kFixNRK_DVBT; //NRK Gull
1075  fix[910LL << 32 | 8770U << 16 | 0x0074] = EITFixUp::kFixNRK_DVBT; //NRK Jazz
1076  fix[910LL << 32 | 8770U << 16 | 0x0067] = EITFixUp::kFixNRK_DVBT; //NRK Super / NRK3
1077  fix[910LL << 32 | 8770U << 16 | 0x0068] = EITFixUp::kFixNRK_DVBT; //NRK Tegnspr�
1078  fix[910LL << 32 | 8770U << 16 | 0x0069] = EITFixUp::kFixNRK_DVBT; //NRK P2
1079  fix[910LL << 32 | 8770U << 16 | 0x006a] = EITFixUp::kFixNRK_DVBT; //NRK P3
1080  fix[910LL << 32 | 8770U << 16 | 0x006b] = EITFixUp::kFixNRK_DVBT; //NRK Alltid Nyheter
1081  fix[910LL << 32 | 8770U << 16 | 0x006c] = EITFixUp::kFixNRK_DVBT; //NRK mP3
1082  fix[910LL << 32 | 8770U << 16 | 0x006d] = EITFixUp::kFixNRK_DVBT; //NRK Klassisk
1083  fix[910LL << 32 | 8770U << 16 | 0x006e] = EITFixUp::kFixNRK_DVBT; //NRK S�i Radio
1084  fix[910LL << 32 | 8770U << 16 | 0x0066] = EITFixUp::kFixNRK_DVBT; //NRK2
1085  fix[910LL << 32 | 8770U << 16 | 0x03f0] = EITFixUp::kFixNRK_DVBT; //NRK1 M�e og Romsdal
1086  fix[910LL << 32 | 8770U << 16 | 0x0455] = EITFixUp::kFixNRK_DVBT; //NRK P1 Tr�delag
1087  fix[910LL << 32 | 8770U << 16 | 0x03f1] = EITFixUp::kFixNRK_DVBT; //NRK1 Midtnytt
1088 
1090  // Special Early fixups for providers that break DVB EIT spec.
1091  // transport_id<<32 | network_id<<16 | service_id
1092 
1093  // Bell Express VU Canada
1094  fix[ 256U << 16] |= EITFixUp::kEFixForceISO8859_1;
1095  fix[ 257U << 16] |= EITFixUp::kEFixForceISO8859_1;
1096  fix[4100U << 16] |= EITFixUp::kEFixForceISO8859_1;
1097  fix[4101U << 16] |= EITFixUp::kEFixForceISO8859_1;
1098  fix[4102U << 16] |= EITFixUp::kEFixForceISO8859_1;
1099  fix[4103U << 16] |= EITFixUp::kEFixForceISO8859_1;
1100  fix[4104U << 16] |= EITFixUp::kEFixForceISO8859_1;
1101  fix[4105U << 16] |= EITFixUp::kEFixForceISO8859_1;
1102  fix[4106U << 16] |= EITFixUp::kEFixForceISO8859_1;
1103  fix[4107U << 16] |= EITFixUp::kEFixForceISO8859_1;
1104  fix[4097U << 16] |= EITFixUp::kEFixForceISO8859_1;
1105  fix[4098U << 16] |= EITFixUp::kEFixForceISO8859_1;
1106 
1107  //DVB-T Germany Berlin HSE/MonA TV
1108  fix[ 772LL << 32 | 8468 << 16 | 16387] = EITFixUp::kEFixForceISO8859_15;
1109  //DVB-T Germany Ruhrgebiet Tele 5
1110  //fix[ 8707LL << 32 | 8468 << 16 | 16413] = EITFixUp::kEFixForceISO8859_15; // they are sending the ISO 8859-9 signalling now
1111  // ANIXE
1112  fix[ 8707LL << 32 | 8468U << 16 | 16426 ] = // DVB-T Rhein-Main
1114 
1115  // DVB-C Kabel Deutschland encoding fixes Germany
1116  fix[ 112LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1117  fix[ 10000LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1118  fix[ 10001LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1119  fix[ 10002LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1120  fix[ 10003LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1121  fix[ 10006LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1122  fix[ 10009LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1123  fix[ 10010LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
1124  // Mark program on the HD transponders as HDTV
1125  fix[ 10012LL << 32 | 61441U << 16] = EITFixUp::kFixHDTV;
1126  fix[ 10013LL << 32 | 61441U << 16] = EITFixUp::kFixHDTV;
1127  // On transport 10004 only DMAX needs no fixing:
1128  fix[10004LL<<32 | 61441U << 16 | 50403] = // BBC World Service
1129  fix[10004LL<<32 | 61441U << 16 | 53101] = // BBC Prime (engl)
1130  fix[10004LL<<32 | 61441U << 16 | 53108] = // Toon Disney (engl)
1131  fix[10004LL<<32 | 61441U << 16 | 53109] = // Sky News (engl)
1132  fix[10004LL<<32 | 61441U << 16 | 53406] = // BBC Prime
1133  fix[10004LL<<32 | 61441U << 16 | 53407] = // Boomerang (engl)
1134  fix[10004LL<<32 | 61441U << 16 | 53404] = // Boomerang
1135  fix[10004LL<<32 | 61441U << 16 | 53408] = // TCM Classic Movies (engl)
1136  fix[10004LL<<32 | 61441U << 16 | 53409] = // Extreme Sports
1137  fix[10004LL<<32 | 61441U << 16 | 53410] = // CNBC Europe (engl)
1138  fix[10004LL<<32 | 61441U << 16 | 53503] = // Detski Mir
1139  fix[10004LL<<32 | 61441U << 16 | 53411] = // Sat.1 Comedy
1140  fix[10004LL<<32 | 61441U << 16 | 53412] = // kabel eins classics
1141  fix[10004LL<<32 | 61441U << 16 | 53112] = // Extreme Sports (engl)
1142  fix[10004LL<<32 | 61441U << 16 | 53513] = // Playhouse Disney (engl)
1143  fix[10004LL<<32 | 61441U << 16 | 53618] = // K1010
1144  fix[10004LL<<32 | 61441U << 16 | 53619] = // GemsTV
1146  // On transport 10005 QVC and Giga Digital needs no fixing:
1147  fix[10005LL<<32 | 61441U << 16 | 50104] = // E! Entertainment
1148  fix[10005LL<<32 | 61441U << 16 | 50107] = // 13th Street (KD)
1149  fix[10005LL<<32 | 61441U << 16 | 50301] = // ESPN Classic
1150  fix[10005LL<<32 | 61441U << 16 | 50302] = // VH1 Classic
1151  fix[10005LL<<32 | 61441U << 16 | 50303] = // Wein TV
1152  fix[10005LL<<32 | 61441U << 16 | 50304] = // AXN
1153  fix[10005LL<<32 | 61441U << 16 | 50305] = // Silverline
1154  fix[10005LL<<32 | 61441U << 16 | 50306] = // NASN
1155  fix[10005LL<<32 | 61441U << 16 | 50307] = // Disney Toon
1156  fix[10005LL<<32 | 61441U << 16 | 53105] = // NASN (engl)
1157  fix[10005LL<<32 | 61441U << 16 | 53115] = // VH1 Classic (engl)
1158  fix[10005LL<<32 | 61441U << 16 | 53405] = // ESPN Classic (engl)
1159  fix[10005LL<<32 | 61441U << 16 | 53402] = // AXN (engl)
1160  fix[10005LL<<32 | 61441U << 16 | 53613] = // CNN (engl)
1161  fix[10005LL<<32 | 61441U << 16 | 53516] = // Voyages Television
1162  fix[10005LL<<32 | 61441U << 16 | 53611] = // Der Schmuckkanal
1163  fix[10005LL<<32 | 61441U << 16 | 53104] = // Jukebox
1165  // On transport 10007 only following channels need fixing:
1166  fix[10007LL<<32| 61441U << 16 | 53607] = // Eurosport
1167  fix[10007LL<<32| 61441U << 16 | 53608] = // Das Vierte
1168  fix[10007LL<<32| 61441U << 16 | 53609] = // Viva
1169  fix[10007LL<<32| 61441U << 16 | 53628] = // COMEDY CENTRAL
1171  // RTL Subtitle parsing
1172  fix[10007LL<<32| 61441U << 16 | 53601] = // RTL
1173  fix[10007LL<<32| 61441U << 16 | 53602] = // Super RTL
1174  fix[10007LL<<32| 61441U << 16 | 53604] = // VOX
1175  fix[10007LL<<32| 61441U << 16 | 53606] = // n-tv
1177  // On transport 10008 only following channels need fixing:
1178  fix[ 10008LL<<32 | 61441U << 16 | 53002] = // Tele 5
1180 
1181  // DVB-C Unitymedia Germany
1182  fix[ 9999 << 16 | 161LL << 32 | 12101 ] = // RTL Television
1183  fix[ 9999 << 16 | 161LL << 32 | 12104 ] = // VOX
1184  fix[ 9999 << 16 | 161LL << 32 | 12107 ] = // Super RTL
1185  fix[ 9999 << 16 | 161LL << 32 | 12109 ] = // n-tv
1186  fix[ 9999 << 16 | 301LL << 32 | 30114 ] = // RTL NITRO
1188  fix[ 9999 << 16 | 191LL << 32 | 11102 ] = // DAS VIERTE
1190  // on this transport are only HD services, two TBD, arte and ServusTV, I think arte properly signals HD!
1191  fix[ 9999 << 16 | 401LL << 32 | 29109 ] = // ServusTV HD
1193 
1194  // DVB-S Astra 19.2E DMAX Germany
1195  fix[ 1113LL << 32 | 1 << 16 | 12602] = EITFixUp::kEFixForceISO8859_15;
1196 
1197  // Premiere
1198  fix[133 << 16] = EITFixUp::kEFixForceISO8859_15;
1199 
1200  // DVB-S Astra 19.2E French channels
1201  fix[ 1022LL << 32 | 1 << 16 | 6901 ] = // DIRECT 8
1202  fix[ 1022LL << 32 | 1 << 16 | 6905 ] = // France 24 (en Francais)
1203  fix[ 1022LL << 32 | 1 << 16 | 6911 ] = // DIRECT 8
1204  fix[ 1072LL << 32 | 1 << 16 | 8201 ] = // CANAL+
1205  fix[ 1070LL << 32 | 1 << 16 | 8004 ] = // EURONEWS
1206  fix[ 1091LL << 32 | 1 << 16 | 31220 ] = // EuroNews
1207  fix[ 1094LL << 32 | 1 << 16 | 17027 ] = // LCP
1208  fix[ 1094LL << 32 | 1 << 16 | 17028 ] = // NT1
1209  fix[ 1100LL << 32 | 1 << 16 | 8710 ] = // NRJ 12
1211 }
1212 
1218 {
1221  maxStarttime, "EITScanner");
1222  seenEITother = false;
1223  maxStarttime = QDateTime();
1224 }