00001 #include <unistd.h>
00002
00003 #include <QTextCodec>
00004
00005 #include "dvbdescriptors.h"
00006 #include "iso6937tables.h"
00007 #include "freesat_huffman.h"
00008 #include "mythlogging.h"
00009
00010
00011 static QString decode_iso6937(const unsigned char *buf, uint length)
00012 {
00013
00014
00015 QString result = "";
00016 ushort ch = 0x20;
00017 for (uint i = 0; (i < length) && buf[i]; i++)
00018 {
00019 if (ch == 0xFFFF)
00020 {
00021
00022 ch = iso6937table_secondary[buf[i-1]][buf[i]];
00023 if (ch == 0xFFFF)
00024 {
00025
00026
00027 ch = iso6937table_base[buf[i]];
00028 if (ch == 0xFFFF)
00029 continue;
00030 }
00031 }
00032 else
00033 {
00034
00035
00036 ch = iso6937table_base[buf[i]];
00037 if (ch == 0xFFFF)
00038 continue;
00039
00040 }
00041 result += QChar(ch);
00042 }
00043 return result;
00044 }
00045
00046 static QString decode_text(const unsigned char *buf, uint length);
00047
00048
00049 QString dvb_decode_text(const unsigned char *src, uint raw_length,
00050 const unsigned char *encoding_override,
00051 uint encoding_override_length)
00052 {
00053 if (!raw_length)
00054 return "";
00055
00056 if (src[0] == 0x1f)
00057 return freesat_huffman_to_string(src, raw_length);
00058
00059 if (((0x10 < src[0]) && (src[0] < 0x15)) ||
00060 ((0x15 < src[0]) && (src[0] < 0x20)))
00061 {
00062
00063 LOG(VB_SIPARSER, LOG_ERR,
00064 "dvb_decode_text: Multi-byte coded text is not yet supported.");
00065 return "";
00066 }
00067
00068
00069
00070 unsigned char *dst =
00071 new unsigned char[raw_length + encoding_override_length];
00072
00073 uint length = 0;
00074 if (encoding_override && src[0] >= 0x20) {
00075 memcpy(dst, encoding_override, encoding_override_length);
00076 length = encoding_override_length;
00077 }
00078
00079
00080 for (uint i = 0; i < raw_length; i++)
00081 {
00082 if ((src[i] < 0x80) || (src[i] > 0x9F))
00083 dst[length++] = src[i];
00084
00085 else if (src[i] == 0x8A)
00086 dst[length++] = 0x20;
00087 }
00088
00089
00090
00091 QString sStr = (!length) ? "" : decode_text(dst, length);
00092
00093 delete [] dst;
00094
00095 return sStr;
00096 }
00097
00098 static QString decode_text(const unsigned char *buf, uint length)
00099 {
00100
00101
00102 static const QTextCodec *iso8859_codecs[16] =
00103 {
00104 QTextCodec::codecForName("Latin1"),
00105 QTextCodec::codecForName("ISO8859-1"),
00106 QTextCodec::codecForName("ISO8859-2"),
00107 QTextCodec::codecForName("ISO8859-3"),
00108 QTextCodec::codecForName("ISO8859-4"),
00109 QTextCodec::codecForName("ISO8859-5"),
00110 QTextCodec::codecForName("ISO8859-6"),
00111 QTextCodec::codecForName("ISO8859-7"),
00112 QTextCodec::codecForName("ISO8859-8"),
00113 QTextCodec::codecForName("ISO8859-9"),
00114 QTextCodec::codecForName("ISO8859-10"),
00115 QTextCodec::codecForName("ISO8859-11"),
00116 QTextCodec::codecForName("ISO8859-12"),
00117 QTextCodec::codecForName("ISO8859-13"),
00118 QTextCodec::codecForName("ISO8859-14"),
00119 QTextCodec::codecForName("ISO8859-15"),
00120 };
00121
00122
00123 if (buf[0] >= 0x20)
00124 {
00125 return decode_iso6937(buf, length);
00126 }
00127 else if ((buf[0] >= 0x01) && (buf[0] <= 0x0B))
00128 {
00129 return iso8859_codecs[4 + buf[0]]->toUnicode((char*)(buf + 1), length - 1);
00130 }
00131 else if (buf[0] == 0x10)
00132 {
00133
00134
00135
00136
00137
00138
00139 uint code = buf[1] << 8 | buf[2];
00140 if (code <= 15)
00141 return iso8859_codecs[code]->toUnicode((char*)(buf + 3), length - 3);
00142 else
00143 return QString::fromLocal8Bit((char*)(buf + 3), length - 3);
00144 }
00145 else if (buf[0] == 0x15)
00146 {
00147 return QString::fromUtf8((char*)(buf + 1), length - 1);
00148 }
00149 else
00150 {
00151
00152 return QString::fromLocal8Bit((char*)(buf + 1), length - 1);
00153 }
00154 }
00155
00156
00157 QString dvb_decode_short_name(const unsigned char *src, uint raw_length)
00158 {
00159 if (raw_length > 50)
00160 {
00161 LOG(VB_SIPARSER, LOG_WARNING,
00162 QString("dvb_decode_short_name: name is %1 chars "
00163 "long. Unlikely to be a short name.")
00164 .arg(raw_length));
00165 return "";
00166 }
00167
00168 if (((0x10 < src[0]) && (src[0] < 0x15)) ||
00169 ((0x15 < src[0]) && (src[0] < 0x20)))
00170 {
00171
00172 LOG(VB_SIPARSER, LOG_ERR, "dvb_decode_short_name: "
00173 "Multi-byte coded text is not yet supported.");
00174 return "";
00175 }
00176
00177 unsigned char *dst = new unsigned char[raw_length];
00178 uint length = 0;
00179
00180
00181 for (uint i = 0; i < raw_length; i++)
00182 if (src[i] == 0x86)
00183 while ((++i < raw_length) && (src[i] != 0x87))
00184 {
00185 if ((src[i] < 0x80) || (src[i] > 0x9F))
00186 dst[length++] = src[i];
00187
00188 else if (src[i] == 0x8A)
00189 dst[length++] = 0x20;
00190 }
00191
00192 QString sStr = (!length) ? dvb_decode_text(src, raw_length)
00193 : decode_text(dst, length);
00194
00195 delete [] dst;
00196
00197 return sStr;
00198 }
00199
00200 QMutex ContentDescriptor::categoryLock;
00201 QMap<uint,QString> ContentDescriptor::categoryDesc;
00202 volatile bool ContentDescriptor::categoryDescExists = false;
00203
00204 QString myth_category_type_to_string(uint category_type)
00205 {
00206 static const char *cattype[] =
00207 { "", "movie", "series", "sports", "tvshow", };
00208
00209 if ((category_type > kCategoryNone) && (category_type < kCategoryLast))
00210 return QString(cattype[category_type]);
00211
00212 return "";
00213 }
00214
00215 MythCategoryType string_to_myth_category_type(const QString &category_type)
00216 {
00217 static const char *cattype[] =
00218 { "", "movie", "series", "sports", "tvshow", };
00219
00220 for (uint i = 1; i < 5; i++)
00221 if (category_type == cattype[i])
00222 return (MythCategoryType) i;
00223 return kCategoryNone;
00224 }
00225
00226 MythCategoryType ContentDescriptor::GetMythCategory(uint i) const
00227 {
00228 if (0x1 == Nibble1(i))
00229 return kCategoryMovie;
00230 if (0x4 == Nibble1(i))
00231 return kCategorySports;
00232 return kCategoryTVShow;
00233 }
00234
00235 const char *linkage_types[] =
00236 {
00237 "Reserved(0x00)",
00238 "Information Service",
00239 "EPG Service",
00240 "CA Replacement Service",
00241 "TS Containing Complete Network/Bouquet SI",
00242 "Service Replacement Service",
00243 "Data Broadcast Service",
00244 "RCS Map",
00245 "Mobile Hand-Over",
00246 "System Software Update Service",
00247 "TS Containing SSU, BAT or NIT",
00248 "IP/MAC Notification Service",
00249 "TS Containing INT, BAT or NIT",
00250 "Event Linkage",
00251 };
00252
00253
00254 QString LinkageDescriptor::LinkageTypeString(void) const
00255 {
00256 if (LinkageType() < (sizeof(linkage_types) / sizeof(const char*)))
00257 return QString(linkage_types[LinkageType()]);
00258 if ((LinkageType() <= 0x7f) || (LinkageType() == 0x7f))
00259 return QString("Reserved(0x%1)").arg(LinkageType(),2,16,QChar('0'));
00260 return QString("User Defined(0x%1)").arg(LinkageType(),2,16,QChar('0'));
00261 }
00262
00263 QString LinkageDescriptor::MobileHandOverTypeString(void) const
00264 {
00265 if (kHandOverIdentical == MobileHandOverType())
00266 return "Hand-Over to an Identical Service";
00267 if (kHandOverLocalVariation == MobileHandOverType())
00268 return "Hand-Over to a Local Variation";
00269 if (kHandOverAssociatedService == MobileHandOverType())
00270 return "Hand-over to an Associated Service";
00271 return "Reserved";
00272 }
00273
00274 QString ContentDescriptor::GetDescription(uint i) const
00275 {
00276 if (!categoryDescExists)
00277 Init();
00278
00279 QMutexLocker locker(&categoryLock);
00280
00281
00282 QMap<uint,QString>::const_iterator it = categoryDesc.find(Nibble(i));
00283 if (it != categoryDesc.end())
00284 return *it;
00285
00286
00287 it = categoryDesc.find(Nibble1(i)<<4);
00288 if (it != categoryDesc.end())
00289 return *it;
00290
00291
00292 return "";
00293 }
00294
00295 QString ContentDescriptor::toString() const
00296 {
00297 QString tmp("ContentDescriptor: ");
00298 for (uint i = 0; i < Count(); i++)
00299 tmp += GetMythCategory(i) + " : " + GetDescription(i) + ", ";
00300 return tmp;
00301 }
00302
00303 void ContentDescriptor::Init(void)
00304 {
00305 QMutexLocker locker(&categoryLock);
00306
00307 if (categoryDescExists)
00308 return;
00309
00310 categoryDesc[0x10] = QObject::tr("Movie");
00311 categoryDesc[0x11] = QObject::tr("Movie") + " - " +
00312 QObject::tr("Detective/Thriller");
00313 categoryDesc[0x12] = QObject::tr("Movie")+ " - " +
00314 QObject::tr("Adventure/Western/War");
00315 categoryDesc[0x13] = QObject::tr("Movie")+ " - " +
00316 QObject::tr("Science Fiction/Fantasy/Horror");
00317 categoryDesc[0x14] = QObject::tr("Movie")+ " - " +
00318 QObject::tr("Comedy");
00319 categoryDesc[0x15] = QObject::tr("Movie")+ " - " +
00320 QObject::tr("Soap/melodrama/folkloric");
00321 categoryDesc[0x16] = QObject::tr("Movie")+ " - " +
00322 QObject::tr("Romance");
00323 categoryDesc[0x17] = QObject::tr("Movie")+ " - " +
00324 QObject::tr("Serious/Classical/Religious/Historical Movie/Drama");
00325 categoryDesc[0x18] = QObject::tr("Movie")+ " - " +
00326 QObject::tr("Adult", "Adult Movie");
00327
00328 categoryDesc[0x20] = QObject::tr("News");
00329 categoryDesc[0x21] = QObject::tr("News/weather report");
00330 categoryDesc[0x22] = QObject::tr("News magazine");
00331 categoryDesc[0x23] = QObject::tr("Documentary");
00332 categoryDesc[0x24] = QObject::tr("Intelligent Programs");
00333
00334 categoryDesc[0x30] = QObject::tr("Entertainment");
00335 categoryDesc[0x31] = QObject::tr("Game Show");
00336 categoryDesc[0x32] = QObject::tr("Variety Show");
00337 categoryDesc[0x33] = QObject::tr("Talk Show");
00338
00339 categoryDesc[0x40] = QObject::tr("Sports");
00340 categoryDesc[0x41] =
00341 QObject::tr("Special Events (World Cup, World Series, etc)");
00342 categoryDesc[0x42] = QObject::tr("Sports Magazines");
00343 categoryDesc[0x43] = QObject::tr("Football (Soccer)");
00344 categoryDesc[0x44] = QObject::tr("Tennis/Squash");
00345 categoryDesc[0x45] =
00346 QObject::tr("Misc. Team Sports");
00347 categoryDesc[0x46] = QObject::tr("Athletics");
00348 categoryDesc[0x47] = QObject::tr("Motor Sport");
00349 categoryDesc[0x48] = QObject::tr("Water Sport");
00350 categoryDesc[0x49] = QObject::tr("Winter Sports");
00351 categoryDesc[0x4A] = QObject::tr("Equestrian");
00352 categoryDesc[0x4B] = QObject::tr("Martial Sports");
00353
00354 categoryDesc[0x50] = QObject::tr("Kids");
00355 categoryDesc[0x51] = QObject::tr("Pre-School Children's Programs");
00356 categoryDesc[0x52] = QObject::tr("Entertainment Programs for 6 to 14");
00357 categoryDesc[0x53] = QObject::tr("Entertainment Programs for 10 to 16");
00358 categoryDesc[0x54] = QObject::tr("Informational/Educational");
00359 categoryDesc[0x55] = QObject::tr("Cartoons/Puppets");
00360
00361 categoryDesc[0x60] = QObject::tr("Music/Ballet/Dance");
00362 categoryDesc[0x61] = QObject::tr("Rock/Pop");
00363 categoryDesc[0x62] = QObject::tr("Classical Music");
00364 categoryDesc[0x63] = QObject::tr("Folk Music");
00365 categoryDesc[0x64] = QObject::tr("Jazz");
00366 categoryDesc[0x65] = QObject::tr("Musical/Opera");
00367 categoryDesc[0x66] = QObject::tr("Ballet");
00368
00369 categoryDesc[0x70] = QObject::tr("Arts/Culture");
00370 categoryDesc[0x71] = QObject::tr("Performing Arts");
00371 categoryDesc[0x72] = QObject::tr("Fine Arts");
00372 categoryDesc[0x73] = QObject::tr("Religion");
00373 categoryDesc[0x74] = QObject::tr("Popular Culture/Traditional Arts");
00374 categoryDesc[0x75] = QObject::tr("Literature");
00375 categoryDesc[0x76] = QObject::tr("Film/Cinema");
00376 categoryDesc[0x77] = QObject::tr("Experimental Film/Video");
00377 categoryDesc[0x78] = QObject::tr("Broadcasting/Press");
00378 categoryDesc[0x79] = QObject::tr("New Media");
00379 categoryDesc[0x7A] = QObject::tr("Arts/Culture Magazines");
00380 categoryDesc[0x7B] = QObject::tr("Fashion");
00381
00382 categoryDesc[0x80] = QObject::tr("Social/Policical/Economics");
00383 categoryDesc[0x81] = QObject::tr("Magazines/Reports/Documentary");
00384 categoryDesc[0x82] = QObject::tr("Economics/Social Advisory");
00385 categoryDesc[0x83] = QObject::tr("Remarkable People");
00386
00387 categoryDesc[0x90] = QObject::tr("Education/Science/Factual");
00388 categoryDesc[0x91] = QObject::tr("Nature/animals/Environment");
00389 categoryDesc[0x92] = QObject::tr("Technology/Natural Sciences");
00390 categoryDesc[0x93] = QObject::tr("Medicine/Physiology/Psychology");
00391 categoryDesc[0x94] = QObject::tr("Foreign Countries/Expeditions");
00392 categoryDesc[0x95] = QObject::tr("Social/Spiritual Sciences");
00393 categoryDesc[0x96] = QObject::tr("Further Education");
00394 categoryDesc[0x97] = QObject::tr("Languages");
00395
00396 categoryDesc[0xA0] = QObject::tr("Leisure/Hobbies");
00397 categoryDesc[0xA1] = QObject::tr("Tourism/Travel");
00398 categoryDesc[0xA2] = QObject::tr("Handicraft");
00399 categoryDesc[0xA3] = QObject::tr("Motoring");
00400 categoryDesc[0xA4] = QObject::tr("Fitness & Health");
00401 categoryDesc[0xA5] = QObject::tr("Cooking");
00402 categoryDesc[0xA6] = QObject::tr("Advertizement/Shopping");
00403 categoryDesc[0xA7] = QObject::tr("Gardening");
00404
00405 categoryDesc[0xB0] = QObject::tr("Original Language");
00406 categoryDesc[0xB1] = QObject::tr("Black & White");
00407 categoryDesc[0xB2] = QObject::tr("\"Unpublished\" Programs");
00408 categoryDesc[0xB3] = QObject::tr("Live Broadcast");
00409
00410 categoryDesc[0xF0] = QObject::tr("Drama");
00411
00412 categoryDescExists = true;
00413 }
00414
00415 QString FrequencyListDescriptor::toString() const
00416 {
00417 QString str = "FrequencyListDescriptor: frequencies: ";
00418
00419 for (uint i = 0; i < FrequencyCount(); i++)
00420 str.append(QString(" %1").arg(FrequencyHz(i)));
00421
00422 return str;
00423 }
00424
00425 QString ServiceDescriptorMapping::toString() const
00426 {
00427 QString str = "";
00428
00429 if (IsDTV())
00430 str.append(" (TV)");
00431 else if (IsDigitalAudio())
00432 str.append(" (Radio)");
00433 else if (IsHDTV())
00434 str.append(" (HDTV)");
00435 else if (IsTeletext())
00436 str.append(" (Teletext)");
00437 else
00438 str.append(QString(" (Unknown %1)").arg(ServiceType(),2,16));
00439
00440 return str;
00441 }
00442
00443 QString CableDeliverySystemDescriptor::toString() const
00444 {
00445 QString str = QString("CableDeliverySystemDescriptor: ");
00446
00447 str.append(QString("Frequency: %1\n").arg(FrequencyHz()));
00448 str.append(QString(" Mod=%1, SymbR=%2, FECInner=%3, FECOuter=%4")
00449 .arg(ModulationString())
00450 .arg(SymbolRateHz())
00451 .arg(FECInnerString())
00452 .arg(FECOuterString()));
00453
00454 return str;
00455 }
00456
00457 QString SatelliteDeliverySystemDescriptor::toString() const
00458 {
00459 QString str = QString("SatelliteDeliverySystemDescriptor: ");
00460
00461 str.append(QString("Frequency: %1\n").arg(FrequencyHz()));
00462 str.append(QString(" Mod=%1, SymbR=%2, FECInner=%3, Orbit=%4, Pol=%5")
00463 .arg(ModulationString())
00464 .arg(SymbolRateHz())
00465 .arg(FECInnerString())
00466 .arg(OrbitalPositionString())
00467 .arg(PolarizationString()));
00468
00469 return str;
00470 }
00471
00472 QString TerrestrialDeliverySystemDescriptor::toString() const
00473 {
00474 QString str = QString("TerrestrialDeliverySystemDescriptor: ");
00475
00476 str.append(QString("Frequency: %1\n").arg(FrequencyHz()));
00477 str.append(QString(" BW=%1k, C=%2, HP=%3, LP=%4, GI=%5, TransMode=%6k")
00478 .arg(BandwidthString())
00479 .arg(ConstellationString())
00480 .arg(CodeRateHPString())
00481 .arg(CodeRateLPString())
00482 .arg(GuardIntervalString())
00483 .arg(TransmissionModeString()));
00484
00485 return str;
00486 }
00487
00488 QString UKChannelListDescriptor::toString() const
00489 {
00490 QString ret = "UKChannelListDescriptor sid->chan_num: ";
00491 for (uint i = 0; i < ChannelCount(); i++)
00492 {
00493 ret += QString("%1->%2").arg(ServiceID(i)).arg(ChannelNumber(i));
00494 ret += (i+1<ChannelCount()) ? ", " : "";
00495 }
00496 return ret;
00497 }
00498
00499 QString CAIdentifierDescriptor::toString(void) const
00500 {
00501 QString ret = QString("CAIdentifierDescriptor ");
00502 for (uint i = 0; i < CASystemCount(); ++i)
00503 {
00504 ret += QString("ca_system_id(0x%1) ")
00505 .arg(CASystemId(i), 0, 16);
00506 }
00507 return ret;
00508 }
00509
00510 QString DataBroadcastDescriptor::toString(void) const
00511 {
00512 QString ret = QString("DataBroadcastDescriptor: "
00513 "data_broadcast_id(%1) "
00514 "component_tag(%1) ")
00515 .arg(DataBroadcastId(), 0, 10)
00516 .arg(DataComponentTag(), 0, 10);
00517
00518 ret += QString("selector(0x ");
00519 for (uint i = 0; i < SelectorLength(); i++)
00520 ret += QString("%1 ").arg(Selector()[i], 0, 16);
00521 ret += ") ";
00522
00523 ret += QString("ISO_639_language_code(%1) ")
00524 .arg(LanguageString());
00525
00526 ret += QString("text(%1) ") + QString(Text());
00527
00528 return ret;
00529 }
00530
00531 QString LocalTimeOffsetDescriptor::toString(void) const
00532 {
00533 QString ret = QString("LocalTimeOffsetDescriptor ");
00534 uint count = Count();
00535 for (uint i = 0; i < count; ++i)
00536 {
00537 ret += QString("country_code(%1) country_region_id(0x%2) "
00538 "local_time_offset_with_polarity(%3) "
00539 "time_of_change(TODO)")
00540 .arg(CountryCodeString(i))
00541 .arg(CountryRegionId(i), 0, 16)
00542 .arg(LocalTimeOffsetWithPolarity(i));
00543
00544 }
00545 return ret;
00546 }
00547
00548 QString NVODReferenceDescriptor::toString(void) const
00549 {
00550 QString ret = QString("NVODReferenceDescriptor ");
00551 for (uint i = 0; i < Count(); ++i)
00552 {
00553 ret += QString("transport_stream_id(0x%1) original_network_id(0x%2) "
00554 "service_id(0x%3) ")
00555 .arg(TransportStreamId(i), 0, 16)
00556 .arg(OriginalNetworkId(i), 0, 16)
00557 .arg(ServiceId(i), 0, 16);
00558 }
00559 return ret;
00560 }
00561
00562 QString PartialTransportStreamDescriptor::toString(void) const
00563 {
00564 return QString("PartialTransportStreamDescriptor peak_rate(%1) "
00565 "min_overall_smooth_rate(%2) max_overall_smooth_buf(3)")
00566 .arg(PeakRate()).arg(SmoothRate()).arg(SmoothBuf());
00567 }
00568
00569 QString AC3Descriptor::toString(void) const
00570 {
00571 QString ret = QString("AC3DescriptorDescriptor ");
00572 if (HasComponentType())
00573 ret += QString("component_type(%1) ")
00574 .arg(ComponentType(), 0, 10);
00575 if (HasBSID())
00576 ret += QString("bsid(0x%1) ").arg(BSID(),0,16);
00577 if (HasMainID())
00578 ret += QString("mainid(0x%1) ").arg(MainID(),0,16);
00579 if (HasASVC())
00580 ret += QString("asvc(%1) ").arg(ASVC());
00581 return ret;
00582 }
00583
00584