MythTV  0.26-pre
eithelper.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 
00003 // Std C headers
00004 #include <time.h>
00005 
00006 // Std C++ headers
00007 #include <algorithm>
00008 using namespace std;
00009 
00010 // MythTV includes
00011 #include "eithelper.h"
00012 #include "eitfixup.h"
00013 #include "eitcache.h"
00014 #include "mythdb.h"
00015 #include "atsctables.h"
00016 #include "dvbtables.h"
00017 #include "premieretables.h"
00018 #include "dishdescriptors.h"
00019 #include "premieredescriptors.h"
00020 #include "mythmiscutil.h"
00021 #include "programdata.h"
00022 #include "programinfo.h" // for subtitle types and audio and video properties
00023 #include "compat.h" // for gmtime_r on windows.
00024 
00025 const uint EITHelper::kChunkSize = 20;
00026 EITCache *EITHelper::eitcache = new EITCache();
00027 
00028 static uint get_chan_id_from_db(uint sourceid,
00029                                 uint atscmajor, uint atscminor);
00030 static uint get_chan_id_from_db(uint sourceid,  uint serviceid,
00031                                 uint networkid, uint transportid);
00032 static void init_fixup(QMap<uint64_t,uint> &fix);
00033 static int calc_eit_utc_offset(void);
00034 
00035 #define LOC QString("EITHelper: ")
00036 
00037 EITHelper::EITHelper() :
00038     eitfixup(new EITFixUp()),
00039     gps_offset(-1 * GPS_LEAP_SECONDS),          utc_offset(0),
00040     sourceid(0)
00041 {
00042     init_fixup(fixup);
00043 
00044     utc_offset = calc_eit_utc_offset();
00045 
00046     int sign    = utc_offset < 0 ? -1 : +1;
00047     int diff    = abs(utc_offset);
00048     int hours   = diff / (60 * 60);
00049     int minutes = ((diff) / 60) % 60;
00050     int seconds = diff % 60;
00051     LOG(VB_EIT, LOG_INFO, LOC + QString("localtime offset %1%2:%3%4:%5%6 ")
00052             .arg((sign < 0) ? "-" : "")
00053             .arg(hours).arg(minutes/10).arg(minutes%10)
00054             .arg(seconds/10).arg(seconds%10));
00055 }
00056 
00057 EITHelper::~EITHelper()
00058 {
00059     QMutexLocker locker(&eitList_lock);
00060     while (db_events.size())
00061         delete db_events.dequeue();
00062 
00063     delete eitfixup;
00064 }
00065 
00066 uint EITHelper::GetListSize(void) const
00067 {
00068     QMutexLocker locker(&eitList_lock);
00069     return db_events.size();
00070 }
00071 
00077 uint EITHelper::ProcessEvents(void)
00078 {
00079     QMutexLocker locker(&eitList_lock);
00080     uint insertCount = 0;
00081 
00082     if (!db_events.size())
00083         return 0;
00084 
00085     MSqlQuery query(MSqlQuery::InitCon());
00086     for (uint i = 0; (i < kChunkSize) && (db_events.size() > 0); i++)
00087     {
00088         DBEventEIT *event = db_events.dequeue();
00089         eitList_lock.unlock();
00090 
00091         eitfixup->Fix(*event);
00092 
00093         insertCount += event->UpdateDB(query, 1000);
00094 
00095         delete event;
00096         eitList_lock.lock();
00097     }
00098 
00099     if (!insertCount)
00100         return 0;
00101 
00102     if (incomplete_events.size() || unmatched_etts.size())
00103     {
00104         LOG(VB_EIT, LOG_INFO,
00105             LOC + QString("Added %1 events -- complete(%2) "
00106                           "incomplete(%3) unmatched(%4)")
00107                 .arg(insertCount).arg(db_events.size())
00108                 .arg(incomplete_events.size()).arg(unmatched_etts.size()));
00109     }
00110     else
00111     {
00112         LOG(VB_EIT, LOG_INFO,
00113             LOC + QString("Added %1 events").arg(insertCount));
00114     }
00115 
00116     return insertCount;
00117 }
00118 
00119 void EITHelper::SetFixup(uint atsc_major, uint atsc_minor, uint eitfixup)
00120 {
00121     QMutexLocker locker(&eitList_lock);
00122     uint atsc_key = (atsc_major << 16) | atsc_minor;
00123     fixup[atsc_key] = eitfixup;
00124 }
00125 
00126 void EITHelper::SetLanguagePreferences(const QStringList &langPref)
00127 {
00128     QMutexLocker locker(&eitList_lock);
00129 
00130     uint priority = 1;
00131     QStringList::const_iterator it;
00132     for (it = langPref.begin(); it != langPref.end(); ++it)
00133     {
00134         if (!(*it).isEmpty())
00135         {
00136             uint language_key   = iso639_str3_to_key(*it);
00137             uint canonoical_key = iso639_key_to_canonical_key(language_key);
00138             languagePreferences[canonoical_key] = priority++;
00139         }
00140     }
00141 }
00142 
00143 void EITHelper::SetSourceID(uint _sourceid)
00144 {
00145     QMutexLocker locker(&eitList_lock);
00146     sourceid = _sourceid;
00147 }
00148 
00149 void EITHelper::AddEIT(uint atsc_major, uint atsc_minor,
00150                        const EventInformationTable *eit)
00151 {
00152     uint atsc_key = (atsc_major << 16) | atsc_minor;
00153     EventIDToATSCEvent &events = incomplete_events[atsc_key];
00154     EventIDToETT &etts = unmatched_etts[atsc_key];
00155 
00156     for (uint i = 0; i < eit->EventCount(); i++)
00157     {
00158         ATSCEvent ev(eit->StartTimeRaw(i), eit->LengthInSeconds(i),
00159                      eit->ETMLocation(i),
00160                      eit->title(i).GetBestMatch(languagePreferences),
00161                      eit->Descriptors(i), eit->DescriptorsLength(i));
00162 
00163         EventIDToETT::iterator it = etts.find(eit->EventID(i));
00164 
00165         if (it != etts.end())
00166         {
00167             CompleteEvent(atsc_major, atsc_minor, ev, *it);
00168             etts.erase(it);
00169         }
00170         else if (!ev.etm)
00171         {
00172             CompleteEvent(atsc_major, atsc_minor, ev, QString::null);
00173         }
00174         else
00175         {
00176             unsigned char *tmp = new unsigned char[ev.desc_length];
00177             memcpy(tmp, eit->Descriptors(i), ev.desc_length);
00178             ev.desc = tmp;
00179             events[eit->EventID(i)] = ev;
00180         }
00181     }
00182 }
00183 
00184 void EITHelper::AddETT(uint atsc_major, uint atsc_minor,
00185                        const ExtendedTextTable *ett)
00186 {
00187     uint atsc_key = (atsc_major << 16) | atsc_minor;
00188     // Try to complete an Event
00189     ATSCSRCToEvents::iterator eits_it = incomplete_events.find(atsc_key);
00190     if (eits_it != incomplete_events.end())
00191     {
00192         EventIDToATSCEvent::iterator it = (*eits_it).find(ett->EventID());
00193         if (it != (*eits_it).end())
00194         {
00195             CompleteEvent(
00196                 atsc_major, atsc_minor, *it,
00197                 ett->ExtendedTextMessage().GetBestMatch(languagePreferences));
00198 
00199             if ((*it).desc)
00200                 delete [] (*it).desc;
00201 
00202             (*eits_it).erase(it);
00203 
00204             return;
00205         }
00206     }
00207 
00208     // Couldn't find matching EIT. If not yet in unmatched ETT map, insert it.
00209     EventIDToETT &elist = unmatched_etts[atsc_key];
00210     if (elist.find(ett->EventID()) == elist.end())
00211     {
00212         elist[ett->EventID()] = ett->ExtendedTextMessage()
00213             .GetBestMatch(languagePreferences);
00214     }
00215 }
00216 
00217 static void parse_dvb_event_descriptors(desc_list_t list, uint fix,
00218                                         QMap<uint,uint> languagePreferences,
00219                                         QString &title, QString &subtitle,
00220                                         QString &description)
00221 {
00222     const unsigned char *bestShortEvent =
00223         MPEGDescriptor::FindBestMatch(
00224             list, DescriptorID::short_event, languagePreferences);
00225 
00226     unsigned char enc_1[3]  = { 0x10, 0x00, 0x01 };
00227     unsigned char enc_15[3] = { 0x10, 0x00, 0x0f };
00228     int enc_len = 0;
00229     const unsigned char *enc = NULL;
00230 
00231     // Is this BellExpressVU EIT (Canada) ?
00232     // Use an encoding override of ISO 8859-1 (Latin1)
00233     if (fix & EITFixUp::kEFixForceISO8859_1)
00234     {
00235         enc = enc_1;
00236         enc_len = sizeof(enc_1);
00237     }
00238 
00239     // Is this broken DVB provider in Western Europe?
00240     // Use an encoding override of ISO 8859-15 (Latin6)
00241     if (fix & EITFixUp::kEFixForceISO8859_15)
00242     {
00243         enc = enc_15;
00244         enc_len = sizeof(enc_15);
00245     }
00246 
00247     if (bestShortEvent)
00248     {
00249         ShortEventDescriptor sed(bestShortEvent);
00250         if (enc)
00251         {
00252             title    = sed.EventName(enc, enc_len);
00253             subtitle = sed.Text(enc, enc_len);
00254         }
00255         else
00256         {
00257             title    = sed.EventName();
00258             subtitle = sed.Text();
00259         }
00260     }
00261 
00262     vector<const unsigned char*> bestExtendedEvents =
00263         MPEGDescriptor::FindBestMatches(
00264             list, DescriptorID::extended_event, languagePreferences);
00265 
00266     description = "";
00267     for (uint j = 0; j < bestExtendedEvents.size(); j++)
00268     {
00269         if (!bestExtendedEvents[j])
00270         {
00271             description = "";
00272             break;
00273         }
00274 
00275         ExtendedEventDescriptor eed(bestExtendedEvents[j]);
00276         if (enc)
00277             description += eed.Text(enc, enc_len);
00278         else
00279             description += eed.Text();
00280     }
00281 }
00282 
00283 static inline void parse_dvb_component_descriptors(desc_list_t list,
00284                                                    unsigned char &subtitle_type,
00285                                                    unsigned char &audio_properties,
00286                                                    unsigned char &video_properties)
00287 {
00288     desc_list_t components =
00289         MPEGDescriptor::FindAll(list, DescriptorID::component);
00290     for (uint j = 0; j < components.size(); j++)
00291     {
00292         ComponentDescriptor component(components[j]);
00293         video_properties |= component.VideoProperties();
00294         audio_properties |= component.AudioProperties();
00295         subtitle_type    |= component.SubtitleType();
00296     }
00297 }
00298 
00299 void EITHelper::AddEIT(const DVBEventInformationTable *eit)
00300 {
00301     uint descCompression = (eit->TableID() > 0x80) ? 2 : 1;
00302     uint fix = fixup.value(eit->OriginalNetworkID() << 16);
00303     fix |= fixup.value((((uint64_t)eit->TSID()) << 32) |
00304                  (eit->OriginalNetworkID() << 16));
00305     fix |= fixup.value((eit->OriginalNetworkID() << 16) | eit->ServiceID());
00306     fix |= fixup.value((((uint64_t)eit->TSID()) << 32) |
00307                  (uint64_t)(eit->OriginalNetworkID() << 16) |
00308                   (uint64_t)eit->ServiceID());
00309     fix |= EITFixUp::kFixGenericDVB;
00310 
00311     uint chanid = GetChanID(eit->ServiceID(), eit->OriginalNetworkID(),
00312                             eit->TSID());
00313     if (!chanid)
00314         return;
00315 
00316     uint tableid   = eit->TableID();
00317     uint version   = eit->Version();
00318     for (uint i = 0; i < eit->EventCount(); i++)
00319     {
00320         // Skip event if we have already processed it before...
00321         if (!eitcache->IsNewEIT(chanid, tableid, version, eit->EventID(i),
00322                               eit->EndTimeUnixUTC(i)))
00323         {
00324             continue;
00325         }
00326 
00327         QString title         = QString("");
00328         QString subtitle      = QString("");
00329         QString description   = QString("");
00330         QString category      = QString("");
00331         uint category_type = kCategoryNone;
00332         unsigned char subtitle_type=0, audio_props=0, video_props=0;
00333 
00334         // Parse descriptors
00335         desc_list_t list = MPEGDescriptor::Parse(
00336             eit->Descriptors(i), eit->DescriptorsLength(i));
00337 
00338         const unsigned char *dish_event_name = NULL;
00339         if (EITFixUp::kFixDish & fix)
00340         {
00341             dish_event_name = MPEGDescriptor::Find(
00342                     list, PrivateDescriptorID::dish_event_name);
00343         }
00344 
00345         if (dish_event_name)
00346         {
00347             DishEventNameDescriptor dend(dish_event_name);
00348             if (dend.HasName())
00349                 title = dend.Name(descCompression);
00350 
00351             const unsigned char *dish_event_description =
00352                 MPEGDescriptor::Find(
00353                     list, PrivateDescriptorID::dish_event_description);
00354             if (dish_event_description)
00355             {
00356                 DishEventDescriptionDescriptor dedd(dish_event_description);
00357                 if (dedd.HasDescription())
00358                     description = dedd.Description(descCompression);
00359             }
00360         }
00361         else
00362         {
00363             parse_dvb_event_descriptors(list, fix, languagePreferences,
00364                                         title, subtitle, description);
00365         }
00366 
00367         parse_dvb_component_descriptors(list, subtitle_type, audio_props,
00368                                         video_props);
00369 
00370         QString programId = QString("");
00371         QString seriesId  = QString("");
00372         QString rating    = QString("");
00373         QString rating_system = QString("");
00374         QString advisory = QString("");
00375         float stars = 0.0;
00376         QDate originalairdate;
00377 
00378         if (EITFixUp::kFixDish & fix)
00379         {
00380             const unsigned char *mpaa_data = MPEGDescriptor::Find(
00381                 list, PrivateDescriptorID::dish_event_mpaa);
00382             if (mpaa_data)
00383             {
00384                 DishEventMPAADescriptor mpaa(mpaa_data);
00385                 stars = mpaa.stars();
00386 
00387                 if (stars) // Only movies for now
00388                 {
00389                     rating = mpaa.rating();
00390                     rating_system = "MPAA";
00391                     advisory = mpaa.advisory();
00392                 }
00393             }
00394 
00395             if (!stars) // Not MPAA rated, check VCHIP
00396             {
00397                 const unsigned char *vchip_data = MPEGDescriptor::Find(
00398                     list, PrivateDescriptorID::dish_event_vchip);
00399                 if (vchip_data)
00400                 {
00401                     DishEventVCHIPDescriptor vchip(vchip_data);
00402                     rating = vchip.rating();
00403                     rating_system = "VCHIP";
00404                     advisory = vchip.advisory();
00405                 }
00406             }
00407 
00408             if (!advisory.isEmpty() && !rating.isEmpty())
00409                 rating += ", " + advisory;
00410             else if (!advisory.isEmpty())
00411             {
00412                 rating = advisory;
00413                 rating_system = "advisory";
00414             }
00415 
00416             const unsigned char *tags_data = MPEGDescriptor::Find(
00417                 list, PrivateDescriptorID::dish_event_tags);
00418             if (tags_data)
00419             {
00420                 DishEventTagsDescriptor tags(tags_data);
00421                 seriesId  = tags.seriesid();
00422                 programId = tags.programid();
00423                 originalairdate = tags.originalairdate(); // future use
00424 
00425                 if (programId.startsWith("MV") || programId.startsWith("SP"))
00426                     seriesId = "";
00427             }
00428 
00429             const unsigned char *properties_data = MPEGDescriptor::Find(
00430                 list, PrivateDescriptorID::dish_event_properties);
00431             if (properties_data)
00432             {
00433                 DishEventPropertiesDescriptor properties(properties_data);
00434                 subtitle_type |= properties.SubtitleProperties(descCompression);
00435                 audio_props   |= properties.AudioProperties(descCompression);
00436             }
00437         }
00438 
00439         const unsigned char *content_data =
00440             MPEGDescriptor::Find(list, DescriptorID::content);
00441         if (content_data)
00442         {
00443             if ((EITFixUp::kFixDish & fix) || (EITFixUp::kFixBell & fix))
00444             {
00445                 DishContentDescriptor content(content_data);
00446                 category_type = content.GetTheme();
00447                 if (EITFixUp::kFixDish & fix)
00448                     category  = content.GetCategory();
00449             }
00450             else
00451             {
00452                 ContentDescriptor content(content_data);
00453                 category      = content.GetDescription(0);
00454                 category_type = content.GetMythCategory(0);
00455             }
00456         }
00457 
00458         desc_list_t contentIds =
00459             MPEGDescriptor::FindAll(list, DescriptorID::dvb_content_identifier);
00460         for (uint j = 0; j < contentIds.size(); j++)
00461         {
00462             DVBContentIdentifierDescriptor desc(contentIds[j]);
00463             if (desc.ContentEncoding() == 0)
00464             {
00465                 // The CRID is a URI.  It could contain UTF8 sequences encoded
00466                 // as %XX but there's no advantage in decoding them.
00467                 // The BBC currently uses private types 0x31 and 0x32.
00468                 if (desc.ContentType() == 0x01 || desc.ContentType() == 0x31)
00469                     programId = desc.ContentId();
00470                 else if (desc.ContentType() == 0x02 || desc.ContentType() == 0x32)
00471                     seriesId = desc.ContentId();
00472             }
00473         }
00474 
00475         QDateTime starttime = MythUTCToLocal(eit->StartTimeUTC(i));
00476         // fix starttime only if the duration is a multiple of a minute
00477         if (!(eit->DurationInSeconds(i) % 60))
00478             EITFixUp::TimeFix(starttime);
00479         QDateTime endtime   = starttime.addSecs(eit->DurationInSeconds(i));
00480 
00481         DBEventEIT *event = new DBEventEIT(
00482             chanid,
00483             title,     subtitle,      description,
00484             category,  category_type,
00485             starttime, endtime,       fix,
00486             subtitle_type,
00487             audio_props,
00488             video_props, stars,
00489             seriesId,  programId);
00490 
00491         db_events.enqueue(event);
00492     }
00493 }
00494 
00495 // This function gets special EIT data from the German provider Premiere
00496 // for the option channels Premiere Sport and Premiere Direkt
00497 void EITHelper::AddEIT(const PremiereContentInformationTable *cit)
00498 {
00499     // set fixup for Premiere
00500     uint fix = fixup.value(133 << 16);
00501     fix |= EITFixUp::kFixGenericDVB;
00502 
00503     QString title         = QString("");
00504     QString subtitle      = QString("");
00505     QString description   = QString("");
00506     QString category      = QString("");
00507     MythCategoryType category_type = kCategoryNone;
00508     unsigned char subtitle_type=0, audio_props=0, video_props=0;
00509 
00510     // Parse descriptors
00511     desc_list_t list = MPEGDescriptor::Parse(
00512         cit->Descriptors(), cit->DescriptorsLength());
00513 
00514     parse_dvb_event_descriptors(list, fix, languagePreferences,
00515                                 title, subtitle, description);
00516 
00517     parse_dvb_component_descriptors(list, subtitle_type, audio_props,
00518                                     video_props);
00519 
00520     const unsigned char *content_data =
00521         MPEGDescriptor::Find(list, DescriptorID::content);
00522     if (content_data)
00523     {
00524         ContentDescriptor content(content_data);
00525         // fix events without real content data
00526         if (content.Nibble(0)==0x00)
00527         {
00528             if(content.UserNibble(0)==0x1)
00529             {
00530                 category_type = kCategoryMovie;
00531             }
00532             else if(content.UserNibble(0)==0x0)
00533             {
00534                 category_type = kCategorySports;
00535                 category = QObject::tr("Sports");
00536             }
00537         }
00538         else
00539         {
00540             category_type = content.GetMythCategory(0);
00541             category      = content.GetDescription(0);
00542         }
00543     }
00544 
00545     uint tableid   = cit->TableID();
00546     uint version   = cit->Version();
00547     uint contentid = cit->ContentID();
00548     // fake endtime
00549     uint endtime   = QDateTime::currentDateTime().addDays(1).toTime_t();
00550 
00551     // Find Transmissions
00552     desc_list_t transmissions =
00553         MPEGDescriptor::FindAll(
00554             list, PrivateDescriptorID::premiere_content_transmission);
00555     for(uint j=0; j< transmissions.size(); j++)
00556     {
00557         PremiereContentTransmissionDescriptor transmission(transmissions[j]);
00558         uint networkid = transmission.OriginalNetworkID();
00559         uint tsid      = transmission.TSID();
00560         uint serviceid = transmission.ServiceID();
00561 
00562         uint chanid = GetChanID(serviceid, networkid, tsid);
00563 
00564         if (!chanid)
00565         {
00566             LOG(VB_EIT, LOG_INFO, LOC +
00567                 QString("Premiere EIT for NIT %1, TID %2, SID %3, "
00568                         "count %4, title: %5. Channel not found!")
00569                     .arg(networkid).arg(tsid).arg(serviceid)
00570                     .arg(transmission.TransmissionCount()).arg(title));
00571             continue;
00572         }
00573 
00574         // Skip event if we have already processed it before...
00575         if (!eitcache->IsNewEIT(chanid, tableid, version, contentid, endtime))
00576         {
00577             continue;
00578         }
00579 
00580         for (uint k=0; k<transmission.TransmissionCount(); ++k)
00581         {
00582             QDateTime starttime = transmission.StartTimeUTC(k);
00583             // fix starttime only if the duration is a multiple of a minute
00584             if (!(cit->DurationInSeconds() % 60))
00585                 EITFixUp::TimeFix(starttime);
00586             QDateTime endtime   = starttime.addSecs(cit->DurationInSeconds());
00587 
00588             DBEventEIT *event = new DBEventEIT(
00589                 chanid,
00590                 title,     subtitle,      description,
00591                 category,  category_type,
00592                 starttime, endtime,       fix,
00593                 subtitle_type,
00594                 audio_props,
00595                 video_props, 0.0,
00596                 "",  "");
00597 
00598             db_events.enqueue(event);
00599         }
00600     }
00601 }
00602 
00603 
00604 void EITHelper::PruneEITCache(uint timestamp)
00605 {
00606     eitcache->PruneOldEntries(timestamp);
00607 }
00608 
00609 void EITHelper::WriteEITCache(void)
00610 {
00611     eitcache->WriteToDB();
00612 }
00613 
00615 // private methods and functions below this line                    //
00617 
00618 void EITHelper::CompleteEvent(uint atsc_major, uint atsc_minor,
00619                               const ATSCEvent &event,
00620                               const QString   &ett)
00621 {
00622     uint chanid = GetChanID(atsc_major, atsc_minor);
00623     if (!chanid)
00624         return;
00625 
00626     QDateTime starttime;
00627     time_t off = GPS_EPOCH + gps_offset + utc_offset;
00628     time_t tmp = event.start_time + off;
00629     tm result;
00630 
00631     if (gmtime_r(&tmp, &result))
00632     {
00633         starttime.setDate(QDate(result.tm_year + 1900,
00634                                 result.tm_mon + 1,
00635                                 result.tm_mday));
00636         starttime.setTime(QTime(result.tm_hour, result.tm_min, result.tm_sec));
00637     }
00638     else
00639     {
00640         starttime.setTime_t(tmp - utc_offset);
00641     }
00642 
00643     // fix starttime only if the duration is a multiple of a minute
00644     if (!(event.length % 60))
00645         EITFixUp::TimeFix(starttime);
00646     QDateTime endtime = starttime.addSecs(event.length);
00647 
00648     desc_list_t list = MPEGDescriptor::Parse(event.desc, event.desc_length);
00649     unsigned char subtitle_type =
00650         MPEGDescriptor::Find(list, DescriptorID::caption_service) ?
00651         SUB_HARDHEAR : SUB_UNKNOWN;
00652     unsigned char audio_properties = AUD_UNKNOWN;
00653     unsigned char video_properties = VID_UNKNOWN;
00654 
00655     uint atsc_key = (atsc_major << 16) | atsc_minor;
00656 
00657     QMutexLocker locker(&eitList_lock);
00658     QString title = event.title;
00659     QString subtitle = ett;
00660     db_events.enqueue(new DBEventEIT(chanid, title, subtitle,
00661                                      starttime, endtime,
00662                                      fixup.value(atsc_key), subtitle_type,
00663                                      audio_properties, video_properties));
00664 }
00665 
00666 uint EITHelper::GetChanID(uint atsc_major, uint atsc_minor)
00667 {
00668     uint64_t key;
00669     key  = ((uint64_t) sourceid);
00670     key |= ((uint64_t) atsc_minor) << 16;
00671     key |= ((uint64_t) atsc_major) << 32;
00672 
00673     ServiceToChanID::const_iterator it = srv_to_chanid.find(key);
00674     if (it != srv_to_chanid.end())
00675         return max(*it, 0);
00676 
00677     uint chanid = get_chan_id_from_db(sourceid, atsc_major, atsc_minor);
00678     if (chanid)
00679         srv_to_chanid[key] = chanid;
00680 
00681     return chanid;
00682 }
00683 
00684 uint EITHelper::GetChanID(uint serviceid, uint networkid, uint tsid)
00685 {
00686     uint64_t key;
00687     key  = ((uint64_t) sourceid);
00688     key |= ((uint64_t) serviceid) << 16;
00689     key |= ((uint64_t) networkid) << 32;
00690     key |= ((uint64_t) tsid)      << 48;
00691 
00692     ServiceToChanID::const_iterator it = srv_to_chanid.find(key);
00693     if (it != srv_to_chanid.end())
00694         return max(*it, 0);
00695 
00696     uint chanid = get_chan_id_from_db(sourceid, serviceid, networkid, tsid);
00697     if (chanid)
00698         srv_to_chanid[key] = chanid;
00699 
00700     return chanid;
00701 }
00702 
00703 static uint get_chan_id_from_db(uint sourceid,
00704                                 uint atsc_major, uint atsc_minor)
00705 {
00706     MSqlQuery query(MSqlQuery::InitCon());
00707     query.prepare(
00708             "SELECT chanid, useonairguide "
00709             "FROM channel "
00710             "WHERE atsc_major_chan = :MAJORCHAN AND "
00711             "      atsc_minor_chan = :MINORCHAN AND "
00712             "      sourceid        = :SOURCEID");
00713     query.bindValue(":MAJORCHAN", atsc_major);
00714     query.bindValue(":MINORCHAN", atsc_minor);
00715     query.bindValue(":SOURCEID",  sourceid);
00716 
00717     if (!query.exec() || !query.isActive())
00718         MythDB::DBError("Looking up chanid 1", query);
00719     else if (query.next())
00720     {
00721         bool useOnAirGuide = query.value(1).toBool();
00722         return (useOnAirGuide) ? query.value(0).toUInt() : 0;
00723     }
00724 
00725     return 0;
00726 }
00727 
00728 // Figure out the chanid for this channel
00729 static uint get_chan_id_from_db(uint sourceid, uint serviceid,
00730                                 uint networkid, uint transportid)
00731 {
00732     uint chanid = 0;
00733     bool useOnAirGuide = false;
00734     MSqlQuery query(MSqlQuery::InitCon());
00735 
00736     // DVB Link to chanid
00737     QString qstr =
00738         "SELECT chanid, useonairguide, channel.sourceid "
00739         "FROM channel, dtv_multiplex "
00740         "WHERE serviceid        = :SERVICEID   AND "
00741         "      networkid        = :NETWORKID   AND "
00742         "      transportid      = :TRANSPORTID AND "
00743         "      channel.mplexid  = dtv_multiplex.mplexid";
00744 
00745     query.prepare(qstr);
00746     query.bindValue(":SERVICEID",   serviceid);
00747     query.bindValue(":NETWORKID",   networkid);
00748     query.bindValue(":TRANSPORTID", transportid);
00749 
00750     if (!query.exec() || !query.isActive())
00751         MythDB::DBError("Looking up chanID", query);
00752 
00753     while (query.next())
00754     {
00755         // Check to see if we are interested in this channel
00756         chanid        = query.value(0).toUInt();
00757         useOnAirGuide = query.value(1).toBool();
00758         if (sourceid == query.value(2).toUInt())
00759             return useOnAirGuide ? chanid : 0;
00760     }
00761 
00762     if (query.size() > 1) {
00763         LOG(VB_EIT, LOG_INFO,
00764             LOC + QString("found %1 channels for networdid %2, "
00765                           "transportid %3, serviceid %4 but none "
00766                           "for current sourceid %5.")
00767                 .arg(query.size()).arg(networkid).arg(transportid)
00768                 .arg(serviceid).arg(sourceid));
00769     }
00770 
00771     return useOnAirGuide ? chanid : 0;
00772 }
00773 
00774 static void init_fixup(QMap<uint64_t,uint> &fix)
00775 {
00777     // Fixups to make EIT provided listings more useful
00778     // transport_id<<32 | netword_id<<16 | service_id
00779 
00780     // Bell Express VU Canada
00781     fix[  256U << 16] = EITFixUp::kFixBell;
00782     fix[  257U << 16] = EITFixUp::kFixBell;
00783     fix[ 4100U << 16] = EITFixUp::kFixBell;
00784     fix[ 4101U << 16] = EITFixUp::kFixBell;
00785     fix[ 4102U << 16] = EITFixUp::kFixBell;
00786     fix[ 4103U << 16] = EITFixUp::kFixBell;
00787     fix[ 4104U << 16] = EITFixUp::kFixBell;
00788     fix[ 4105U << 16] = EITFixUp::kFixBell;
00789     fix[ 4106U << 16] = EITFixUp::kFixBell;
00790     fix[ 4107U << 16] = EITFixUp::kFixBell;
00791     fix[ 4097U << 16] = EITFixUp::kFixBell;
00792     fix[ 4098U << 16] = EITFixUp::kFixBell;
00793 
00794     // United Kingdom
00795     fix[ 9018U << 16] = EITFixUp::kFixUK;
00796     // UK Freesat
00797     fix[ 2013LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00798     fix[ 2041LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00799     fix[ 2042LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00800     fix[ 2044LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00801     fix[ 2045LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00802     fix[ 2046LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00803     fix[ 2047LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00804     fix[ 2048LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00805     fix[ 2049LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00806     fix[ 2050LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00807     fix[ 2051LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00808     fix[ 2053LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00809     fix[ 2054LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00810     fix[ 2056LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00811     fix[ 2057LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00812     fix[ 2063LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00813     fix[ 2068LL << 32 | 2U << 16] = EITFixUp::kFixUK;
00814 
00815     // ComHem Sweden
00816     fix[40999U << 16       ] = EITFixUp::kFixComHem;
00817     fix[40999U << 16 | 1070] = EITFixUp::kFixSubtitle;
00818     fix[40999U << 16 | 1308] = EITFixUp::kFixSubtitle;
00819     fix[40999U << 16 | 1041] = EITFixUp::kFixSubtitle;
00820     fix[40999U << 16 | 1306] = EITFixUp::kFixSubtitle;
00821     fix[40999U << 16 | 1307] = EITFixUp::kFixSubtitle;
00822     fix[40999U << 16 | 1030] = EITFixUp::kFixSubtitle;
00823     fix[40999U << 16 | 1016] = EITFixUp::kFixSubtitle;
00824     fix[40999U << 16 | 1131] = EITFixUp::kFixSubtitle;
00825     fix[40999U << 16 | 1068] = EITFixUp::kFixSubtitle;
00826     fix[40999U << 16 | 1069] = EITFixUp::kFixSubtitle;
00827 
00828     // Australia
00829     fix[ 4096U << 16] = EITFixUp::kFixAUStar;
00830     fix[ 4096U << 16] = EITFixUp::kFixAUStar;
00831 
00832     // MultiChoice Africa
00833     fix[ 6144U << 16] = EITFixUp::kFixMCA;
00834 
00835     // RTL Subtitle parsing
00836     fix[      1089LL << 32 |     1  << 16] = // DVB-S
00837         fix[   773LL << 32 |  8468U << 16] = // DVB-T Berlin/Brandenburg
00838         fix[  2819LL << 32 |  8468U << 16] = // DVB-T Niedersachsen + Bremen
00839         fix[  8706LL << 32 |  8468U << 16] = // DVB-T NRW
00840         fix[ 12801LL << 32 |  8468U << 16] = // DVB-T Bayern
00841         EITFixUp::kFixRTL | EITFixUp::kFixCategory;
00842 
00843     // Premiere EIT processing
00844     fix[   1LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00845     fix[   2LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00846     fix[   3LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00847     fix[   4LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00848     fix[   5LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00849     fix[   6LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00850     fix[  17LL << 32 |  133 << 16] = EITFixUp::kFixPremiere;
00851     // Mark Premiere HD and Discovery HD as HDTV
00852     fix[   6LL << 32 |  133 << 16 | 129] = EITFixUp::kFixHDTV;
00853     fix[   6LL << 32 |  133 << 16 | 130] = EITFixUp::kFixHDTV;
00854 
00855     // Netherlands
00856     fix[ 1000U << 16] = EITFixUp::kFixNL;
00857 
00858     // Finland
00859     fix[      8438U << 16] = // DVB-T Espoo
00860         fix[ 42249U << 16] = // DVB-C Welho
00861         fix[    15U << 16] = // DVB-C Welho
00862         EITFixUp::kFixFI | EITFixUp::kFixCategory;
00863 
00864     // DVB-S(2) Thor 0.8W Norwegian
00865     fix[70U << 16] = EITFixUp::kFixNO;
00866 
00867     // DVB-T NTV/NRK (Norway)
00868     fix[910LL << 32 | 8770U  << 16 | 0x006f] = EITFixUp::kFixNRK_DVBT;  //NRK Folkemusikk
00869     fix[910LL << 32 | 8770U  << 16 | 0x0070] = EITFixUp::kFixNRK_DVBT;  //NRK Stortinget
00870     fix[910LL << 32 | 8770U  << 16 | 0x0071] = EITFixUp::kFixNRK_DVBT;  //NRK Super
00871     fix[910LL << 32 | 8770U  << 16 | 0x0072] = EITFixUp::kFixNRK_DVBT;  //NRK Sport
00872     fix[910LL << 32 | 8770U  << 16 | 0x0073] = EITFixUp::kFixNRK_DVBT;  //NRK Gull
00873     fix[910LL << 32 | 8770U  << 16 | 0x0074] = EITFixUp::kFixNRK_DVBT;  //NRK Jazz
00874     fix[910LL << 32 | 8770U  << 16 | 0x0067] = EITFixUp::kFixNRK_DVBT;  //NRK Super / NRK3
00875     fix[910LL << 32 | 8770U  << 16 | 0x0068] = EITFixUp::kFixNRK_DVBT;  //NRK Tegnspr�
00876     fix[910LL << 32 | 8770U  << 16 | 0x0069] = EITFixUp::kFixNRK_DVBT;  //NRK P2
00877     fix[910LL << 32 | 8770U  << 16 | 0x006a] = EITFixUp::kFixNRK_DVBT;  //NRK P3
00878     fix[910LL << 32 | 8770U  << 16 | 0x006b] = EITFixUp::kFixNRK_DVBT;  //NRK Alltid Nyheter
00879     fix[910LL << 32 | 8770U  << 16 | 0x006c] = EITFixUp::kFixNRK_DVBT;  //NRK mP3
00880     fix[910LL << 32 | 8770U  << 16 | 0x006d] = EITFixUp::kFixNRK_DVBT;  //NRK Klassisk
00881     fix[910LL << 32 | 8770U  << 16 | 0x006e] = EITFixUp::kFixNRK_DVBT;  //NRK S�i Radio
00882     fix[910LL << 32 | 8770U  << 16 | 0x0066] = EITFixUp::kFixNRK_DVBT;  //NRK2
00883     fix[910LL << 32 | 8770U  << 16 | 0x03f0] = EITFixUp::kFixNRK_DVBT;  //NRK1 M�e og Romsdal
00884     fix[910LL << 32 | 8770U  << 16 | 0x0455] = EITFixUp::kFixNRK_DVBT;  //NRK P1 Tr�delag
00885     fix[910LL << 32 | 8770U  << 16 | 0x03f1] = EITFixUp::kFixNRK_DVBT;  //NRK1 Midtnytt
00886 
00888     // Special Early fixups for providers that break DVB EIT spec.
00889     // transport_id<<32 | network_id<<16 | service_id
00890 
00891     // Bell Express VU Canada
00892     fix[ 256U << 16] |= EITFixUp::kEFixForceISO8859_1;
00893     fix[ 257U << 16] |= EITFixUp::kEFixForceISO8859_1;
00894     fix[4100U << 16] |= EITFixUp::kEFixForceISO8859_1;
00895     fix[4101U << 16] |= EITFixUp::kEFixForceISO8859_1;
00896     fix[4102U << 16] |= EITFixUp::kEFixForceISO8859_1;
00897     fix[4103U << 16] |= EITFixUp::kEFixForceISO8859_1;
00898     fix[4104U << 16] |= EITFixUp::kEFixForceISO8859_1;
00899     fix[4105U << 16] |= EITFixUp::kEFixForceISO8859_1;
00900     fix[4106U << 16] |= EITFixUp::kEFixForceISO8859_1;
00901     fix[4107U << 16] |= EITFixUp::kEFixForceISO8859_1;
00902     fix[4097U << 16] |= EITFixUp::kEFixForceISO8859_1;
00903     fix[4098U << 16] |= EITFixUp::kEFixForceISO8859_1;
00904 
00905     //DVB-T Germany Berlin HSE/MonA TV
00906     fix[  772LL << 32 | 8468 << 16 | 16387] = EITFixUp::kEFixForceISO8859_15;
00907     //DVB-T Germany Ruhrgebiet Tele 5
00908     fix[ 8707LL << 32 | 8468 << 16 | 16413] = EITFixUp::kEFixForceISO8859_15;
00909 
00910     // DVB-C Kabel Deutschland encoding fixes Germany
00911     fix[   112LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00912     fix[ 10000LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00913     fix[ 10001LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00914     fix[ 10002LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00915     fix[ 10003LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00916     fix[ 10006LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00917     fix[ 10009LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00918     fix[ 10010LL << 32 | 61441U << 16] = EITFixUp::kEFixForceISO8859_15;
00919     // Mark program on the HD transponders as HDTV
00920     fix[ 10012LL << 32 | 61441U << 16] = EITFixUp::kFixHDTV;
00921     fix[ 10013LL << 32 | 61441U << 16] = EITFixUp::kFixHDTV;
00922     // On transport 10004 only DMAX needs no fixing:
00923     fix[10004LL<<32 | 61441U << 16 | 50403] = // BBC World Service
00924     fix[10004LL<<32 | 61441U << 16 | 53101] = // BBC Prime (engl)
00925     fix[10004LL<<32 | 61441U << 16 | 53108] = // Toon Disney (engl)
00926     fix[10004LL<<32 | 61441U << 16 | 53109] = // Sky News (engl)
00927     fix[10004LL<<32 | 61441U << 16 | 53406] = // BBC Prime
00928     fix[10004LL<<32 | 61441U << 16 | 53407] = // Boomerang (engl)
00929     fix[10004LL<<32 | 61441U << 16 | 53404] = // Boomerang
00930     fix[10004LL<<32 | 61441U << 16 | 53408] = // TCM Classic Movies (engl)
00931     fix[10004LL<<32 | 61441U << 16 | 53409] = // Extreme Sports
00932     fix[10004LL<<32 | 61441U << 16 | 53410] = // CNBC Europe (engl)
00933     fix[10004LL<<32 | 61441U << 16 | 53503] = // Detski Mir
00934     fix[10004LL<<32 | 61441U << 16 | 53411] = // Sat.1 Comedy
00935     fix[10004LL<<32 | 61441U << 16 | 53412] = // kabel eins classics
00936     fix[10004LL<<32 | 61441U << 16 | 53112] = // Extreme Sports (engl)
00937     fix[10004LL<<32 | 61441U << 16 | 53513] = // Playhouse Disney (engl)
00938     fix[10004LL<<32 | 61441U << 16 | 53618] = // K1010
00939     fix[10004LL<<32 | 61441U << 16 | 53619] = // GemsTV
00940         EITFixUp::kEFixForceISO8859_15;
00941     // On transport 10005 QVC and Giga Digital  needs no fixing:
00942     fix[10005LL<<32 | 61441U << 16 | 50104] = // E! Entertainment
00943     fix[10005LL<<32 | 61441U << 16 | 50107] = // 13th Street (KD)
00944     fix[10005LL<<32 | 61441U << 16 | 50301] = // ESPN Classic
00945     fix[10005LL<<32 | 61441U << 16 | 50302] = // VH1 Classic
00946     fix[10005LL<<32 | 61441U << 16 | 50303] = // Wein TV
00947     fix[10005LL<<32 | 61441U << 16 | 50304] = // AXN
00948     fix[10005LL<<32 | 61441U << 16 | 50305] = // Silverline
00949     fix[10005LL<<32 | 61441U << 16 | 50306] = // NASN
00950     fix[10005LL<<32 | 61441U << 16 | 50307] = // Disney Toon
00951     fix[10005LL<<32 | 61441U << 16 | 53105] = // NASN (engl)
00952     fix[10005LL<<32 | 61441U << 16 | 53115] = // VH1 Classic (engl)
00953     fix[10005LL<<32 | 61441U << 16 | 53405] = // ESPN Classic (engl)
00954     fix[10005LL<<32 | 61441U << 16 | 53402] = // AXN (engl)
00955     fix[10005LL<<32 | 61441U << 16 | 53613] = // CNN (engl)
00956     fix[10005LL<<32 | 61441U << 16 | 53516] = // Voyages Television
00957     fix[10005LL<<32 | 61441U << 16 | 53611] = // Der Schmuckkanal
00958     fix[10005LL<<32 | 61441U << 16 | 53104] = // Jukebox
00959         EITFixUp::kEFixForceISO8859_15;
00960     // On transport 10007 only following channels need fixing:
00961     fix[10007LL<<32| 61441U << 16 | 53607] = // Eurosport
00962     fix[10007LL<<32| 61441U << 16 | 53608] = // Das Vierte
00963     fix[10007LL<<32| 61441U << 16 | 53609] = // Viva
00964     fix[10007LL<<32| 61441U << 16 | 53628] = // COMEDY CENTRAL
00965         EITFixUp::kEFixForceISO8859_15;
00966     // RTL Subtitle parsing
00967     fix[10007LL<<32| 61441U << 16 | 53601] = // RTL
00968     fix[10007LL<<32| 61441U << 16 | 53602] = // Super RTL
00969     fix[10007LL<<32| 61441U << 16 | 53604] = // VOX
00970     fix[10007LL<<32| 61441U << 16 | 53606] = // n-tv
00971         EITFixUp::kFixRTL | EITFixUp::kFixCategory;
00972     // On transport 10008 only following channels need fixing:
00973     fix[    10008LL<<32 | 61441U << 16 | 53002] = // Tele 5
00974         EITFixUp::kEFixForceISO8859_15;
00975 
00976     // DVB-S Astra 19.2E DMAX Germany
00977     fix[  1113LL << 32 | 1 << 16 | 12602] = EITFixUp::kEFixForceISO8859_15;
00978 
00979     // Premiere
00980     fix[133 << 16] = EITFixUp::kEFixForceISO8859_15;
00981 
00982     // DVB-S Astra 19.2E French channels
00983     fix[     1022LL << 32 | 1 << 16 |  6901 ] = // DIRECT 8
00984         fix[ 1022LL << 32 | 1 << 16 |  6905 ] = // France 24 (en Francais)
00985         fix[ 1022LL << 32 | 1 << 16 |  6911 ] = // DIRECT 8
00986         fix[ 1072LL << 32 | 1 << 16 |  8201 ] = // CANAL+
00987         fix[ 1070LL << 32 | 1 << 16 |  8004 ] = // EURONEWS
00988         fix[ 1091LL << 32 | 1 << 16 | 31220 ] = // EuroNews
00989         fix[ 1094LL << 32 | 1 << 16 | 17027 ] = // LCP
00990         fix[ 1094LL << 32 | 1 << 16 | 17028 ] = // NT1
00991         fix[ 1100LL << 32 | 1 << 16 |  8710 ] = // NRJ 12
00992         EITFixUp::kEFixForceISO8859_15;
00993 }
00994 
00995 static int calc_eit_utc_offset(void)
00996 {
00997     QString config_offset = gCoreContext->GetSetting("EITTimeOffset", "Auto");
00998 
00999     if (config_offset == "Auto")
01000         return calc_utc_offset();
01001 
01002     if (config_offset == "None")
01003         return 0;
01004 
01005     int sign    = config_offset.left(1) == "-" ? -1 : +1;
01006     int hours   = config_offset.mid(1,2).toInt();
01007     int minutes = config_offset.right(2).toInt();
01008     return sign * (hours * 60 * 60) + (minutes * 60);
01009 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends