00001
00002
00003 #include "atsctables.h"
00004 #include "atscdescriptors.h"
00005
00006 QString MasterGuideTable::TableClassString(uint i) const
00007 {
00008 static const QString tts[] = {
00009 QString("UNKNOWN"),
00010 QString("Terrestrial VCT with current()"),
00011 QString("Terrestrial VCT with !current()"),
00012 QString("Cable VCT with current()"),
00013 QString("Cable VCT with !current()"),
00014 QString("Channel ETT"),
00015 QString("DCCSCT"),
00016 QString("EIT + 0x100"),
00017 QString("Event ETT + 0x200"),
00018 QString("DCCT + 0x1400"),
00019 QString("RTT + 0x300")
00020 };
00021 int tt = TableClass(i) + 1;
00022 return tts[tt];
00023 }
00024
00025 int MasterGuideTable::TableClass(uint i) const
00026 {
00027 const int tt = TableType(i);
00028 if (tt < 6)
00029 {
00030 return tt;
00031 }
00032 else if (tt < 0x300)
00033 {
00034 if (tt < 0x200) return TableClass::EIT;
00035 return TableClass::ETTe;
00036 }
00037 else if (tt >= 0x1400 && tt < 0x1500)
00038 return TableClass::DCCT;
00039 else if (tt < 0x400)
00040 return TableClass::RRT;
00041 return TableClass::UNKNOWN;
00042 }
00043
00044 void MasterGuideTable::Parse(void) const
00045 {
00046 _ptrs.clear();
00047 _ptrs.push_back(const_cast<unsigned char*>(psipdata()) + 3);
00048 for (uint i = 0; i < TableCount(); i++)
00049 _ptrs.push_back(_ptrs[i] + 11 + TableDescriptorsLength(i));
00050 }
00051
00052
00053 void VirtualChannelTable::Parse(void) const
00054 {
00055 _ptrs.clear();
00056 _ptrs.push_back(const_cast<unsigned char*>(psipdata()) + 2);
00057 for (uint i = 0; i < ChannelCount(); i++)
00058 _ptrs.push_back(_ptrs[i] + 32 + DescriptorsLength(i));
00059 }
00060
00061 void EventInformationTable::Parse(void) const
00062 {
00063 _ptrs.clear();
00064 _ptrs.push_back(const_cast<unsigned char*>(psipdata()) + 2);
00065 for (uint i = 0; i < EventCount(); i++)
00066 _ptrs.push_back(_ptrs[i] + 12 + TitleLength(i) + DescriptorsLength(i));
00067 }
00068
00069 QString MasterGuideTable::toString(void) const
00070 {
00071 QString str;
00072 str.append(QString("Master Guide Section\n%1"
00073 " table_count(%2)\n")
00074 .arg(PSIPTable::toString())
00075 .arg(TableCount()));
00076 for (uint i = 0; i < TableCount(); i++)
00077 {
00078 str.append(QString(" Table #%1 ").arg(i, 2, 10));
00079 str.append(QString("pid(0x%1) ver(%2) ")
00080 .arg(TablePID(i), 0, 16).arg(TableVersion(i), 2, 10));
00081 str.append(QString("size(%1) desc_len(%2) type: %4 %3 \n")
00082 .arg(TableDescriptorsBytes(i), 4, 10)
00083 .arg(TableDescriptorsLength(i))
00084 .arg(TableClassString(i)).arg(TableType(i)));
00085 if (0 != TableDescriptorsLength(i))
00086 {
00087 vector<const unsigned char*> desc =
00088 MPEGDescriptor::Parse(TableDescriptors(i),
00089 TableDescriptorsLength(i));
00090 for (uint i = 0; i < desc.size(); i++)
00091 str.append(QString(" %1\n")
00092 .arg(MPEGDescriptor(desc[i]).toString()));
00093 }
00094 }
00095 if (0 != GlobalDescriptorsLength())
00096 {
00097 str.append(QString(" global descriptors length(%1) ")
00098 .arg(GlobalDescriptorsLength()));
00099 vector<const unsigned char*> desc =
00100 MPEGDescriptor::Parse(GlobalDescriptors(),
00101 GlobalDescriptorsLength());
00102 str.append(QString("count: %1\n").arg(desc.size()));
00103 for (uint i = 0; i < desc.size(); i++)
00104 {
00105 str.append(QString(" %1\n")
00106 .arg(MPEGDescriptor(desc[i]).toString()));
00107 }
00108 }
00109 return str;
00110 }
00111
00112 QString MasterGuideTable::toStringXML(uint indent_level) const
00113 {
00114 QString indent_0 = xml_indent(indent_level);
00115 QString indent_1 = xml_indent(indent_level + 1);
00116 QString indent_2 = xml_indent(indent_level + 2);
00117
00118 QString str =
00119 QString("%1<MasterGuideSection table_count=\"%2\" "
00120 "global_descriptors_length=\"%3\"\n%4%5>\n")
00121 .arg(indent_0)
00122 .arg(TableCount())
00123 .arg(GlobalDescriptorsLength())
00124 .arg(indent_1)
00125 .arg(PSIPTable::XMLValues(indent_level + 1));
00126
00127 vector<const unsigned char*> gdesc =
00128 MPEGDescriptor::Parse(GlobalDescriptors(), GlobalDescriptorsLength());
00129 for (uint i = 0; i < gdesc.size(); i++)
00130 {
00131 str += MPEGDescriptor(gdesc[i], 300)
00132 .toStringXML(indent_level + 1) + "\n";
00133 }
00134
00135 for (uint i = 0; i < TableCount(); i++)
00136 {
00137 str += QString(
00138 "%1<Table pid=\"0x%2\" version=\"%3\""
00139 "\n%4type=\"0x%5\" type_desc=\"%6\""
00140 "\n%7number_bytes=\"%8\" table_descriptors_length=\"%9\"")
00141 .arg(indent_1)
00142 .arg(TablePID(i),4,16,QChar('0'))
00143 .arg(TableVersion(i))
00144 .arg(indent_1)
00145 .arg(TableType(i),4,16,QChar('0'))
00146 .arg(TableClassString(i))
00147 .arg(indent_2)
00148 .arg(TableDescriptorsBytes(i))
00149 .arg(TableDescriptorsLength(i));
00150
00151 vector<const unsigned char*> desc =
00152 MPEGDescriptor::Parse(
00153 TableDescriptors(i), TableDescriptorsLength(i));
00154 str += (desc.empty()) ? " />\n" : ">\n";
00155 for (uint i = 0; i < desc.size(); i++)
00156 {
00157 str += MPEGDescriptor(desc[i], 300)
00158 .toStringXML(indent_level + 2) + "\n";
00159 }
00160
00161 if (!desc.empty())
00162 str += indent_1 + "</Table>\n";
00163 }
00164
00165 return str + "</MasterGuideSection>";
00166 }
00167
00168 QString VirtualChannelTable::ModulationModeString(uint i) const
00169 {
00170 static const char *modnames[6] =
00171 {
00172 "[Reserved]", "Analog", "SCTE mode 1",
00173 "SCTE mode 2", "ATSC 8-VSB", "ATSC 16-VSB",
00174 };
00175 uint mode = ModulationMode(i);
00176 if (mode >= (sizeof(modnames) / sizeof(char*)))
00177 return QString("Unknown 0x%1").arg(mode,2,16,QChar('0'));
00178 else
00179 return QString(modnames[mode]);
00180 }
00181
00182 QString VirtualChannelTable::ServiceTypeString(uint i) const
00183 {
00184 static const char *servicenames[5] =
00185 {
00186 "[Reserved]", "Analog", "ATSC TV", "ATSC Audio", "ATSC Data",
00187 };
00188 uint type = ServiceType(i);
00189 if (type >= (sizeof(servicenames) / sizeof(char*)))
00190 return QString("Unknown 0x%1").arg(type,2,16,QChar('0'));
00191 else
00192 return QString(servicenames[type]);
00193 }
00194
00195 QString VirtualChannelTable::toString(void) const
00196 {
00197 QString str;
00198 str.append(QString("%1 Virtual Channel Section\n%2"
00199 " channel_count(%3) tsid(0x%4)")
00200 .arg((TableID::TVCT == TableID()) ? "Terrestrial":"Cable")
00201 .arg(PSIPTable::toString())
00202 .arg(ChannelCount())
00203 .arg(TransportStreamID(),4,16,QChar('0')));
00204
00205 if (TableID::CVCT == TableID())
00206 {
00207 uint sctemapid = (pesdata()[3]<<8) | pesdata()[4];
00208 str.append(" mapid(0x%1)").arg(sctemapid,0,16);
00209 }
00210
00211 str.append("\n");
00212
00213 for (uint i = 0; i < ChannelCount(); i++)
00214 str.append(ChannelString(i));
00215
00216 if (0 != GlobalDescriptorsLength())
00217 {
00218 str.append(QString("global descriptors length(%1) ")
00219 .arg(GlobalDescriptorsLength()));
00220 vector<const unsigned char*> desc =
00221 MPEGDescriptor::Parse(GlobalDescriptors(),
00222 GlobalDescriptorsLength());
00223 str.append(QString("count: %1\n").arg(desc.size()));
00224 for (uint i = 0; i < desc.size(); i++)
00225 {
00226 str.append(QString(" %1\n")
00227 .arg(MPEGDescriptor(desc[i]).toString()));
00228 }
00229 }
00230
00231 return str;
00232 }
00233
00234 QString VirtualChannelTable::toStringXML(uint indent_level) const
00235 {
00236 QString indent_0 = xml_indent(indent_level);
00237 QString indent_1 = xml_indent(indent_level + 1);
00238 QString indent_2 = xml_indent(indent_level + 2);
00239
00240 QString section_name = QString("%1VirtualChannelSection")
00241 .arg((TableID::TVCT == TableID()) ? "Terrestrial" : "Cable");
00242
00243 QString mapid;
00244 if (TableID::CVCT == TableID())
00245 {
00246 uint sctemapid = (pesdata()[3]<<8) | pesdata()[4];
00247 mapid = QString(" mapid=\"0x%1\"").arg(sctemapid,4,16,QChar('0'));
00248 }
00249
00250 QString str =
00251 QString("%1<%2 tsid=\"0x%3\" channel_count=\"%4\""
00252 "\n%5global_descriptors_length=\"%6\"%7"
00253 "\n%8%9>\n")
00254 .arg(indent_0)
00255 .arg(section_name)
00256 .arg(TransportStreamID(),4,16,QChar('0'))
00257 .arg(ChannelCount())
00258 .arg(indent_1)
00259 .arg(GlobalDescriptorsLength())
00260 .arg(mapid)
00261 .arg(indent_1)
00262 .arg(PSIPTable::XMLValues(indent_level + 1));
00263
00264 vector<const unsigned char*> gdesc =
00265 MPEGDescriptor::Parse(GlobalDescriptors(), GlobalDescriptorsLength());
00266 for (uint i = 0; i < gdesc.size(); i++)
00267 {
00268 str += MPEGDescriptor(gdesc[i], 300)
00269 .toStringXML(indent_level + 1) + "\n";
00270 }
00271
00272 for (uint i = 0; i < ChannelCount(); i++)
00273 str += ChannelStringXML(indent_level + 1, i) + "\n";
00274
00275 return str + indent_0 + QString("</%1>").arg(section_name);
00276 }
00277
00278 QString VirtualChannelTable::ChannelStringXML(
00279 uint indent_level, uint chan) const
00280 {
00281 QString indent_0 = xml_indent(indent_level);
00282 QString indent_1 = xml_indent(indent_level + 1);
00283 QString str = QString("%1<Channel %2\n%3descriptors_length=\"%4\">\n")
00284 .arg(indent_0)
00285 .arg(XMLChannelValues(indent_level + 1, chan))
00286 .arg(indent_1)
00287 .arg(DescriptorsLength(chan));
00288
00289 vector<const unsigned char*> desc =
00290 MPEGDescriptor::Parse(Descriptors(chan), DescriptorsLength(chan));
00291 for (uint i = 0; i < desc.size(); i++)
00292 {
00293 str += MPEGDescriptor(desc[i], 300)
00294 .toStringXML(indent_level + 1) + "\n";
00295 }
00296
00297 return str + indent_0 + "</Channel>";
00298 }
00299
00300 QString VirtualChannelTable::XMLChannelValues(
00301 uint indent_level, uint chan) const
00302 {
00303 QString indent_0 = xml_indent(indent_level);
00304 QString str;
00305
00306 str += QString("short_channel_name=\"%1\" ").arg(ShortChannelName(chan));
00307 str += "\n" + indent_0;
00308
00309 str += QString("modulation=\"0x%1\" modulation_desc=\"%2\" ")
00310 .arg(ModulationMode(chan),2,16,QChar('0'))
00311 .arg(ModulationModeString(chan));
00312 str += QString("channel_tsid=\"0x%1\"")
00313 .arg(ChannelTransportStreamID(chan),4,16,QChar('0'));
00314 str += "\n" + indent_0;
00315
00316 str += QString("program_number=\"%1\" ").arg(ProgramNumber(chan));
00317 str += QString("etm_location=\"%1\" ").arg(ETMlocation(chan));
00318 str += QString("access_controlled=\"%1\"")
00319 .arg(xml_bool_to_string(IsAccessControlled(chan)));
00320 str += "\n" + indent_0;
00321
00322 str += QString("hidden=\"%1\" ")
00323 .arg(xml_bool_to_string(IsHidden(chan)));
00324 str += QString("hide_guide=\"%1\"")
00325 .arg(xml_bool_to_string(IsHiddenInGuide(chan)));
00326 str += "\n" + indent_0;
00327
00328 str += QString("service_type=\"0x%1\" service_type_desc=\"%2\"")
00329 .arg(ServiceType(chan),2,16,QChar('0'))
00330 .arg(ServiceTypeString(chan));
00331 str += "\n" + indent_0;
00332
00333 str += QString("source_id=\"0x%1\"")
00334 .arg(SourceID(chan),4,16,QChar('0'));
00335
00336 return str;
00337 }
00338
00339 QString TerrestrialVirtualChannelTable::XMLChannelValues(
00340 uint indent_level, uint chan) const
00341 {
00342 return QString("major_channel=\"%1\" minor_channel=\"%2\" ")
00343 .arg(MajorChannel(chan)).arg(MinorChannel(chan)) +
00344 VirtualChannelTable::XMLChannelValues(indent_level, chan);
00345 }
00346
00347 QString TerrestrialVirtualChannelTable::ChannelString(uint chan) const
00348 {
00349 QString str;
00350 str.append(QString(" Channel #%1 ").arg(chan));
00351 str.append(QString("name(%1) %2-%3 ").arg(ShortChannelName(chan))
00352 .arg(MajorChannel(chan)).arg(MinorChannel(chan)));
00353 str.append(QString("mod(%1) ").arg(ModulationModeString(chan)));
00354 str.append(QString("cTSID(0x%1)\n")
00355 .arg(ChannelTransportStreamID(chan),4,16,QChar('0')));
00356
00357 str.append(QString(" pnum(%1) ").arg(ProgramNumber(chan)));
00358 str.append(QString("ETM_loc(%1) ").arg(ETMlocation(chan)));
00359 str.append(QString("access_ctrl(%1) ").arg(IsAccessControlled(chan)));
00360 str.append(QString("hidden(%1) ").arg(IsHidden(chan)));
00361 str.append(QString("hide_guide(%1) ").arg(IsHiddenInGuide(chan)));
00362 str.append(QString("service_type(%1)\n").arg(ServiceTypeString(chan)));
00363
00364 str.append(QString(" source_id(%1)\n").arg(SourceID(chan)));
00365 if (0 != DescriptorsLength(chan))
00366 {
00367 str.append(QString(" descriptors length(%1) ")
00368 .arg(DescriptorsLength(chan)));
00369 vector<const unsigned char*> desc =
00370 MPEGDescriptor::Parse(Descriptors(chan), DescriptorsLength(chan));
00371 str.append(QString("count:%1\n").arg(desc.size()));
00372 for (uint i = 0; i < desc.size(); i++)
00373 {
00374 str.append(QString(" %1\n")
00375 .arg(MPEGDescriptor(desc[i]).toString()));
00376 }
00377 }
00378 return str;
00379 }
00380
00381 QString CableVirtualChannelTable::XMLChannelValues(
00382 uint indent_level, uint chan) const
00383 {
00384 QString channel_info = SCTEIsChannelNumberTwoPart(chan) ?
00385 QString("major_channel=\"%1\" minor_channel=\"%2\" ")
00386 .arg(MajorChannel(chan)).arg(MinorChannel(chan)) :
00387 QString("channel_number=\"%1\" ")
00388 .arg(SCTEOnePartChannel(chan));
00389
00390 return channel_info +
00391 VirtualChannelTable::XMLChannelValues(indent_level, chan) +
00392 QString(" path_select=\"%1\" out_of_band=\"%2\"")
00393 .arg(xml_bool_to_string(IsPathSelect(chan)))
00394 .arg(xml_bool_to_string(IsOutOfBand(chan)));
00395 }
00396
00397 QString CableVirtualChannelTable::ChannelString(uint chan) const
00398 {
00399 QString str;
00400 str.append(QString(" Channel #%1 ").arg(chan));
00401 str.append(QString("name(%1)").arg(ShortChannelName(chan)));
00402
00403 if (SCTEIsChannelNumberTwoPart(chan))
00404 {
00405 str.append(QString(" %1-%2 ")
00406 .arg(MajorChannel(chan)).arg(MinorChannel(chan)));
00407 }
00408 else
00409 {
00410 str.append(QString(" %1 ").arg(SCTEOnePartChannel(chan)));
00411 }
00412
00413 str.append(QString("mod(%1) ").arg(ModulationModeString(chan)));
00414 str.append(QString("cTSID(0x%1)\n")
00415 .arg(ChannelTransportStreamID(chan),4,16,QChar('0')));
00416
00417 str.append(QString(" pnum(%1) ").arg(ProgramNumber(chan)));
00418 str.append(QString("ETM_loc(%1) ").arg(ETMlocation(chan)));
00419 str.append(QString("access_ctrl(%1) ").arg(IsAccessControlled(chan)));
00420 str.append(QString("hidden(%1) ").arg(IsHidden(chan)));
00421 str.append(QString("hide_guide(%1) ").arg(IsHiddenInGuide(chan)));
00422 str.append(QString("service_type(%1)\n").arg(ServiceTypeString(chan)));
00423
00424 str.append(QString(" source_id(%1) ").arg(SourceID(chan)));
00425 str.append(QString("path_select(%1) ").arg(IsPathSelect(chan)));
00426 str.append(QString("out_of_band(%1)\n").arg(IsOutOfBand(chan)));
00427
00428 if (0 != DescriptorsLength(chan))
00429 {
00430 str.append(QString(" descriptors length(%1) ")
00431 .arg(DescriptorsLength(chan)));
00432 vector<const unsigned char*> desc =
00433 MPEGDescriptor::Parse(Descriptors(chan), DescriptorsLength(chan));
00434 str.append(QString("count:%1\n").arg(desc.size()));
00435 for (uint i = 0; i < desc.size(); i++)
00436 str.append(QString(" %1\n")
00437 .arg(MPEGDescriptor(desc[i]).toString()));
00438 }
00439 return str;
00440 }
00441
00442 QString EventInformationTable::toString(void) const
00443 {
00444 QString str;
00445 str.append(QString("Event Information Table\n"));
00446 str.append(((PSIPTable*)(this))->toString());
00447 str.append(QString(" pid(0x%1) sourceID(%2) eventCount(%3)\n")
00448 .arg(tsheader()->PID()).arg(SourceID()).arg(EventCount()));
00449 for (uint i = 0; i < EventCount(); i++)
00450 {
00451 str.append(QString(" Event #%1 ID(%2) start_time(%3) length(%4 sec)\n")
00452 .arg(i,2,10).arg(EventID(i))
00453 .arg(StartTimeGPS(i).toString(Qt::LocalDate))
00454 .arg(LengthInSeconds(i)));
00455 str.append(QString(" ETM_loc(%1) Title(%2)\n").
00456 arg(ETMLocation(i)).arg(title(i).toString()));
00457 if (0 != DescriptorsLength(i))
00458 {
00459 vector<const unsigned char*> desc =
00460 MPEGDescriptor::Parse(Descriptors(i), DescriptorsLength(i));
00461 for (uint j=0; j<desc.size(); j++)
00462 str.append(QString("%1\n")
00463 .arg(MPEGDescriptor(desc[j]).toString()));
00464 }
00465 }
00466 return str;
00467 }
00468
00469 QString ExtendedTextTable::toString(void) const
00470 {
00471 QString str =
00472 QString("Extended Text Table -- sourceID(%1) eventID(%2) "
00473 "ettID(%3) isChannelETM(%4) isEventETM(%5)\n%6")
00474 .arg(SourceID()).arg(EventID()).arg(ExtendedTextTableID())
00475 .arg(IsChannelETM()).arg(IsEventETM())
00476 .arg(ExtendedTextMessage().toString());
00477 return str;
00478 }
00479
00480 int VirtualChannelTable::Find(int major, int minor) const
00481 {
00482 if (major>0)
00483 {
00484 for (uint i = 0; i < ChannelCount(); i++)
00485 {
00486 if ((MajorChannel(i) == (uint)major) &&
00487 (MinorChannel(i) == (uint)minor))
00488 return (int)i;
00489 }
00490 }
00491 else if (minor>0)
00492 {
00493 for (uint i = 0; i < ChannelCount(); i++)
00494 {
00495 if (MinorChannel(i) == (uint)minor)
00496 return (int)i;
00497 }
00498 }
00499 return -1;
00500 }
00501
00502 QString VirtualChannelTable::GetExtendedChannelName(uint i) const
00503 {
00504 if ((i >= ChannelCount()) || DescriptorsLength(i) == 0)
00505 return QString::null;
00506
00507 vector<const unsigned char*> parsed =
00508 MPEGDescriptor::Parse(Descriptors(i), DescriptorsLength(i));
00509
00510 const unsigned char* desc =
00511 MPEGDescriptor::Find(parsed, DescriptorID::extended_channel_name);
00512
00513 if (!desc)
00514 return QString::null;
00515
00516 return ExtendedChannelNameDescriptor(desc).LongChannelNameString();
00517 }
00518
00519 QString SystemTimeTable::toString(void) const
00520 {
00521 QString str =
00522 QString("System Time Section GPSTime(%1) GPS2UTC_Offset(%2) ")
00523 .arg(SystemTimeGPS().toString(Qt::ISODate)).arg(GPSOffset());
00524 str.append(QString("DS(%3) Day(%4) Hour(%5)\n")
00525 .arg(InDaylightSavingsTime())
00526 .arg(DayDaylightSavingsStarts())
00527 .arg(HourDaylightSavingsStarts()));
00528 return str;
00529 }
00530
00531 QString SystemTimeTable::toStringXML(uint indent_level) const
00532 {
00533 QString indent_0 = xml_indent(indent_level);
00534 QString indent_1 = xml_indent(indent_level + 1);
00535
00536 return QString(
00537 "%1<SystemTimeSection system_time=\"%2\" system_time_iso=\"%3\""
00538 "\n%4in_dst=\"%5\" dst_start_day=\"%6\" dst_start_hour=\"%7\""
00539 "\n%8%9 />")
00540 .arg(indent_0)
00541 .arg(GPSRaw())
00542 .arg(SystemTimeGPS().toString(Qt::ISODate))
00543 .arg(indent_1)
00544 .arg(xml_bool_to_string(InDaylightSavingsTime()))
00545 .arg(DayDaylightSavingsStarts())
00546 .arg(HourDaylightSavingsStarts())
00547 .arg(indent_1)
00548 .arg(PSIPTable::XMLValues(indent_level + 1));
00549 }