00001
00002
00003 #include "mpegtables.h"
00004 #include "atscdescriptors.h"
00005
00006 const unsigned char DEFAULT_PAT_HEADER[8] =
00007 {
00008 0x00,
00009 0xb0,
00010 0x00,
00011 0x00,
00012
00013 0x00,
00014 0xc1,
00015 0x00,
00016 0x00,
00017 };
00018
00019 const unsigned char DEFAULT_PMT_HEADER[12] =
00020 {
00021 0x02,
00022 0xb0,
00023 0x00,
00024 0x00,
00025
00026 0x00,
00027 0xc1,
00028 0x00,
00029 0x00,
00030 0xff, 0xff,
00031 0x00, 0x00,
00032 };
00033
00034 static const uint len_for_alloc[] =
00035 {
00036 TSPacket::PAYLOAD_SIZE
00037 - 1
00038 - 3 ,
00039 4000,
00040 };
00041
00042 uint StreamID::Normalize(uint stream_id, const desc_list_t &desc,
00043 const QString &sistandard)
00044 {
00045 if ((sistandard != "dvb") && (OpenCableVideo == stream_id))
00046 return MPEG2Video;
00047
00048 if (MPEGDescriptor::Find(desc, DescriptorID::AC3))
00049 return AC3Audio;
00050
00051 const unsigned char* d = NULL;
00052 QString reg("");
00053 if ((d = MPEGDescriptor::Find(desc, DescriptorID::registration)))
00054 reg = RegistrationDescriptor(d).FormatIdentifierString();
00055
00056 if (reg == "DTS1")
00057 return DTSAudio;
00058
00059 #if 0
00060
00061 if (MPEGDescriptor::Find(desc, DescriptorID::teletext) ||
00062 MPEGDescriptor::Find(desc, DescriptorID::subtitling))
00063 return stream_id;
00064 #endif
00065
00066 return stream_id;
00067 }
00068
00069 bool PSIPTable::HasCRC(void) const
00070 {
00071 bool has_crc = false;
00072
00073 switch (TableID())
00074 {
00075
00076 case TableID::PAT:
00077 case TableID::CAT:
00078 case TableID::PMT:
00079 has_crc = true;
00080 break;
00081
00082
00083
00084 case TableID::NIT:
00085 case TableID::SDT:
00086 case TableID::PF_EIT:
00087 has_crc = true;
00088 break;
00089 case TableID::TDT:
00090 has_crc = false;
00091 break;
00092
00093
00094 case TableID::NITo:
00095 case TableID::SDTo:
00096 case TableID::BAT:
00097 case TableID::PF_EITo:
00098 has_crc = true;
00099 break;
00100 case TableID::RST:
00101 case TableID::ST:
00102 has_crc = false;
00103 break;
00104 case TableID::TOT:
00105 has_crc = true;
00106 break;
00107
00108
00109
00110
00111
00112 case TableID::DIT:
00113 has_crc = false;
00114 break;
00115 case TableID::SIT:
00116 has_crc = true;
00117 break;
00118
00119
00120 case TableID::MGT:
00121 case TableID::TVCT:
00122 case TableID::CVCT:
00123 case TableID::RRT:
00124 case TableID::EIT:
00125 case TableID::ETT:
00126 case TableID::STT:
00127 case TableID::DET:
00128 case TableID::DST:
00129
00130
00131 case TableID::NRT:
00132 case TableID::LTST:
00133 case TableID::DCCT:
00134 case TableID::DCCSCT:
00135
00136 case TableID::AEIT:
00137 case TableID::AETT:
00138 case TableID::SVCT:
00139 has_crc = true;
00140 break;
00141
00142 default:
00143 {
00144
00145 if (TableID::SC_EITbeg <= TableID() &&
00146 TableID() <= TableID::SC_EITendo)
00147 {
00148 has_crc = true;
00149 }
00150
00151
00152 if (TableID::DN_EITbego <= TableID() &&
00153 TableID() <= TableID::DN_EITendo)
00154 {
00155 has_crc = true;
00156 }
00157 }
00158 break;
00159 }
00160
00161 return has_crc;
00162 }
00163
00164 bool PSIPTable::VerifyPSIP(bool verify_crc) const
00165 {
00166 if (verify_crc && (CalcCRC() != CRC()))
00167 {
00168 VERBOSE(VB_SIPARSER,
00169 QString("PSIPTable: Failed CRC check 0x%1 != 0x%2 "
00170 "for StreamID = 0x%3")
00171 .arg(CRC(),0,16).arg(CalcCRC(),0,16).arg(StreamID(),0,16));
00172 return false;
00173 }
00174
00175 unsigned char *bufend = _fullbuffer + _allocSize;
00176
00177 if ((_pesdata + 2) >= bufend)
00178 return false;
00179
00180 if (psipdata() >= bufend)
00181 return false;
00182
00183 if (TableID::PAT == TableID())
00184 {
00185 uint pcnt = (SectionLength() - PSIP_OFFSET - 2) >> 2;
00186 bool ok = (psipdata() + (pcnt << 2) + 3 < bufend);
00187 if (!ok)
00188 {
00189 VERBOSE(VB_SIPARSER, "PSIPTable: PAT: program "
00190 "list extends past end of buffer");
00191 return false;
00192 }
00193
00194 if ((Length() == 0xfff) && (TableIDExtension() == 0xffff) &&
00195 (Section() == 0xff) && (LastSection() == 0xff))
00196 {
00197 VERBOSE(VB_SIPARSER, "PSIPTable: PAT: All values a maximums");
00198 return false;
00199 }
00200
00201 return true;
00202 }
00203
00204 if (TableID::PMT == TableID())
00205 {
00206 if (psipdata() + 3 >= bufend)
00207 {
00208 VERBOSE(VB_SIPARSER, "PSIPTable: PMT: "
00209 "can't query program info length");
00210 return false;
00211 }
00212
00213 if (psipdata() + Length() - 9 > bufend)
00214 {
00215 VERBOSE(VB_SIPARSER, "PSIPTable: PMT: reported length to large");
00216 return false;
00217 }
00218
00219 uint proginfolen = ((psipdata()[2]<<8) | psipdata()[3]) & 0x0fff;
00220 const unsigned char *proginfo = psipdata() + 4;
00221 const unsigned char *cpos = proginfo + proginfolen;
00222 if (cpos > bufend)
00223 {
00224 VERBOSE(VB_SIPARSER, "PSIPTable: PMT: "
00225 "program info extends past end of buffer");
00226 return false;
00227 }
00228
00229 vector<unsigned char*> _ptrs;
00230 const unsigned char *pos = cpos;
00231 uint i = 0;
00232 for (; pos < psipdata() + Length() - 9; i++)
00233 {
00234 const unsigned char *ptr = pos;
00235 if (pos + 4 > bufend)
00236 {
00237 VERBOSE(VB_SIPARSER, QString(
00238 "PSIPTable: PMT: stream info %1 extends "
00239 "past end of buffer").arg(i));
00240 return false;
00241 }
00242 pos += 5 + ((ptr[3] << 8) | ptr[4]) & 0x0fff;
00243 }
00244 if (pos > bufend)
00245 {
00246 VERBOSE(VB_SIPARSER,
00247 QString("PSIPTable: PMT: last stream info %1 extends "
00248 "past end of buffer").arg(i));
00249 return false;
00250 }
00251
00252 return true;
00253 }
00254
00255 return true;
00256 }
00257
00258 ProgramAssociationTable* ProgramAssociationTable::CreateBlank(bool smallPacket)
00259 {
00260 (void) smallPacket;
00261 TSPacket *tspacket = TSPacket::CreatePayloadOnlyPacket();
00262 memcpy(tspacket->data() + sizeof(TSHeader) + 1,
00263 DEFAULT_PAT_HEADER, sizeof(DEFAULT_PAT_HEADER));
00264 PSIPTable psip = PSIPTable::View(*tspacket);
00265 psip.SetLength(TSPacket::PAYLOAD_SIZE
00266 - 1
00267 - 3 );
00268 ProgramAssociationTable *pat = new ProgramAssociationTable(psip);
00269 pat->SetTotalLength(sizeof(DEFAULT_PAT_HEADER));
00270 delete tspacket;
00271 return pat;
00272 }
00273
00274 ProgramAssociationTable* ProgramAssociationTable::Create(
00275 uint tsid, uint version,
00276 const vector<uint>& pnum, const vector<uint>& pid)
00277 {
00278 const uint count = min(pnum.size(), pid.size());
00279 ProgramAssociationTable* pat = CreateBlank();
00280 pat->SetVersionNumber(version);
00281 pat->SetTranportStreamID(tsid);
00282 pat->SetTotalLength(PSIP_OFFSET + (count * 4));
00283
00284
00285 if ((count * 4) >= (184 - (PSIP_OFFSET+1)))
00286 {
00287 VERBOSE(VB_IMPORTANT, "PAT::Create: Error, old "
00288 "PAT size exceeds maximum PAT size.");
00289 delete pat;
00290 return 0;
00291 }
00292
00293 uint offset = PSIP_OFFSET;
00294 for (uint i = 0; i < count; i++)
00295 {
00296
00297 pat->pesdata()[offset++] = pnum[i]>>8;
00298 pat->pesdata()[offset++] = pnum[i] & 0xff;
00299
00300 pat->pesdata()[offset++] = ((pid[i]>>8) & 0x1f) | 0xe0;
00301 pat->pesdata()[offset++] = pid[i] & 0xff;
00302 }
00303
00304 pat->Finalize();
00305
00306 return pat;
00307 }
00308
00309 ProgramMapTable* ProgramMapTable::CreateBlank(bool smallPacket)
00310 {
00311 ProgramMapTable *pmt = NULL;
00312 TSPacket *tspacket = TSPacket::CreatePayloadOnlyPacket();
00313 memcpy(tspacket->data() + sizeof(TSHeader) + 1,
00314 DEFAULT_PMT_HEADER, sizeof(DEFAULT_PMT_HEADER));
00315
00316 if (smallPacket)
00317 {
00318 PSIPTable psip = PSIPTable::View(*tspacket);
00319 psip.SetLength(len_for_alloc[0]);
00320 pmt = new ProgramMapTable(psip);
00321 }
00322 else
00323 {
00324 PSIPTable psip(*tspacket);
00325 psip.SetLength(len_for_alloc[1]);
00326 pmt = new ProgramMapTable(psip);
00327 }
00328
00329 pmt->SetTotalLength(sizeof(DEFAULT_PMT_HEADER));
00330 delete tspacket;
00331 return pmt;
00332 }
00333
00334 ProgramMapTable* ProgramMapTable::Create(
00335 uint programNumber, uint basepid, uint pcrpid, uint version,
00336 vector<uint> pids, vector<uint> types)
00337 {
00338 const uint count = min(pids.size(), types.size());
00339 ProgramMapTable* pmt = CreateBlank(false);
00340 pmt->tsheader()->SetPID(basepid);
00341
00342 pmt->RemoveAllStreams();
00343 pmt->SetProgramNumber(programNumber);
00344 pmt->SetPCRPID(pcrpid);
00345 pmt->SetVersionNumber(version);
00346
00347 for (uint i=0; i<count; i++)
00348 pmt->AppendStream(pids[i], types[i]);
00349 pmt->Finalize();
00350
00351 return pmt;
00352 }
00353
00354 ProgramMapTable* ProgramMapTable::Create(
00355 uint programNumber, uint basepid, uint pcrpid, uint version,
00356 const desc_list_t &global_desc,
00357 const vector<uint> &pids,
00358 const vector<uint> &types,
00359 const vector<desc_list_t> &prog_desc)
00360 {
00361 const uint count = min(pids.size(), types.size());
00362 ProgramMapTable* pmt = CreateBlank(false);
00363 pmt->tsheader()->SetPID(basepid);
00364
00365 pmt->RemoveAllStreams();
00366 pmt->SetProgramNumber(programNumber);
00367 pmt->SetPCRPID(pcrpid);
00368 pmt->SetVersionNumber(version);
00369
00370 vector<unsigned char> gdesc;
00371 for (uint i=0; i<global_desc.size(); i++)
00372 {
00373 uint len = global_desc[i][1] + 2;
00374 gdesc.insert(gdesc.end(), global_desc[i], global_desc[i] + len);
00375 }
00376 pmt->SetProgramInfo(&gdesc[0], gdesc.size());
00377
00378 for (uint i = 0; i < count; i++)
00379 {
00380 vector<unsigned char> pdesc;
00381 for (uint j = 0; j < prog_desc[i].size(); j++)
00382 {
00383 uint len = prog_desc[i][j][1] + 2;
00384 pdesc.insert(pdesc.end(),
00385 prog_desc[i][j], prog_desc[i][j] + len);
00386 }
00387
00388 pmt->AppendStream(pids[i], types[i], &pdesc[0], pdesc.size());
00389 }
00390 pmt->Finalize();
00391
00392 VERBOSE(VB_SIPARSER, "Created PMT \n"<<pmt->toString());
00393
00394 return pmt;
00395 }
00396
00397 void ProgramMapTable::Parse() const
00398 {
00399 _ptrs.clear();
00400 const unsigned char *cpos = psipdata() + pmt_header + ProgramInfoLength();
00401 unsigned char *pos = const_cast<unsigned char*>(cpos);
00402 for (uint i = 0; pos < psipdata() + Length() - 9; i++)
00403 {
00404 _ptrs.push_back(pos);
00405 pos += 5 + StreamInfoLength(i);
00406
00407
00408 }
00409 _ptrs.push_back(pos);
00410
00411 }
00412
00413 void ProgramMapTable::AppendStream(
00414 uint pid, uint type,
00415 unsigned char* streamInfo, uint infoLength)
00416 {
00417 if (!StreamCount())
00418 _ptrs.push_back(psipdata() + pmt_header + ProgramInfoLength());
00419 memset(_ptrs[StreamCount()], 0xff, 5);
00420 SetStreamPID(StreamCount(), pid);
00421 SetStreamType(StreamCount(), type);
00422 SetStreamProgramInfo(StreamCount(), streamInfo, infoLength);
00423 _ptrs.push_back(_ptrs[StreamCount()]+5+StreamInfoLength(StreamCount()));
00424 SetTotalLength(_ptrs[StreamCount()] - pesdata());
00425 }
00426
00436 bool ProgramMapTable::IsVideo(uint i, QString sistandard) const
00437 {
00438 if (StreamID::IsVideo(StreamType(i)))
00439 return true;
00440
00441 desc_list_t list = MPEGDescriptor::
00442 Parse(StreamInfo(i), StreamInfoLength(i));
00443 uint stream_id = StreamID::Normalize(StreamType(i), list, sistandard);
00444
00445 return StreamID::IsVideo(stream_id);
00446 }
00447
00457 bool ProgramMapTable::IsAudio(uint i, QString sistandard) const
00458 {
00459 if (StreamID::IsAudio(StreamType(i)))
00460 return true;
00461
00462 desc_list_t list = MPEGDescriptor::
00463 Parse(StreamInfo(i), StreamInfoLength(i));
00464 uint stream_id = StreamID::Normalize(StreamType(i), list, sistandard);
00465
00466 return StreamID::IsAudio(stream_id);
00467 }
00468
00472 bool ProgramMapTable::IsEncrypted(void) const
00473 {
00474 bool encrypted = IsProgramEncrypted();
00475
00476 for (uint i = 0; !encrypted && i < StreamCount(); i++)
00477 encrypted |= IsStreamEncrypted(i);
00478
00479 return encrypted;
00480 }
00481
00485 bool ProgramMapTable::IsProgramEncrypted(void) const
00486 {
00487 desc_list_t descs = MPEGDescriptor::ParseOnlyInclude(
00488 ProgramInfo(), ProgramInfoLength(), DescriptorID::conditional_access);
00489
00490 bool encrypted = false;
00491 QMap<uint,uint> encryption_system;
00492 for (uint i = 0; i < descs.size(); i++)
00493 {
00494 ConditionalAccessDescriptor cad(descs[i]);
00495 encryption_system[cad.PID()] = cad.SystemID();
00496 encrypted |= cad.SystemID();
00497
00498
00499 }
00500
00501 return encrypted;
00502 }
00503
00509 bool ProgramMapTable::IsStreamEncrypted(uint i) const
00510 {
00511 desc_list_t descs = MPEGDescriptor::ParseOnlyInclude(
00512 StreamInfo(i), StreamInfoLength(i), DescriptorID::conditional_access);
00513
00514 bool encrypted = false;
00515 QMap<uint,uint> encryption_system;
00516 for (uint j = 0; j < descs.size(); j++)
00517 {
00518 ConditionalAccessDescriptor cad(descs[j]);
00519 encryption_system[cad.PID()] = cad.SystemID();
00520 encrypted |= cad.SystemID();
00521
00522
00523 }
00524
00525 return encrypted;
00526 }
00527
00528 bool ProgramMapTable::IsStillPicture(QString sistandard) const
00529 {
00530 static const unsigned char STILL_PICTURE_FLAG = 0x01;
00531
00532 for (uint i = 0; i < StreamCount(); i++)
00533 {
00534 if (IsVideo(i, sistandard))
00535 {
00536 return StreamInfoLength(i) > 2 &&
00537 (StreamInfo(i)[2] & STILL_PICTURE_FLAG);
00538 }
00539 }
00540 return false;
00541 }
00542
00543
00552 uint ProgramMapTable::FindPIDs(uint type,
00553 vector<uint> &pids,
00554 const QString &sistandard) const
00555 {
00556 if ((StreamID::AnyMask & type) != StreamID::AnyMask)
00557 {
00558 for (uint i=0; i < StreamCount(); i++)
00559 if (type == StreamType(i))
00560 pids.push_back(StreamPID(i));
00561 }
00562 else if (StreamID::AnyVideo == type)
00563 {
00564 for (uint i=0; i < StreamCount(); i++)
00565 if (IsVideo(i, sistandard))
00566 pids.push_back(StreamPID(i));
00567 }
00568 else if (StreamID::AnyAudio == type)
00569 {
00570 for (uint i=0; i < StreamCount(); i++)
00571 if (IsAudio(i, sistandard))
00572 pids.push_back(StreamPID(i));
00573 }
00574
00575 return pids.size();
00576 }
00577
00588 uint ProgramMapTable::FindPIDs(uint type,
00589 vector<uint> &pids,
00590 vector<uint> &types,
00591 const QString &sistandard,
00592 bool normalize) const
00593 {
00594 uint pids_start = pids.size();
00595
00596 if ((StreamID::AnyMask & type) != StreamID::AnyMask)
00597 {
00598 for (uint i=0; i < StreamCount(); i++)
00599 if (type == StreamType(i))
00600 {
00601 pids.push_back(StreamPID(i));
00602 types.push_back(StreamType(i));
00603 }
00604 }
00605 else if (StreamID::AnyVideo == type)
00606 {
00607 for (uint i=0; i < StreamCount(); i++)
00608 if (IsVideo(i, sistandard))
00609 {
00610 pids.push_back(StreamPID(i));
00611 types.push_back(StreamType(i));
00612 }
00613 }
00614 else if (StreamID::AnyAudio == type)
00615 {
00616 for (uint i=0; i < StreamCount(); i++)
00617 if (IsAudio(i, sistandard))
00618 {
00619 pids.push_back(StreamPID(i));
00620 types.push_back(StreamType(i));
00621 }
00622 }
00623
00624 if (!normalize)
00625 return pids.size();
00626
00627 for (uint i = pids_start; i < pids.size(); i++)
00628 {
00629 int index = FindPID(pids[i]);
00630 if (index >= 0)
00631 {
00632 desc_list_t desc = MPEGDescriptor::Parse(
00633 StreamInfo(i), StreamInfoLength(i));
00634 types[i] = StreamID::Normalize(types[i], desc, sistandard);
00635 }
00636 }
00637
00638 return pids.size();
00639 }
00640
00641 uint ProgramMapTable::FindUnusedPID(uint desired_pid)
00642 {
00643 uint pid = desired_pid;
00644 while (FindPID(pid) >= 0)
00645 pid += 0x10;
00646
00647 if (desired_pid <= 0x1fff)
00648 return pid;
00649
00650 pid = desired_pid;
00651 while (FindPID(desired_pid) >= 0)
00652 desired_pid += 1;
00653
00654 if (desired_pid <= 0x1fff)
00655 return pid;
00656
00657 pid = 0x20;
00658 while (FindPID(desired_pid) >= 0)
00659 desired_pid += 1;
00660
00661 return desired_pid & 0x1fff;
00662 }
00663
00664 const QString PSIPTable::toString() const
00665 {
00666 QString str;
00667 str.append(QString(" PSIP tableID(0x%1) length(%2) extension(0x%3)\n")
00668 .arg(TableID(), 0, 16).arg(Length())
00669 .arg(TableIDExtension(), 0, 16));
00670 str.append(QString(" version(%1) current(%2) "
00671 "section(%3) last_section(%4)\n")
00672 .arg(Version()).arg(IsCurrent())
00673 .arg(Section()).arg(LastSection()));
00674
00675 return str;
00676 }
00677
00678 const QString ProgramAssociationTable::toString() const
00679 {
00680 QString str;
00681 str.append(QString("Program Association Table\n"));
00682 str.append(static_cast<const PSIPTable*>(this)->toString());
00683 str.append(QString(" tsid: %1\n").arg(TransportStreamID()));
00684 str.append(QString(" programCount: %1\n").arg(ProgramCount()));
00685
00686 uint cnt0 = 0, cnt1fff = 0;
00687 for (uint i = 0; i < ProgramCount(); i++)
00688 {
00689 const unsigned char* p = psipdata() + (i<<2);
00690
00691 if (0x1fff == ProgramPID(i))
00692 {
00693 cnt1fff++;
00694 continue;
00695 }
00696
00697 if (0x0 == ProgramPID(i))
00698 {
00699 cnt0++;
00700 continue;
00701 }
00702
00703 str.append(QString(" program number %1").arg(ProgramNumber(i),5)).
00704 append(QString(" has PID 0x%1 data ").arg(ProgramPID(i),4,16)).
00705 append(QString(" 0x%1 0x%2").arg(p[0],2,16).arg(p[1],2,16)).
00706 append(QString(" 0x%1 0x%2\n").arg(p[2],2,16).arg(p[3],2,16));
00707 }
00708
00709 if (cnt0 || cnt1fff)
00710 {
00711 str.append(QString(" also contains %1 + %2 dummy programs\n")
00712 .arg(cnt0).arg(cnt1fff));
00713 }
00714
00715 return str;
00716 }
00717
00718 const QString ProgramMapTable::toString() const
00719 {
00720 QString str =
00721 QString("Program Map Table ver(%1) pid(0x%2) pnum(%3) len(%4)\n")
00722 .arg(Version()).arg(tsheader()->PID(), 0, 16)
00723 .arg(ProgramNumber()).arg(Length());
00724
00725 if (0 != StreamCount())
00726 {
00727 vector<const unsigned char*> desc =
00728 MPEGDescriptor::Parse(ProgramInfo(), ProgramInfoLength());
00729 for (uint i=0; i<desc.size(); i++)
00730 str.append(QString(" %1\n")
00731 .arg(MPEGDescriptor(desc[i]).toString()));
00732 }
00733 str.append("\n");
00734 for (uint i = 0; i < StreamCount(); i++)
00735 {
00736 str.append(QString(" Stream #%1 pid(0x%2) type(%3 0x%4)\n")
00737 .arg(i).arg(StreamPID(i), 0, 16)
00738 .arg(StreamTypeString(i)).arg(StreamType(i), 0, 16));
00739 if (0 != StreamInfoLength(i))
00740 {
00741 vector<const unsigned char*> desc =
00742 MPEGDescriptor::Parse(StreamInfo(i), StreamInfoLength(i));
00743 for (uint i=0; i<desc.size(); i++)
00744 str.append(QString(" %1\n")
00745 .arg(MPEGDescriptor(desc[i]).toString()));
00746 }
00747 }
00748 return str;
00749 }
00750
00751 const char *StreamID::toString(uint streamID)
00752 {
00753
00754 char* retval = "unknown";
00755
00756
00757 if (StreamID::MPEG2Video==streamID)
00758 return "video-mpeg2";
00759 else if (StreamID::MPEG1Video==streamID)
00760 return "video-mpeg1";
00761 else if (StreamID::MPEG4Video==streamID)
00762 return "video-mpeg4";
00763 else if (StreamID::H264Video==streamID)
00764 return "video-h264";
00765 else if (StreamID::OpenCableVideo==streamID)
00766 return "video-opencable";
00767
00768
00769 else if (StreamID::AC3Audio==streamID)
00770 return "audio-ac3";
00771 else if (StreamID::MPEG2Audio==streamID)
00772 return "audio-mp2-layer[1,2,3]";
00773 else if (StreamID::MPEG1Audio==streamID)
00774 return "audio-mp1-layer[1,2,3]";
00775 else if (StreamID::AACAudio==streamID)
00776 return "audio-aac";
00777 else if (StreamID::DTSAudio==streamID)
00778 return "audio-dts";
00779
00780
00781 else if (StreamID::PrivSec==streamID)
00782 return "private-sec";
00783 else if (StreamID::PrivData==streamID)
00784 return "private-data";
00785
00786
00787 else if (StreamID::DSMCC_A==streamID)
00788 return "dsmcc-a encap";
00789 else if (StreamID::DSMCC_B==streamID)
00790 return "dsmcc-b std data";
00791 else if (StreamID::DSMCC_C==streamID)
00792 return "dsmcc-c NPD data";
00793 else if (StreamID::DSMCC_D==streamID)
00794 return "dsmcc-d data";
00795
00796 else switch (streamID)
00797 {
00798 case (TableID::STUFFING):
00799 retval="stuffing"; break;
00800 case (TableID::CAPTION):
00801 retval="caption service"; break;
00802 case (TableID::CENSOR):
00803 retval="censor"; break;
00804 case (TableID::ECN):
00805 retval="extended channel name"; break;
00806 case (TableID::SRVLOC):
00807 retval="service location"; break;
00808 case (TableID::TSS):
00809 retval="time-shifted service"; break;
00810 case (TableID::CMPNAME): retval="component name"; break;
00811 }
00812 return retval;
00813 }
00814
00815 QString ProgramMapTable::GetLanguage(uint i) const
00816 {
00817 const desc_list_t list = MPEGDescriptor::Parse(
00818 StreamInfo(i), StreamInfoLength(i));
00819 const unsigned char *lang_desc = MPEGDescriptor::Find(
00820 list, DescriptorID::ISO_639_language);
00821
00822 if (!lang_desc)
00823 return QString::null;
00824
00825 ISO639LanguageDescriptor iso_lang(lang_desc);
00826 return iso_lang.CanonicalLanguageString();
00827 }
00828
00829 QString ProgramMapTable::StreamDescription(uint i, QString sistandard) const
00830 {
00831 desc_list_t list;
00832
00833 list = MPEGDescriptor::Parse(StreamInfo(i), StreamInfoLength(i));
00834 uint type = StreamID::Normalize(StreamType(i), list, sistandard);
00835 QString desc = StreamID::toString(type);
00836 QString lang = GetLanguage(i);
00837
00838 if (!lang.isEmpty())
00839 desc += QString(" (%1)").arg(lang);
00840
00841 return desc;
00842 }