|
MythTV
0.26-pre
|
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 }
1.7.6.1