MythTV  0.26-pre
mpegtables.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 // Copyright (c) 2003-2004, Daniel Thor Kristjansson
00003 
00004 #include "splicedescriptors.h"
00005 #include "atscdescriptors.h"
00006 #include "mythlogging.h"
00007 #include "mpegtables.h"
00008 #include "mythmiscutil.h" // for xml_indent
00009 
00010 const unsigned char DEFAULT_PAT_HEADER[8] =
00011 {
00012     0x00, // TableID::PAT
00013     0xb0, // Syntax indicator
00014     0x00, // Length (set seperately)
00015     0x00, // Transport stream ID top bits
00016 
00017     0x00, // Transport stream ID bottom bits
00018     0xc1, // current | reserved
00019     0x00, // Current Section
00020     0x00, // Last Section
00021 };
00022 
00023 const unsigned char DEFAULT_PMT_HEADER[12] =
00024 {
00025     0x02, // TableID::PMT
00026     0xb0, // Syntax indicator
00027     0x00, // Length (set seperately)
00028     0x00, // MPEG Program number top bits (set seperately)
00029 
00030     0x00, // MPEG Program number bottom bits (set seperately)
00031     0xc1, // Version + Current/Next
00032     0x00, // Current Section
00033     0x00, // Last Section
00034     0xff, 0xff, // PCR pid
00035     0x00, 0x00, // Program Info Length
00036 };
00037 
00038 static const uint len_for_alloc[] =
00039 {
00040     TSPacket::kPayloadSize
00041     - 1 /* for start of field pointer */
00042     - 3 /* for data before data last byte of pes length */,
00043     4000,
00044 };
00045 
00046 uint StreamID::Normalize(uint stream_id, const desc_list_t &desc,
00047                          const QString &sistandard)
00048 {
00049     if ((sistandard != "dvb") && (OpenCableVideo == stream_id))
00050         return MPEG2Video;
00051 
00052     if (MPEGDescriptor::Find(desc, DescriptorID::ac3))
00053         return AC3Audio;
00054 
00055     QString reg;
00056     const unsigned char *d = MPEGDescriptor::Find(
00057         desc, DescriptorID::registration);
00058     if (d)
00059     {
00060         RegistrationDescriptor rd(d);
00061         if (rd.IsValid())
00062             reg = rd.FormatIdentifierString();
00063     }
00064 
00065     if (reg == "DTS1")
00066         return DTSAudio;
00067 
00068 #if 0
00069     // not needed while there is no specific stream id for these
00070     if (MPEGDescriptor::Find(desc, DescriptorID::teletext) ||
00071         MPEGDescriptor::Find(desc, DescriptorID::subtitling))
00072         return stream_id;
00073 #endif
00074 
00075     return stream_id;
00076 }
00077 
00078 bool PSIPTable::HasCRC(void) const
00079 {
00080     bool has_crc = false;
00081 
00082     switch (TableID())
00083     {
00084         // MPEG
00085         case TableID::PAT:
00086         case TableID::CAT:
00087         case TableID::PMT:
00088             has_crc = true;
00089             break;
00090 //      case TableID::TSDT
00091 
00092         // DVB manditory
00093         case TableID::NIT:
00094         case TableID::SDT:
00095         case TableID::PF_EIT:
00096             has_crc = true;
00097             break;
00098         case TableID::TDT:
00099             has_crc = false;
00100             break;
00101 
00102         // DVB optional
00103         case TableID::NITo:
00104         case TableID::SDTo:
00105         case TableID::BAT:
00106         case TableID::PF_EITo:
00107             has_crc = true;
00108             break;
00109         case TableID::RST:
00110         case TableID::ST:
00111             has_crc = false;
00112             break;
00113         case TableID::TOT:
00114             has_crc = true;
00115             break;
00116 //      case TableID::RNT:
00117 //      case TableID::CT:
00118 //      case TableID::RCT:
00119 //      case TableID::CIT:
00120 //      case TableID::MPEFEC:
00121         case TableID::DIT:
00122             has_crc = false;
00123             break;
00124         case TableID::SIT:
00125             has_crc = true;
00126             break;
00127 
00128         // SCTE
00129         case TableID::NITscte:
00130         case TableID::NTT:
00131         case TableID::SVCTscte:
00132         case TableID::STTscte:
00133         case TableID::SITscte:
00134             has_crc = true;
00135             break;
00136         case TableID::ADET:
00137             has_crc = false;
00138             break;
00139 
00140         // ATSC
00141         case TableID::MGT:
00142         case TableID::TVCT:
00143         case TableID::CVCT:
00144         case TableID::RRT:
00145         case TableID::EIT:
00146         case TableID::ETT:
00147         case TableID::STT:
00148         case TableID::DET:
00149         case TableID::DST:
00150 
00151         //case TableID::PIT:
00152         case TableID::NRT:
00153         case TableID::LTST:
00154         case TableID::DCCT:
00155         case TableID::DCCSCT:
00156         //case TableID::SITatsc:
00157         case TableID::AEIT:
00158         case TableID::AETT:
00159         case TableID::SVCT:
00160             has_crc = true;
00161             break;
00162 
00163         default:
00164         {
00165             // DVB Longterm EIT data
00166             if (TableID::SC_EITbeg <= TableID() &&
00167                 TableID() <= TableID::SC_EITendo)
00168             {
00169                 has_crc = true;
00170             }
00171 
00172             // Dishnet Longterm EIT data
00173             if (TableID::DN_EITbego <= TableID() &&
00174                 TableID() <= TableID::DN_EITendo)
00175             {
00176                 has_crc = true;
00177             }
00178         }
00179         break;
00180     }
00181 
00182     return has_crc;
00183 }
00184 
00185 bool PSIPTable::HasSectionNumber(void) const
00186 {
00187     bool has_sn = false;
00188     switch (TableID())
00189     {
00190         // MPEG
00191         case TableID::PAT:
00192         case TableID::CAT:
00193         case TableID::PMT:
00194         // ATSC
00195         case TableID::MGT:
00196         case TableID::TVCT:
00197         case TableID::CVCT:
00198         case TableID::RRT:
00199         case TableID::EIT:
00200         case TableID::ETT:
00201         case TableID::STT:
00202         case TableID::DET:
00203         case TableID::DST:
00204             has_sn = true;
00205             break;
00206     }
00207 
00208     return has_sn;
00209 }
00210 
00211 bool PSIPTable::VerifyPSIP(bool verify_crc) const
00212 {
00213     if (verify_crc && (CalcCRC() != CRC()))
00214     {
00215         LOG(VB_SIPARSER, LOG_ERR,
00216             QString("PSIPTable: Failed CRC check 0x%1 != 0x%2 "
00217                     "for StreamID = 0x%3")
00218                 .arg(CRC(),0,16).arg(CalcCRC(),0,16).arg(StreamID(),0,16));
00219         return false;
00220     }
00221 
00222     unsigned char *bufend = _fullbuffer + _allocSize;
00223 
00224     if ((_pesdata + 2) >= bufend)
00225         return false; // can't query length
00226 
00227     if (psipdata() >= bufend)
00228         return false; // data outside buffer
00229 
00230     if (TableID::PAT == TableID())
00231     {
00232         uint pcnt = (SectionLength() - PSIP_OFFSET - 2) >> 2;
00233         bool ok = (psipdata() + (pcnt << 2) + 3 < bufend);
00234         if (!ok)
00235         {
00236             LOG(VB_SIPARSER, LOG_ERR,
00237                 "PSIPTable: PAT: program list extends past end of buffer");
00238             return false;
00239         }
00240 
00241         if ((Length() == 0xfff) && (TableIDExtension() == 0xffff) &&
00242             (Section() == 0xff) && (LastSection() == 0xff))
00243         {
00244             LOG(VB_SIPARSER, LOG_ERR, "PSIPTable: PAT: All values at maximums");
00245             return false;
00246         }
00247 
00248         return true;
00249     }
00250 
00251     if (TableID::PMT == TableID())
00252     {
00253         if (psipdata() + 3 >= bufend)
00254         {
00255             LOG(VB_SIPARSER, LOG_ERR,
00256                 "PSIPTable: PMT: can't query program info length");
00257             return false;
00258         }
00259 
00260         if (psipdata() + Length() - 9 > bufend)
00261         {
00262             LOG(VB_SIPARSER, LOG_ERR,
00263                 "PSIPTable: PMT: reported length too large");
00264             return false;
00265         }
00266 
00267         uint proginfolen = ((psipdata()[2]<<8) | psipdata()[3]) & 0x0fff;
00268         const unsigned char *proginfo = psipdata() + 4;
00269         const unsigned char *cpos = proginfo + proginfolen;
00270         if (cpos > bufend)
00271         {
00272             LOG(VB_SIPARSER, LOG_ERR,
00273                 "PSIPTable: PMT: program info extends past end of buffer");
00274             return false;
00275         }
00276 
00277         vector<unsigned char*> _ptrs;
00278         const unsigned char *pos = cpos;
00279         uint i = 0;
00280         for (; pos < psipdata() + Length() - 9; i++)
00281         {
00282             const unsigned char *ptr = pos;
00283             if (pos + 4 > bufend)
00284             {
00285                 LOG(VB_SIPARSER, LOG_ERR,
00286                     QString("PSIPTable: PMT: stream info %1 extends "
00287                             "past end of buffer").arg(i));
00288                 return false;
00289             }
00290             pos += 5 + (((ptr[3] << 8) | ptr[4]) & 0x0fff);
00291         }
00292         if (pos > bufend)
00293         {
00294             LOG(VB_SIPARSER, LOG_ERR,
00295                 QString("PSIPTable: PMT: last stream info %1 extends "
00296                         "past end of buffer").arg(i));
00297             return false;
00298         }
00299 
00300         return true;
00301     }
00302 
00303     return true;
00304 }
00305 
00306 ProgramAssociationTable* ProgramAssociationTable::CreateBlank(bool smallPacket)
00307 {
00308     (void) smallPacket; // currently always a small packet..
00309     TSPacket *tspacket = TSPacket::CreatePayloadOnlyPacket();
00310     memcpy(tspacket->data() + sizeof(TSHeader) + 1/* start of field pointer */,
00311            DEFAULT_PAT_HEADER, sizeof(DEFAULT_PAT_HEADER));
00312     PSIPTable psip = PSIPTable::View(*tspacket);
00313     psip.SetLength(TSPacket::kPayloadSize
00314                    - 1 /* for start of field pointer */
00315                    - 3 /* for data before data last byte of pes length */);
00316     ProgramAssociationTable *pat = new ProgramAssociationTable(psip);
00317     pat->SetTotalLength(sizeof(DEFAULT_PAT_HEADER));
00318     delete tspacket;
00319     return pat;
00320 }
00321 
00322 ProgramAssociationTable* ProgramAssociationTable::Create(
00323     uint tsid, uint version,
00324     const vector<uint>& pnum, const vector<uint>& pid)
00325 {
00326     const uint count = min(pnum.size(), pid.size());
00327     ProgramAssociationTable* pat = CreateBlank();
00328     pat->SetVersionNumber(version);
00329     pat->SetTranportStreamID(tsid);
00330     pat->SetTotalLength(PSIP_OFFSET + (count * 4));
00331 
00332     // create PAT data
00333     if ((count * 4) >= (184 - (PSIP_OFFSET+1)))
00334     { // old PAT must be in single TS for this create function
00335         LOG(VB_GENERAL, LOG_ERR,
00336             "PAT::Create: Error, old PAT size exceeds maximum PAT size.");
00337         delete pat;
00338         return 0;
00339     }
00340 
00341     uint offset = PSIP_OFFSET;
00342     for (uint i = 0; i < count; i++)
00343     {
00344         // pnum
00345         pat->pesdata()[offset++] = pnum[i]>>8;
00346         pat->pesdata()[offset++] = pnum[i] & 0xff;
00347         // pid
00348         pat->pesdata()[offset++] = ((pid[i]>>8) & 0x1f) | 0xe0;
00349         pat->pesdata()[offset++] = pid[i] & 0xff;
00350     }
00351 
00352     pat->Finalize();
00353 
00354     return pat;
00355 }
00356 
00357 ProgramMapTable* ProgramMapTable::CreateBlank(bool smallPacket)
00358 {
00359     ProgramMapTable *pmt = NULL;
00360     TSPacket *tspacket = TSPacket::CreatePayloadOnlyPacket();
00361     memcpy(tspacket->data() + sizeof(TSHeader) + 1/* start of field pointer */,
00362            DEFAULT_PMT_HEADER, sizeof(DEFAULT_PMT_HEADER));
00363 
00364     if (smallPacket)
00365     {
00366         PSIPTable psip = PSIPTable::View(*tspacket);
00367         psip.SetLength(len_for_alloc[0]);
00368         pmt = new ProgramMapTable(psip);
00369     }
00370     else
00371     {
00372         PSIPTable psip(*tspacket);
00373         psip.SetLength(len_for_alloc[1]);
00374         pmt = new ProgramMapTable(psip);
00375     }
00376 
00377     pmt->SetTotalLength(sizeof(DEFAULT_PMT_HEADER));
00378     delete tspacket;
00379     return pmt;
00380 }
00381 
00382 ProgramMapTable* ProgramMapTable::Create(
00383     uint programNumber, uint basepid, uint pcrpid, uint version,
00384     vector<uint> pids, vector<uint> types)
00385 {
00386     const uint count = min(pids.size(), types.size());
00387     ProgramMapTable* pmt = CreateBlank(false);
00388     pmt->tsheader()->SetPID(basepid);
00389 
00390     pmt->RemoveAllStreams();
00391     pmt->SetProgramNumber(programNumber);
00392     pmt->SetPCRPID(pcrpid);
00393     pmt->SetVersionNumber(version);
00394 
00395     for (uint i=0; i<count; i++)
00396         pmt->AppendStream(pids[i], types[i]);
00397     pmt->Finalize();
00398 
00399     return pmt;
00400 }
00401 
00402 ProgramMapTable* ProgramMapTable::Create(
00403     uint programNumber, uint basepid, uint pcrpid, uint version,
00404     const desc_list_t         &global_desc,
00405     const vector<uint>        &pids,
00406     const vector<uint>        &types,
00407     const vector<desc_list_t> &prog_desc)
00408 {
00409     const uint count = min(pids.size(), types.size());
00410     ProgramMapTable* pmt = CreateBlank(false);
00411     pmt->tsheader()->SetPID(basepid);
00412 
00413     pmt->RemoveAllStreams();
00414     pmt->SetProgramNumber(programNumber);
00415     pmt->SetPCRPID(pcrpid);
00416     pmt->SetVersionNumber(version);
00417 
00418     vector<unsigned char> gdesc;
00419     for (uint i=0; i<global_desc.size(); i++)
00420     {
00421         uint len = global_desc[i][1] + 2;
00422         gdesc.insert(gdesc.end(), global_desc[i], global_desc[i] + len);
00423     }
00424     pmt->SetProgramInfo(&gdesc[0], gdesc.size());
00425 
00426     for (uint i = 0; i < count; i++)
00427     {
00428         vector<unsigned char> pdesc;
00429         for (uint j = 0; j < prog_desc[i].size(); j++)
00430         {
00431             uint len = prog_desc[i][j][1] + 2;
00432             pdesc.insert(pdesc.end(),
00433                          prog_desc[i][j], prog_desc[i][j] + len);
00434         }
00435 
00436         pmt->AppendStream(pids[i], types[i], &pdesc[0], pdesc.size());
00437     }
00438     pmt->Finalize();
00439 
00440     LOG(VB_SIPARSER, LOG_INFO, "Created PMT \n" + pmt->toString());
00441 
00442     return pmt;
00443 }
00444 
00445 void ProgramMapTable::Parse() const
00446 {
00447     _ptrs.clear();
00448     const unsigned char *cpos = psipdata() + pmt_header + ProgramInfoLength();
00449     unsigned char *pos = const_cast<unsigned char*>(cpos);
00450     for (uint i = 0; pos < psipdata() + Length() - 9; i++)
00451     {
00452         _ptrs.push_back(pos);
00453         pos += 5 + StreamInfoLength(i);
00454 #if 0
00455         LOG(VB_SIPARSER, LOG_DEBUG, QString("Parsing PMT(0x%1) i(%2) len(%3)")
00456                 .arg((uint64_t)this, 0, 16) .arg(i) .arg(StreamInfoLength(i)));
00457 #endif
00458     }
00459     _ptrs.push_back(pos);
00460 #if 0
00461     LOG(VB_SIPARSER, LOG_DEBUG, QString("Parsed PMT(0x%1)\n%2")
00462             .arg((uint64_t)this, 0, 16) .arg(toString()));
00463 #endif
00464 }
00465 
00466 void ProgramMapTable::AppendStream(
00467     uint pid, uint type,
00468     unsigned char* streamInfo, uint infoLength)
00469 {
00470     if (!StreamCount())
00471         _ptrs.push_back(psipdata() + pmt_header + ProgramInfoLength());
00472     memset(_ptrs[StreamCount()], 0xff, 5);
00473     SetStreamPID(StreamCount(), pid);
00474     SetStreamType(StreamCount(), type);
00475     SetStreamProgramInfo(StreamCount(), streamInfo, infoLength);
00476     _ptrs.push_back(_ptrs[StreamCount()]+5+StreamInfoLength(StreamCount()));
00477     SetTotalLength(_ptrs[StreamCount()] - pesdata());
00478 }
00479 
00489 bool ProgramMapTable::IsVideo(uint i, QString sistandard) const
00490 {
00491     if (StreamID::IsVideo(StreamType(i)))
00492         return true;
00493 
00494     desc_list_t list = MPEGDescriptor::
00495         Parse(StreamInfo(i), StreamInfoLength(i));
00496     uint stream_id = StreamID::Normalize(StreamType(i), list, sistandard);
00497 
00498     return StreamID::IsVideo(stream_id);
00499 }
00500 
00510 bool ProgramMapTable::IsAudio(uint i, QString sistandard) const
00511 {
00512     if (StreamID::IsAudio(StreamType(i)))
00513         return true;
00514 
00515     desc_list_t list = MPEGDescriptor::
00516         Parse(StreamInfo(i), StreamInfoLength(i));
00517     uint stream_id = StreamID::Normalize(StreamType(i), list, sistandard);
00518 
00519     return StreamID::IsAudio(stream_id);
00520 }
00521 
00525 bool ProgramMapTable::IsEncrypted(QString sistandard) const
00526 {
00527     bool encrypted = IsProgramEncrypted();
00528 
00529     for (uint i = 0; !encrypted && i < StreamCount(); i++) {
00530     /* Only check audio/video streams */
00531         if (IsAudio(i,sistandard) || IsVideo(i,sistandard))
00532             encrypted |= IsStreamEncrypted(i);
00533     }
00534 
00535     return encrypted;
00536 }
00537 
00541 bool ProgramMapTable::IsProgramEncrypted(void) const
00542 {
00543     desc_list_t descs = MPEGDescriptor::ParseOnlyInclude(
00544         ProgramInfo(), ProgramInfoLength(), DescriptorID::conditional_access);
00545 
00546     uint encrypted = 0;
00547     QMap<uint,uint> encryption_system;
00548     for (uint i = 0; i < descs.size(); i++)
00549     {
00550         ConditionalAccessDescriptor cad(descs[i]);
00551         encryption_system[cad.PID()] = cad.SystemID();
00552         encrypted |= cad.SystemID();
00553 
00554 #if 0
00555         LOG(VB_GENERAL, LOG_INFO, "DTVsm: " + cad.toString());
00556 #endif
00557     }
00558 
00559     return encrypted != 0;
00560 }
00561 
00567 bool ProgramMapTable::IsStreamEncrypted(uint i) const
00568 {
00569     desc_list_t descs = MPEGDescriptor::ParseOnlyInclude(
00570         StreamInfo(i), StreamInfoLength(i), DescriptorID::conditional_access);
00571 
00572     uint encrypted = 0;
00573     QMap<uint,uint> encryption_system;
00574     for (uint j = 0; j < descs.size(); j++)
00575     {
00576         ConditionalAccessDescriptor cad(descs[j]);
00577         encryption_system[cad.PID()] = cad.SystemID();
00578         encrypted |= cad.SystemID();
00579 
00580 #if 0
00581         LOG(VB_GENERAL, LOG_INFO, "DTVsm: " + cad.toString());
00582 #endif
00583     }
00584 
00585     return encrypted != 0;
00586 }
00587 
00588 bool ProgramMapTable::IsStillPicture(QString sistandard) const
00589 {
00590     static const unsigned char STILL_PICTURE_FLAG = 0x01;
00591 
00592     for (uint i = 0; i < StreamCount(); i++)
00593     {
00594         if (IsVideo(i, sistandard))
00595         {
00596             return StreamInfoLength(i) > 2 &&
00597                    (StreamInfo(i)[2] & STILL_PICTURE_FLAG);
00598         }
00599     }
00600     return false;
00601 }
00602 
00603 
00612 uint ProgramMapTable::FindPIDs(uint           type,
00613                                vector<uint>  &pids,
00614                                const QString &sistandard) const
00615 {
00616     if ((StreamID::AnyMask & type) != StreamID::AnyMask)
00617     {
00618         for (uint i=0; i < StreamCount(); i++)
00619             if (type == StreamType(i))
00620                 pids.push_back(StreamPID(i));
00621     }
00622     else if (StreamID::AnyVideo == type)
00623     {
00624         for (uint i=0; i < StreamCount(); i++)
00625             if (IsVideo(i, sistandard))
00626                 pids.push_back(StreamPID(i));
00627     }
00628     else if (StreamID::AnyAudio == type)
00629     {
00630         for (uint i=0; i < StreamCount(); i++)
00631             if (IsAudio(i, sistandard))
00632                 pids.push_back(StreamPID(i));
00633     }
00634 
00635     return pids.size();
00636 }
00637 
00648 uint ProgramMapTable::FindPIDs(uint           type,
00649                                vector<uint>  &pids,
00650                                vector<uint>  &types,
00651                                const QString &sistandard,
00652                                bool           normalize) const
00653 {
00654     uint pids_start = pids.size();
00655 
00656     if ((StreamID::AnyMask & type) != StreamID::AnyMask)
00657     {
00658         for (uint i=0; i < StreamCount(); i++)
00659             if (type == StreamType(i))
00660             {
00661                 pids.push_back(StreamPID(i));
00662                 types.push_back(StreamType(i));
00663             }
00664     }
00665     else if (StreamID::AnyVideo == type)
00666     {
00667         for (uint i=0; i < StreamCount(); i++)
00668             if (IsVideo(i, sistandard))
00669             {
00670                 pids.push_back(StreamPID(i));
00671                 types.push_back(StreamType(i));
00672             }
00673     }
00674     else if (StreamID::AnyAudio == type)
00675     {
00676         for (uint i=0; i < StreamCount(); i++)
00677             if (IsAudio(i, sistandard))
00678             {
00679                 pids.push_back(StreamPID(i));
00680                 types.push_back(StreamType(i));
00681             }
00682     }
00683 
00684     if (!normalize)
00685         return pids.size();
00686 
00687     for (uint i = pids_start; i < pids.size(); i++)
00688     {
00689         int index = FindPID(pids[i]);
00690         if (index >= 0)
00691         {
00692             desc_list_t desc = MPEGDescriptor::Parse(
00693                 StreamInfo(i), StreamInfoLength(i));
00694             types[i] = StreamID::Normalize(types[i], desc, sistandard);
00695         }
00696     }
00697 
00698     return pids.size();
00699 }
00700 
00701 uint ProgramMapTable::FindUnusedPID(uint desired_pid)
00702 {
00703     uint pid = desired_pid;
00704     while (FindPID(pid) >= 0)
00705         pid += 0x10;
00706 
00707     if (desired_pid <= 0x1fff)
00708         return pid;
00709 
00710     pid = desired_pid;
00711     while (FindPID(desired_pid) >= 0)
00712         desired_pid += 1;
00713 
00714     if (desired_pid <= 0x1fff)
00715         return pid;
00716 
00717     pid = 0x20;
00718     while (FindPID(desired_pid) >= 0)
00719         desired_pid += 1;
00720 
00721     return desired_pid & 0x1fff;
00722 }
00723 
00724 QString PSIPTable::toString(void) const
00725 {
00726     QString str;
00727     str.append(QString(" PSIP tableID(0x%1) length(%2) extension(0x%3)\n")
00728                .arg(TableID(), 0, 16).arg(Length())
00729                .arg(TableIDExtension(), 0, 16));
00730     str.append(QString("      version(%1) current(%2) "
00731                        "section(%3) last_section(%4)\n")
00732                .arg(Version()).arg(IsCurrent())
00733                .arg(Section()).arg(LastSection()));
00734     if ((TableID() >= TableID::MGT) && (TableID() <= TableID::SRM))
00735     {
00736         str.append(QString("      atsc_protocol_version(%1)\n")
00737                    .arg(ATSCProtocolVersion()));
00738     }
00739     return str;
00740 }
00741 
00742 QString PSIPTable::toStringXML(uint indent_level) const
00743 {
00744     QString indent = xml_indent(indent_level);
00745     return indent + "<PSIPSection " + XMLValues(indent_level + 1) + " />";
00746 }
00747 
00748 QString PSIPTable::XMLValues(uint indent_level) const
00749 {
00750     QString indent = xml_indent(indent_level);
00751 
00752     QString str = QString(
00753         "table_id=\"0x%1\" length=\"%2\"")
00754         .arg(TableID(), 2, 16, QChar('0'))
00755         .arg(Length());
00756 
00757     if (HasSectionNumber())
00758     {
00759         str += QString(" section=\"%4\" last_section=\"%5\"")
00760             .arg(Section()).arg(LastSection());
00761     }
00762 
00763     if ((TableID() >= TableID::MGT) && (TableID() <= TableID::SRM))
00764     {
00765         str += QString("\n%1version=\"%2\" current=\"%3\" "
00766                        "protocol_version=\"%4\" extension=\"0x%5\"")
00767             .arg(indent)
00768             .arg(Version()).arg(xml_bool_to_string(IsCurrent()))
00769             .arg(ATSCProtocolVersion())
00770             .arg(TableIDExtension(), 0, 16);
00771     }
00772 
00773     return str;
00774 }
00775 
00776 QString ProgramAssociationTable::toString(void) const
00777 {
00778     QString str;
00779     str.append(QString("Program Association Section\n"));
00780     str.append(PSIPTable::toString());
00781     str.append(QString("      tsid(%1) ").arg(TransportStreamID()));
00782     str.append(QString("programCount(%1)\n").arg(ProgramCount()));
00783 
00784     uint cnt0 = 0, cnt1fff = 0;
00785     for (uint i = 0; i < ProgramCount(); i++)
00786     {
00787         if (0x1fff == ProgramPID(i))
00788         {
00789             cnt1fff++;
00790             continue;
00791         }
00792 
00793         if (0x0 == ProgramPID(i))
00794         {
00795             cnt0++;
00796             continue;
00797         }
00798 
00799         str += QString("  program number %1 has PID 0x%2\n")
00800             .arg(ProgramNumber(i),5)
00801             .arg(ProgramPID(i),4,16,QChar('0'));
00802     }
00803 
00804     if (cnt0 || cnt1fff)
00805     {
00806         str.append(QString("  also contains %1 dummy programs\n")
00807                    .arg(cnt0 + cnt1fff));
00808     }
00809 
00810     return str;
00811 }
00812 
00813 QString ProgramAssociationTable::toStringXML(uint indent_level) const
00814 {
00815     QString indent_0 = xml_indent(indent_level);
00816     QString indent_1 = xml_indent(indent_level + 1);
00817 
00818     QString str = QString(
00819         "%1<ProgramAssociationSection tsid=\"0x%2\" program_count=\"%3\""
00820         "\n%4%5>\n")
00821         .arg(indent_0)
00822         .arg(TransportStreamID(),4,16,QChar('0'))
00823         .arg(ProgramCount())
00824         .arg(indent_1)
00825         .arg(PSIPTable::XMLValues(indent_level + 1));
00826 
00827     for (uint i = 0; i < ProgramCount(); i++)
00828     {
00829         bool dummy = (0x1fff == ProgramPID(i)) || (0x0 == ProgramPID(i));
00830         str += QString("%1<Program number=\"%2\" pid=\"0x%3\" %4/>\n")
00831             .arg(indent_1)
00832             .arg(ProgramNumber(i))
00833             .arg(ProgramPID(i),4,16,QChar('0'))
00834             .arg(dummy ? "comment=\"Dummy Program\" " : "");
00835     }
00836 
00837     return str + indent_0 + "</ProgramAssociationSection>";
00838 }
00839 
00840 QString ProgramMapTable::toString(void) const
00841 {
00842     QString str =
00843         QString("Program Map Section"
00844                 "\n%1"
00845                 "      pnum(%2) pid(0x%3)\n")
00846         .arg(PSIPTable::toString())
00847         .arg(ProgramNumber())
00848         .arg(tsheader()->PID(),0,16);
00849 
00850     vector<const unsigned char*> desc =
00851         MPEGDescriptor::Parse(ProgramInfo(), ProgramInfoLength());
00852     for (uint i = 0; i < desc.size(); i++)
00853     {
00854         str.append(QString("  %1\n")
00855                    .arg(MPEGDescriptor(desc[i], 300).toString()));
00856     }
00857 
00858     for (uint i = 0; i < StreamCount(); i++)
00859     {
00860         str.append(QString("  Stream #%1 pid(0x%2) type(0x%3 %4)\n")
00861                    .arg(i).arg(StreamPID(i), 0, 16)
00862                    .arg(StreamType(i), 2, 16, QChar('0'))
00863                    .arg(StreamTypeString(i)));
00864         vector<const unsigned char*> desc =
00865             MPEGDescriptor::Parse(StreamInfo(i), StreamInfoLength(i));
00866         for (uint i = 0; i < desc.size(); i++)
00867         {
00868             str.append(QString("    %1\n")
00869                        .arg(MPEGDescriptor(desc[i], 300).toString()));
00870         }
00871     }
00872     return str;
00873 }
00874 
00875 QString ProgramMapTable::toStringXML(uint indent_level) const
00876 {
00877     QString indent_0 = xml_indent(indent_level);
00878     QString indent_1 = xml_indent(indent_level + 1);
00879 
00880     QString str = QString(
00881         "%1<ProgramMapSection pcr_pid=\"0x%2\" program_number=\"%3\"\n"
00882         "%4program_info_length=\"%5\" stream_count=\"%7\"%8>\n")
00883         .arg(indent_0)
00884         .arg(PCRPID(),0,16)
00885         .arg(ProgramNumber())
00886         .arg(indent_1)
00887         .arg(ProgramInfoLength())
00888         .arg(PSIPTable::XMLValues(indent_level + 1));
00889 
00890     vector<const unsigned char*> gdesc =
00891         MPEGDescriptor::Parse(ProgramInfo(), ProgramInfoLength());
00892     for (uint i = 0; i < gdesc.size(); i++)
00893     {
00894         str += MPEGDescriptor(gdesc[i], 300)
00895             .toStringXML(indent_level + 1) + "\n";
00896     }
00897 
00898     for (uint i = 0; i < StreamCount(); i++)
00899     {
00900         str += QString("%1<Stream pid=\"0x%2\" type=\"0x%3\" "
00901                        "type_desc=\"%4\" stream_info_length=\"%5\"")
00902             .arg(indent_1)
00903             .arg(StreamPID(i),2,16,QChar('0'))
00904             .arg(StreamType(i),2,16,QChar('0'))
00905             .arg(StreamTypeString(i))
00906             .arg(StreamInfoLength(i));
00907         vector<const unsigned char*> ldesc =
00908             MPEGDescriptor::Parse(StreamInfo(i), StreamInfoLength(i));
00909         str += (ldesc.empty()) ? " />\n" : ">\n";
00910         for (uint i = 0; i < ldesc.size(); i++)
00911         {
00912             str += MPEGDescriptor(ldesc[i], 300)
00913                 .toStringXML(indent_level + 2) + "\n";
00914         }
00915         if (!ldesc.empty())
00916             str += indent_1 + "</Stream>\n";
00917     }
00918 
00919     return str + indent_0 + "</ProgramMapSection>";
00920 }
00921 
00922 const char *StreamID::toString(uint streamID)
00923 {
00924     // valid for some ATSC/DVB stuff too
00925     switch (streamID)
00926     {
00927     case StreamID::MPEG2Video:
00928         return "video-mpeg2";
00929     case StreamID::MPEG1Video:
00930         return "video-mpeg1";
00931     case StreamID::MPEG4Video:
00932         return "video-mpeg4";
00933     case StreamID::H264Video:
00934         return "video-h264";
00935     case StreamID::OpenCableVideo:
00936         return "video-opencable";
00937 
00938     // audio
00939     case StreamID::AC3Audio:
00940         return "audio-ac3";  // EIT, PMT
00941     case StreamID::MPEG2Audio:
00942         return "audio-mp2-layer[1,2,3]"; // EIT, PMT
00943     case StreamID::MPEG1Audio:
00944         return "audio-mp1-layer[1,2,3]"; // EIT, PMT
00945     case StreamID::MPEG2AudioAmd1:
00946          return "audio-aac-latm"; // EIT, PMT
00947     case StreamID::MPEG2AACAudio:
00948         return "audio-aac"; // EIT, PMT
00949     case StreamID::DTSAudio:
00950         return "audio-dts"; // EIT, PMT
00951 
00952     // other
00953     case StreamID::PrivSec:
00954         return "private-sec";
00955     case StreamID::PrivData:
00956         return "private-data";
00957 
00958     // DSMCC Object Carousel
00959     case StreamID::DSMCC_A:
00960         return "dsmcc-a encap";
00961     case StreamID::DSMCC_B:
00962         return "dsmcc-b std data";
00963     case StreamID::DSMCC_C:
00964         return "dsmcc-c NPD data";
00965     case StreamID::DSMCC_D:
00966         return "dsmcc-d data";
00967 
00968     // Can be in any MPEG stream ATSC, DVB, or ARIB ; but defined in SCTE 35
00969     case StreamID::Splice:
00970         return "splice"; // PMT
00971 
00972     //case TableID::STUFFING: XXX: Duplicate?
00973     //    return "stuffing"; // optionally in any
00974     case TableID::CENSOR:
00975         return "censor"; // EIT, optionally in PMT
00976     case TableID::ECN:
00977         return "extended channel name";
00978     case TableID::SRVLOC:
00979         return "service location"; // required in VCT
00980     case TableID::TSS: // other channels with same stuff
00981         return "time-shifted service";
00982     case TableID::CMPNAME:
00983         return "component name"; //??? PMT
00984     }
00985     return "unknown";
00986 }
00987 
00988 QString StreamID::GetDescription(uint stream_id)
00989 {
00990     // valid for some ATSC/DVB stuff too
00991     switch (stream_id)
00992     {
00993         // video
00994         case StreamID::MPEG1Video:
00995             return "11172-2 MPEG-1 Video";
00996         case StreamID::MPEG2Video:
00997             return "13818-2 MPEG-2 Video";
00998         case StreamID::MPEG4Video:
00999             return "14492-2 MPEG-4 Video";
01000         case StreamID::H264Video:
01001             return "H.264 Video";
01002         case StreamID::OpenCableVideo:
01003             return "OpenCable Video";
01004         case StreamID::VC1Video:
01005             return "VC-1 Video";
01006 
01007         // audio
01008         case StreamID::MPEG1Audio:
01009             return "11172-2 MPEG-1 Audio";
01010         case StreamID::MPEG2Audio:
01011             return "13818-3 MPEG-2 Audio";
01012         case StreamID::MPEG2AACAudio:
01013             return "13818-7 AAC MPEG-2 Audio";
01014         case StreamID::MPEG2AudioAmd1:
01015             return "13818-3 AAC LATM MPEG-2 Audio";
01016         case StreamID::AC3Audio:
01017             return "AC3 Audio";
01018         case StreamID::DTSAudio:
01019             return "DTS Audio";
01020 
01021         // DSMCC Object Carousel
01022         case StreamID::DSMCC:
01023             return "13818-1 DSM-CC";
01024         case StreamID::DSMCC_A:
01025             return "13818-6 DSM-CC Type A";
01026         case StreamID::DSMCC_B:
01027             return "13818-6 DSM-CC Type B";
01028         case StreamID::DSMCC_C:
01029             return "13818-6 DSM-CC Type C";
01030         case StreamID::DSMCC_D:
01031             return "13818-6 DSM-CC Type D";
01032         case StreamID::DSMCC_DL:
01033             return "13818-6 Download";
01034         case StreamID::MetaDataPES:
01035             return "13818-6 Metadata in PES";
01036         case StreamID::MetaDataSec:
01037             return "13818-6 Metadata in Sections";
01038         case StreamID::MetaDataDC:
01039             return "13818-6 Metadata in Data Carousel";
01040         case StreamID::MetaDataOC:
01041             return "13818-6 Metadata in Obj Carousel";
01042         case StreamID::MetaDataDL:
01043             return "13818-6 Metadata in Download";
01044 
01045         // other
01046         case StreamID::PrivSec:
01047             return "13818-1 Private Sections";
01048         case StreamID::PrivData:
01049             return "13818-3 Private Data";
01050         case StreamID::MHEG:
01051             return "13522 MHEG";
01052         case StreamID::H222_1:
01053             return "ITU H.222.1";
01054         case StreamID::MPEG2Aux:
01055             return "13818-1 Aux & ITU H.222.0";
01056         case StreamID::FlexMuxPES:
01057             return "14496-1 SL/FlexMux in PES";
01058         case StreamID::FlexMuxSec:
01059             return "14496-1 SL/FlexMux in Sections";
01060         case StreamID::MPEG2IPMP:
01061             return "13818-10 IPMP";
01062         case StreamID::MPEG2IPMP2:
01063             return "13818-10 IPMP2";
01064 
01065         case AnyMask:  return QString();
01066         case AnyVideo: return "video";
01067         case AnyAudio: return "audio";
01068     }
01069 
01070     return QString();
01071 }
01072 
01073 QString ProgramMapTable::GetLanguage(uint i) const
01074 {
01075     const desc_list_t list = MPEGDescriptor::Parse(
01076         StreamInfo(i), StreamInfoLength(i));
01077     const unsigned char *lang_desc = MPEGDescriptor::Find(
01078         list, DescriptorID::iso_639_language);
01079 
01080     if (!lang_desc)
01081         return QString::null;
01082 
01083     ISO639LanguageDescriptor iso_lang(lang_desc);
01084     return iso_lang.CanonicalLanguageString();
01085 }
01086 
01087 QString ProgramMapTable::StreamDescription(uint i, QString sistandard) const
01088 {
01089     desc_list_t list;
01090 
01091     list         = MPEGDescriptor::Parse(StreamInfo(i), StreamInfoLength(i));
01092     uint    type = StreamID::Normalize(StreamType(i), list, sistandard);
01093     QString desc = StreamID::toString(type);
01094     QString lang = GetLanguage(i);
01095 
01096     if (!lang.isEmpty())
01097         desc += QString(" (%1)").arg(lang);
01098 
01099     return desc;
01100 }
01101 
01102 QString ConditionalAccessTable::toString(void) const
01103 {
01104     QString str =
01105         QString("Condiditional Access Section %1")
01106         .arg(PSIPTable::toString());
01107     
01108     vector<const unsigned char*> gdesc =
01109         MPEGDescriptor::Parse(Descriptors(), DescriptorsLength());
01110     for (uint i = 0; i < gdesc.size(); i++)
01111         str += "  " + MPEGDescriptor(gdesc[i], 300).toString() + "\n";
01112 
01113     str += "\n";
01114 
01115     return str;
01116 }
01117 
01118 QString ConditionalAccessTable::toStringXML(uint indent_level) const
01119 {
01120     QString indent_0 = xml_indent(indent_level);
01121 
01122     QString str =
01123         QString("%1<ConditionalAccessSection %3")
01124         .arg(indent_0)
01125         .arg(PSIPTable::XMLValues(indent_level + 1));
01126 
01127     vector<const unsigned char*> gdesc =
01128         MPEGDescriptor::Parse(Descriptors(), DescriptorsLength());
01129     str += (gdesc.empty()) ? " />\n" : ">\n";
01130     for (uint i = 0; i < gdesc.size(); i++)
01131     {
01132         str += MPEGDescriptor(gdesc[i], 300)
01133             .toStringXML(indent_level + 1) + "\n";
01134     }
01135     if (!gdesc.empty())
01136         str += indent_0 + "</ConditionalAccessSection>\n";
01137 
01138     return str;
01139 }
01140 
01141 QString SpliceTimeView::toString(int64_t first, int64_t last) const
01142 {
01143     if (!IsTimeSpecified())
01144         return QString("splice_time(N/A)");
01145 
01146     int64_t abs_pts_time = PTSTime();
01147     if ((first > 0) && (last > 0))
01148     {
01149         int64_t elapsed = abs_pts_time - first;
01150         elapsed = (elapsed < 0) ? elapsed + 0x1000000000LL : elapsed;
01151         QTime abs = QTime(0,0,0,0).addMSecs(elapsed/90);
01152 
01153         elapsed = abs_pts_time - last; /* rel_pts_time */
01154         elapsed = (elapsed < 0) ? elapsed + 0x1000000000LL : elapsed;
01155         QTime rel = QTime(0,0,0,0).addMSecs(elapsed/90);
01156 
01157         return QString("splice_time(pts: %1 abs: %2, rel: +%3)")
01158             .arg(abs_pts_time)
01159             .arg(abs.toString("hh:mm:ss.zzz"))
01160             .arg(rel.toString("hh:mm:ss.zzz"));
01161     }
01162 
01163     return QString("splice_time(pts: %1)").arg(abs_pts_time);
01164 }
01165 
01166 QString SpliceTimeView::toStringXML(
01167     uint indent_level, int64_t first, int64_t last) const
01168 {
01169     QString indent = xml_indent(indent_level);
01170 
01171     if (!IsTimeSpecified())
01172         return indent + "<SpliceTime />";
01173 
01174     int64_t abs_pts_time = PTSTime();
01175 
01176     QString abs_str;
01177     if (first > 0)
01178     {
01179         int64_t elapsed = abs_pts_time - first;
01180         elapsed = (elapsed < 0) ? elapsed + 0x1000000000LL : elapsed;
01181         QTime abs = QTime(0,0,0,0).addMSecs(elapsed/90);
01182         abs_str = QString("absolute=\"%1\" ")
01183             .arg(abs.toString("hh:mm:ss.zzz"));
01184     }
01185 
01186     QString rel_str;
01187     if (last > 0)
01188     {
01189         int64_t elapsed = abs_pts_time - last; /* rel_pts_time */
01190         elapsed = (elapsed < 0) ? elapsed + 0x1000000000LL : elapsed;
01191         QTime rel = QTime(0,0,0,0).addMSecs(elapsed/90);
01192         rel_str = QString("relative=\"+%1\" ")
01193             .arg(rel.toString("hh:mm:ss.zzz"));
01194     }
01195 
01196     return QString("%1<SpliceTime pts=\"%2\" %3%4/>")
01197         .arg(indent).arg(abs_pts_time).arg(abs_str).arg(rel_str);
01198 }
01199 
01201 SpliceInformationTable *SpliceInformationTable::GetDecrypted(
01202     const QString &codeWord) const
01203 {
01204     // TODO
01205     return NULL;
01206 }
01207 
01208 bool SpliceInformationTable::Parse(void)
01209 {
01210     _epilog = NULL;
01211     _ptrs0.clear();
01212     _ptrs1.clear();
01213 
01214     if (TableID::SITscte != TableID())
01215         return false;
01216 
01217     if (SpliceProtocolVersion() != 0)
01218         return false;
01219 
01220     if (IsEncryptedPacket())
01221         return true; // it's "parsed" but you can't read encrypted portion
01222 
01223     uint type = SpliceCommandType();
01224     if (kSCTNull == type || kSCTBandwidthReservation == type)
01225     {
01226         _epilog = pesdata() + 14;
01227     }
01228     else if (kSCTTimeSignal == type)
01229     {
01230         _epilog = pesdata() + 14 + TimeSignal().size();
01231     }
01232     else if (kSCTSpliceSchedule == type)
01233     {
01234         uint splice_count = pesdata()[14];
01235         const unsigned char *cur = pesdata() + 15;
01236         for (uint i = 0; i < splice_count; i++)
01237         {
01238             _ptrs0.push_back(cur);
01239             bool event_cancel = cur[4] & 0x80;
01240             if (event_cancel)
01241             {
01242                 _ptrs1.push_back(NULL);
01243                 cur += 5;
01244                 continue;
01245             }
01246             bool program_slice = cur[5] & 0x40;
01247             uint component_count = cur[6];
01248             _ptrs1.push_back(cur + (program_slice ? 10 : 7 * component_count));
01249         }
01250         if (splice_count)
01251         {
01252             bool duration = _ptrs0.back()[5] & 0x2;
01253             _epilog = _ptrs1.back() + ((duration) ? 9 : 4);
01254         }
01255         else
01256         {
01257             _epilog = cur;
01258         }
01259     }
01260     else if (kSCTSpliceInsert == type)
01261     {
01262         _ptrs1.push_back(pesdata() + 14);
01263         bool splice_cancel = pesdata()[18] & 0x80;
01264         if (splice_cancel)
01265         {
01266             _epilog = pesdata() + 19;
01267         }
01268         else
01269         {
01270             bool program_splice = pesdata()[19] & 0x40;
01271             bool duration = pesdata()[19] & 0x20;
01272             bool splice_immediate = pesdata()[19] & 0x10;
01273             const unsigned char *cur = pesdata() + 20;
01274             if (program_splice && !splice_immediate)
01275             {
01276                 cur += SpliceTimeView(cur).size();
01277             }
01278             else if (!program_splice)
01279             {
01280                 uint component_count = pesdata()[20];
01281                 cur = pesdata() + 21;
01282                 for (uint i = 0; i < component_count; i++)
01283                 {
01284                     _ptrs0.push_back(cur);
01285                     cur += (splice_immediate) ?
01286                         1 : 1 + SpliceTimeView(cur).size();
01287                 }
01288             }
01289             _ptrs1.push_back(cur);
01290             _ptrs1.push_back(cur + (duration ? 5 : 0));
01291         }
01292     }
01293     else
01294     {
01295         _epilog = NULL;
01296     }
01297 
01298     return _epilog != NULL;
01299 }
01300 
01301 QString SpliceInformationTable::EncryptionAlgorithmString(void) const
01302 {
01303     uint alg = EncryptionAlgorithm();
01304     switch (alg)
01305     {
01306         case kNoEncryption: return "None";
01307         case kECB:          return "DES-ECB";
01308         case kCBC:          return "DES-CBC";
01309         case k3DES:         return "3DES";
01310         default:
01311             return QString((alg<32) ? "Reserved(%1)" : "Private(%1)").arg(alg);
01312     }
01313 }
01314 
01315 QString SpliceInformationTable::SpliceCommandTypeString(void) const
01316 {
01317     uint type = SpliceCommandType();
01318     switch (type)
01319     {
01320         case kSCTNull:
01321             return "Null";
01322         case kSCTSpliceSchedule:
01323             return "SpliceSchedule";
01324         case kSCTSpliceInsert:
01325             return "SpliceInsert";
01326         case kSCTTimeSignal:
01327             return "TimeSignal";
01328         case kSCTBandwidthReservation:
01329             return "BandwidthReservation";
01330         case kSCTPrivateCommand:
01331             return "Private";
01332         default:
01333             return QString("Reserved(%1)").arg(type);
01334     };
01335 }
01336 
01337 QString SpliceInformationTable::toString(int64_t first, int64_t last) const
01338 {
01339     QString str =
01340         QString("SpliceInformationSection enc_alg(%1) pts_adj(%2)")
01341         .arg(IsEncryptedPacket()?EncryptionAlgorithmString():"None")
01342         .arg(PTSAdjustment());
01343     str += IsEncryptedPacket() ? QString(" cw_index(%1)") : QString("");
01344     str += QString(" command_len(%1) command_type(%2)")
01345         .arg(SpliceCommandLength())
01346         .arg(SpliceCommandTypeString());
01347 
01348     if (IsEncryptedPacket())
01349         return str;
01350 
01351     switch (SpliceCommandType())
01352     {
01353         case kSCTSpliceSchedule:
01354             break;
01355         case kSCTSpliceInsert:
01356         {
01357             str += "\n  " + SpliceInsert().toString(first, last);
01358             break;
01359         }
01360         case kSCTTimeSignal:
01361             break;
01362     }
01363 
01364     return str;
01365 }
01366 
01367 QString SpliceInsertView::toString(int64_t first, int64_t last) const
01368 {
01369     QString str = 
01370         QString("eventid(0x%1) cancel(%2) "
01371                 "out_of_network(%3) program_splice(%4) "
01372                 "duration(%5) immediate(%6)\n  ")
01373         .arg(SpliceEventID(),0,16)
01374         .arg(IsSpliceEventCancel()?"yes":"no")
01375         .arg(IsOutOfNetwork()?"yes":"no")
01376         .arg(IsProgramSplice()?"yes":"no")
01377         .arg(IsDuration()?"yes":"no")
01378         .arg(IsSpliceImmediate()?"yes":"no");
01379 
01380     if (IsProgramSplice() && !IsSpliceImmediate())
01381         str += SpliceTime().toString(first, last);
01382 
01383     str += QString(" unique_program_id(%1)")
01384         .arg(UniqueProgramID());
01385 
01386     str += QString(" avail(%1/%2)")
01387         .arg(AvailNum()).arg(AvailsExpected());
01388 
01389     return str;
01390 }
01391 
01392 QString SpliceInformationTable::toStringXML(
01393     uint indent_level, int64_t first, int64_t last) const
01394 {
01395     QString indent = xml_indent(indent_level);
01396 
01397     QString cap_time = "";
01398     if (first >= 0)
01399     {
01400         cap_time = QString("pts=\"%1\" ").arg(first);
01401         if (last >= 0) 
01402         {
01403             QTime abs = QTime(0,0,0,0).addMSecs((last - first)/90);
01404             cap_time += QString("capture_time=\"%1\" ")
01405                 .arg(abs.toString("hh:mm:ss.zzz"));
01406         }
01407     }
01408 
01409     QString str = QString(
01410         "%1<SpliceInformationSection %2 encryption_algorithm=\"%3\" "
01411         "pts_adjustment=\"%4\" code_word_index=\"%5\" command_type=\"%6\">\n")
01412         .arg(indent)
01413         .arg(cap_time)
01414         .arg(EncryptionAlgorithmString())
01415         .arg(PTSAdjustment())
01416         .arg(CodeWordIndex())
01417         .arg(SpliceCommandTypeString());
01418 
01419     if (IsEncryptedPacket())
01420         return str + indent + "</SpliceInformationSection>";
01421 
01422     switch (SpliceCommandType())
01423     {
01424         case kSCTSpliceSchedule:
01425             break;
01426         case kSCTSpliceInsert:
01427         {
01428             str += SpliceInsert().toStringXML(indent_level + 1, first, last);
01429             str += "\n";
01430             break;
01431         }
01432         case kSCTTimeSignal:
01433             break;
01434     }
01435 
01436     str += indent + "</SpliceInformationSection>";
01437     return str;
01438 }
01439 
01440 QString SpliceInsertView::toStringXML(
01441     uint indent_level, int64_t first, int64_t last) const
01442 {
01443     QString indent_0 = xml_indent(indent_level);
01444     QString indent_1 = xml_indent(indent_level + 1);
01445     QString str = QString(
01446         "%1<SpliceInsert eventid=\"0x%2\" cancel=\"%3\"\n")
01447         .arg(indent_0)
01448         .arg(SpliceEventID(),0,16)
01449         .arg(xml_bool_to_string(IsSpliceEventCancel()));
01450 
01451     str += QString(
01452         "%1out_of_network=\"%2\" program_splice=\"%3\" duration=\"%4\"\n")
01453         .arg(indent_1)
01454         .arg(xml_bool_to_string(IsOutOfNetwork()))
01455         .arg(xml_bool_to_string(IsProgramSplice()))
01456         .arg(xml_bool_to_string(IsDuration()));
01457 
01458     str += QString(
01459         "%1immediate=\"%2\" unique_program_id=\"%3\"\n"
01460         "%4avail_num=\"%5\" avails_expected=\"%6\">\n")
01461         .arg(indent_1)
01462         .arg(xml_bool_to_string(IsSpliceImmediate()))
01463         .arg(UniqueProgramID())
01464         .arg(indent_1)
01465         .arg(AvailNum())
01466         .arg(AvailsExpected());
01467     
01468     if (IsProgramSplice() && !IsSpliceImmediate())
01469     {
01470         str += SpliceTime().toStringXML(indent_level + 1, first, last) + "\n";
01471     }
01472 
01473     str += indent_0 + "</SpliceInsert>";
01474     return str;
01475 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends