vdr  1.7.27
remux.c
Go to the documentation of this file.
00001 /*
00002  * remux.c: Tools for detecting frames and handling PAT/PMT
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: remux.c 2.64 2012/03/02 10:56:49 kls Exp $
00008  */
00009 
00010 #include "remux.h"
00011 #include "device.h"
00012 #include "libsi/si.h"
00013 #include "libsi/section.h"
00014 #include "libsi/descriptor.h"
00015 #include "recording.h"
00016 #include "shutdown.h"
00017 #include "tools.h"
00018 
00019 // Set these to 'true' for debug output:
00020 static bool DebugPatPmt = false;
00021 static bool DebugFrames = false;
00022 
00023 #define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a)
00024 #define dbgframes(a...) if (DebugFrames) fprintf(stderr, a)
00025 
00026 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
00027 {
00028   if (Count < 7)
00029      return phNeedMoreData; // too short
00030 
00031   if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
00032      if (Count < 9)
00033         return phNeedMoreData; // too short
00034 
00035      PesPayloadOffset = 6 + 3 + Data[8];
00036      if (Count < PesPayloadOffset)
00037         return phNeedMoreData; // too short
00038 
00039      if (ContinuationHeader)
00040         *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
00041 
00042      return phMPEG2; // MPEG 2
00043      }
00044 
00045   // check for MPEG 1 ...
00046   PesPayloadOffset = 6;
00047 
00048   // skip up to 16 stuffing bytes
00049   for (int i = 0; i < 16; i++) {
00050       if (Data[PesPayloadOffset] != 0xFF)
00051          break;
00052 
00053       if (Count <= ++PesPayloadOffset)
00054          return phNeedMoreData; // too short
00055       }
00056 
00057   // skip STD_buffer_scale/size
00058   if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
00059      PesPayloadOffset += 2;
00060 
00061      if (Count <= PesPayloadOffset)
00062         return phNeedMoreData; // too short
00063      }
00064 
00065   if (ContinuationHeader)
00066      *ContinuationHeader = false;
00067 
00068   if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
00069      // skip PTS only
00070      PesPayloadOffset += 5;
00071      }
00072   else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
00073      // skip PTS and DTS
00074      PesPayloadOffset += 10;
00075      }
00076   else if (Data[PesPayloadOffset] == 0x0F) {
00077      // continuation header
00078      PesPayloadOffset++;
00079 
00080      if (ContinuationHeader)
00081         *ContinuationHeader = true;
00082      }
00083   else
00084      return phInvalid; // unknown
00085 
00086   if (Count < PesPayloadOffset)
00087      return phNeedMoreData; // too short
00088 
00089   return phMPEG1; // MPEG 1
00090 }
00091 
00092 #define VIDEO_STREAM_S   0xE0
00093 
00094 // --- cRemux ----------------------------------------------------------------
00095 
00096 void cRemux::SetBrokenLink(uchar *Data, int Length)
00097 {
00098   int PesPayloadOffset = 0;
00099   if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
00100      for (int i = PesPayloadOffset; i < Length - 7; i++) {
00101          if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
00102             if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
00103                Data[i + 7] |= 0x20;
00104             return;
00105             }
00106          }
00107      dsyslog("SetBrokenLink: no GOP header found in video packet");
00108      }
00109   else
00110      dsyslog("SetBrokenLink: no video packet in frame");
00111 }
00112 
00113 // --- Some TS handling tools ------------------------------------------------
00114 
00115 int64_t TsGetPts(const uchar *p, int l)
00116 {
00117   // Find the first packet with a PTS and use it:
00118   while (l > 0) {
00119         const uchar *d = p;
00120         if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
00121            return PesGetPts(d);
00122         p += TS_SIZE;
00123         l -= TS_SIZE;
00124         }
00125   return -1;
00126 }
00127 
00128 void TsSetTeiOnBrokenPackets(uchar *p, int l)
00129 {
00130   bool Processed[MAXPID] = { false };
00131   while (l >= TS_SIZE) {
00132         if (*p != TS_SYNC_BYTE)
00133            break;
00134         int Pid = TsPid(p);
00135         if (!Processed[Pid]) {
00136            if (!TsPayloadStart(p))
00137               p[1] |= TS_ERROR;
00138            else {
00139               Processed[Pid] = true;
00140               int offs = TsPayloadOffset(p);
00141               cRemux::SetBrokenLink(p + offs, TS_SIZE - offs);
00142               }
00143            }
00144         l -= TS_SIZE;
00145         p += TS_SIZE;
00146         }
00147 }
00148 
00149 // --- cPatPmtGenerator ------------------------------------------------------
00150 
00151 cPatPmtGenerator::cPatPmtGenerator(const cChannel *Channel)
00152 {
00153   numPmtPackets = 0;
00154   patCounter = pmtCounter = 0;
00155   patVersion = pmtVersion = 0;
00156   pmtPid = 0;
00157   esInfoLength = NULL;
00158   SetChannel(Channel);
00159 }
00160 
00161 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
00162 {
00163   TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
00164   if (++Counter > 0x0F)
00165      Counter = 0x00;
00166 }
00167 
00168 void cPatPmtGenerator::IncVersion(int &Version)
00169 {
00170   if (++Version > 0x1F)
00171      Version = 0x00;
00172 }
00173 
00174 void cPatPmtGenerator::IncEsInfoLength(int Length)
00175 {
00176   if (esInfoLength) {
00177      Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
00178      *esInfoLength = 0xF0 | (Length >> 8);
00179      *(esInfoLength + 1) = Length;
00180      }
00181 }
00182 
00183 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
00184 {
00185   int i = 0;
00186   Target[i++] = Type; // stream type
00187   Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
00188   Target[i++] = Pid; // pid lo
00189   esInfoLength = &Target[i];
00190   Target[i++] = 0xF0; // dummy (4), ES info length hi
00191   Target[i++] = 0x00; // ES info length lo
00192   return i;
00193 }
00194 
00195 int cPatPmtGenerator::MakeAC3Descriptor(uchar *Target, uchar Type)
00196 {
00197   int i = 0;
00198   Target[i++] = Type;
00199   Target[i++] = 0x01; // length
00200   Target[i++] = 0x00;
00201   IncEsInfoLength(i);
00202   return i;
00203 }
00204 
00205 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
00206 {
00207   int i = 0;
00208   Target[i++] = SI::SubtitlingDescriptorTag;
00209   Target[i++] = 0x08; // length
00210   Target[i++] = *Language++;
00211   Target[i++] = *Language++;
00212   Target[i++] = *Language++;
00213   Target[i++] = SubtitlingType;
00214   Target[i++] = CompositionPageId >> 8;
00215   Target[i++] = CompositionPageId & 0xFF;
00216   Target[i++] = AncillaryPageId >> 8;
00217   Target[i++] = AncillaryPageId & 0xFF;
00218   IncEsInfoLength(i);
00219   return i;
00220 }
00221 
00222 int cPatPmtGenerator::MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount)
00223 {
00224   int i = 0, j = 0;
00225   Target[i++] = SI::TeletextDescriptorTag;
00226   int l = i;
00227   Target[i++] = 0x00; // length
00228   for (int n = 0; n < pageCount; n++) {
00229       const char* Language = pages[n].ttxtLanguage;
00230       Target[i++] = *Language++;
00231       Target[i++] = *Language++;
00232       Target[i++] = *Language++;
00233       Target[i++] = (pages[n].ttxtType << 3) + pages[n].ttxtMagazine;
00234       Target[i++] = pages[n].ttxtPage;
00235       j++;
00236       }
00237   if (j > 0) {
00238      Target[l] = j * 5; // update length
00239      IncEsInfoLength(i);
00240      return i;
00241      }
00242   return 0;
00243 }
00244 
00245 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
00246 {
00247   int i = 0;
00248   Target[i++] = SI::ISO639LanguageDescriptorTag;
00249   int Length = i++;
00250   Target[Length] = 0x00; // length
00251   for (const char *End = Language + strlen(Language); Language < End; ) {
00252       Target[i++] = *Language++;
00253       Target[i++] = *Language++;
00254       Target[i++] = *Language++;
00255       Target[i++] = 0x00;     // audio type
00256       Target[Length] += 0x04; // length
00257       if (*Language == '+')
00258          Language++;
00259       }
00260   IncEsInfoLength(i);
00261   return i;
00262 }
00263 
00264 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
00265 {
00266   int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
00267   int i = 0;
00268   Target[i++] = crc >> 24;
00269   Target[i++] = crc >> 16;
00270   Target[i++] = crc >> 8;
00271   Target[i++] = crc;
00272   return i;
00273 }
00274 
00275 #define P_TSID    0x8008 // pseudo TS ID
00276 #define P_PMT_PID 0x0084 // pseudo PMT pid
00277 #define MAXPID    0x2000 // the maximum possible number of pids
00278 
00279 void cPatPmtGenerator::GeneratePmtPid(const cChannel *Channel)
00280 {
00281   bool Used[MAXPID] = { false };
00282 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
00283 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
00284   SETPID(Channel->Vpid());
00285   SETPID(Channel->Ppid());
00286   SETPID(Channel->Tpid());
00287   SETPIDS(Channel->Apids());
00288   SETPIDS(Channel->Dpids());
00289   SETPIDS(Channel->Spids());
00290   for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
00291       ;
00292 }
00293 
00294 void cPatPmtGenerator::GeneratePat(void)
00295 {
00296   memset(pat, 0xFF, sizeof(pat));
00297   uchar *p = pat;
00298   int i = 0;
00299   p[i++] = TS_SYNC_BYTE; // TS indicator
00300   p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
00301   p[i++] = PATPID & 0xFF; // pid lo
00302   p[i++] = 0x10; // flags (4), continuity counter (4)
00303   p[i++] = 0x00; // pointer field (payload unit start indicator is set)
00304   int PayloadStart = i;
00305   p[i++] = 0x00; // table id
00306   p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
00307   int SectionLength = i;
00308   p[i++] = 0x00; // section length lo (filled in later)
00309   p[i++] = P_TSID >> 8;   // TS id hi
00310   p[i++] = P_TSID & 0xFF; // TS id lo
00311   p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
00312   p[i++] = 0x00; // section number
00313   p[i++] = 0x00; // last section number
00314   p[i++] = pmtPid >> 8;   // program number hi
00315   p[i++] = pmtPid & 0xFF; // program number lo
00316   p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
00317   p[i++] = pmtPid & 0xFF; // PMT pid lo
00318   pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC
00319   MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
00320   IncVersion(patVersion);
00321 }
00322 
00323 void cPatPmtGenerator::GeneratePmt(const cChannel *Channel)
00324 {
00325   // generate the complete PMT section:
00326   uchar buf[MAX_SECTION_SIZE];
00327   memset(buf, 0xFF, sizeof(buf));
00328   numPmtPackets = 0;
00329   if (Channel) {
00330      int Vpid = Channel->Vpid();
00331      int Ppid = Channel->Ppid();
00332      int Tpid = Channel->Tpid();
00333      uchar *p = buf;
00334      int i = 0;
00335      p[i++] = 0x02; // table id
00336      int SectionLength = i;
00337      p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
00338      p[i++] = 0x00; // section length lo (filled in later)
00339      p[i++] = pmtPid >> 8;   // program number hi
00340      p[i++] = pmtPid & 0xFF; // program number lo
00341      p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
00342      p[i++] = 0x00; // section number
00343      p[i++] = 0x00; // last section number
00344      p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
00345      p[i++] = Ppid; // PCR pid lo
00346      p[i++] = 0xF0; // dummy (4), program info length hi (4)
00347      p[i++] = 0x00; // program info length lo
00348 
00349      if (Vpid)
00350         i += MakeStream(buf + i, Channel->Vtype(), Vpid);
00351      for (int n = 0; Channel->Apid(n); n++) {
00352          i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
00353          const char *Alang = Channel->Alang(n);
00354          i += MakeLanguageDescriptor(buf + i, Alang);
00355          }
00356      for (int n = 0; Channel->Dpid(n); n++) {
00357          i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
00358          i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
00359          i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
00360          }
00361      for (int n = 0; Channel->Spid(n); n++) {
00362          i += MakeStream(buf + i, 0x06, Channel->Spid(n));
00363          i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
00364          }
00365      if (Tpid) {
00366         i += MakeStream(buf + i, 0x06, Tpid);
00367         i += MakeTeletextDescriptor(buf + i, Channel->TeletextSubtitlePages(), Channel->TotalTeletextSubtitlePages());
00368         }
00369 
00370      int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
00371      buf[SectionLength] |= (sl >> 8) & 0x0F;
00372      buf[SectionLength + 1] = sl;
00373      MakeCRC(buf + i, buf, i);
00374      // split the PMT section into several TS packets:
00375      uchar *q = buf;
00376      bool pusi = true;
00377      while (i > 0) {
00378            uchar *p = pmt[numPmtPackets++];
00379            int j = 0;
00380            p[j++] = TS_SYNC_BYTE; // TS indicator
00381            p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
00382            p[j++] = pmtPid & 0xFF; // pid lo
00383            p[j++] = 0x10; // flags (4), continuity counter (4)
00384            if (pusi) {
00385               p[j++] = 0x00; // pointer field (payload unit start indicator is set)
00386               pusi = false;
00387               }
00388            int l = TS_SIZE - j;
00389            memcpy(p + j, q, l);
00390            q += l;
00391            i -= l;
00392            }
00393      IncVersion(pmtVersion);
00394      }
00395 }
00396 
00397 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
00398 {
00399   patVersion = PatVersion & 0x1F;
00400   pmtVersion = PmtVersion & 0x1F;
00401 }
00402 
00403 void cPatPmtGenerator::SetChannel(const cChannel *Channel)
00404 {
00405   if (Channel) {
00406      GeneratePmtPid(Channel);
00407      GeneratePat();
00408      GeneratePmt(Channel);
00409      }
00410 }
00411 
00412 uchar *cPatPmtGenerator::GetPat(void)
00413 {
00414   IncCounter(patCounter, pat);
00415   return pat;
00416 }
00417 
00418 uchar *cPatPmtGenerator::GetPmt(int &Index)
00419 {
00420   if (Index < numPmtPackets) {
00421      IncCounter(pmtCounter, pmt[Index]);
00422      return pmt[Index++];
00423      }
00424   return NULL;
00425 }
00426 
00427 // --- cPatPmtParser ---------------------------------------------------------
00428 
00429 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
00430 {
00431   updatePrimaryDevice = UpdatePrimaryDevice;
00432   Reset();
00433 }
00434 
00435 void cPatPmtParser::Reset(void)
00436 {
00437   pmtSize = 0;
00438   patVersion = pmtVersion = -1;
00439   pmtPid = -1;
00440   vpid = vtype = 0;
00441   ppid = 0;
00442   tpid = 0;
00443 }
00444 
00445 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
00446 {
00447   // Unpack the TS packet:
00448   int PayloadOffset = TsPayloadOffset(Data);
00449   Data += PayloadOffset;
00450   Length -= PayloadOffset;
00451   // The PAT is always assumed to fit into a single TS packet
00452   if ((Length -= Data[0] + 1) <= 0)
00453      return;
00454   Data += Data[0] + 1; // process pointer_field
00455   SI::PAT Pat(Data, false);
00456   if (Pat.CheckCRCAndParse()) {
00457      dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
00458      if (patVersion == Pat.getVersionNumber())
00459         return;
00460      SI::PAT::Association assoc;
00461      for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
00462          dbgpatpmt("     isNITPid = %d\n", assoc.isNITPid());
00463          if (!assoc.isNITPid()) {
00464             pmtPid = assoc.getPid();
00465             dbgpatpmt("     service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
00466             }
00467          }
00468      patVersion = Pat.getVersionNumber();
00469      }
00470   else
00471      esyslog("ERROR: can't parse PAT");
00472 }
00473 
00474 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
00475 {
00476   // Unpack the TS packet:
00477   bool PayloadStart = TsPayloadStart(Data);
00478   int PayloadOffset = TsPayloadOffset(Data);
00479   Data += PayloadOffset;
00480   Length -= PayloadOffset;
00481   // The PMT may extend over several TS packets, so we need to assemble them
00482   if (PayloadStart) {
00483      pmtSize = 0;
00484      if ((Length -= Data[0] + 1) <= 0)
00485         return;
00486      Data += Data[0] + 1; // this is the first packet
00487      if (SectionLength(Data, Length) > Length) {
00488         if (Length <= int(sizeof(pmt))) {
00489            memcpy(pmt, Data, Length);
00490            pmtSize = Length;
00491            }
00492         else
00493            esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
00494         return;
00495         }
00496      // the packet contains the entire PMT section, so we run into the actual parsing
00497      }
00498   else if (pmtSize > 0) {
00499      // this is a following packet, so we add it to the pmt storage
00500      if (Length <= int(sizeof(pmt)) - pmtSize) {
00501         memcpy(pmt + pmtSize, Data, Length);
00502         pmtSize += Length;
00503         }
00504      else {
00505         esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
00506         pmtSize = 0;
00507         }
00508      if (SectionLength(pmt, pmtSize) > pmtSize)
00509         return; // more packets to come
00510      // the PMT section is now complete, so we run into the actual parsing
00511      Data = pmt;
00512      }
00513   else
00514      return; // fragment of broken packet - ignore
00515   SI::PMT Pmt(Data, false);
00516   if (Pmt.CheckCRCAndParse()) {
00517      dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
00518      dbgpatpmt("     pcr = %d\n", Pmt.getPCRPid());
00519      if (pmtVersion == Pmt.getVersionNumber())
00520         return;
00521      if (updatePrimaryDevice)
00522         cDevice::PrimaryDevice()->ClrAvailableTracks(false, true);
00523      int NumApids = 0;
00524      int NumDpids = 0;
00525      int NumSpids = 0;
00526      vpid = vtype = 0;
00527      ppid = 0;
00528      tpid = 0;
00529      apids[0] = 0;
00530      dpids[0] = 0;
00531      spids[0] = 0;
00532      atypes[0] = 0;
00533      dtypes[0] = 0;
00534      totalTtxtSubtitlePages = 0;
00535      SI::PMT::Stream stream;
00536      for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
00537          dbgpatpmt("     stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
00538          switch (stream.getStreamType()) {
00539            case 0x01: // STREAMTYPE_11172_VIDEO
00540            case 0x02: // STREAMTYPE_13818_VIDEO
00541            case 0x1B: // MPEG4
00542                       vpid = stream.getPid();
00543                       vtype = stream.getStreamType();
00544                       ppid = Pmt.getPCRPid();
00545                       break;
00546            case 0x03: // STREAMTYPE_11172_AUDIO
00547            case 0x04: // STREAMTYPE_13818_AUDIO
00548            case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
00549            case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
00550                       {
00551                       if (NumApids < MAXAPIDS) {
00552                          apids[NumApids] = stream.getPid();
00553                          atypes[NumApids] = stream.getStreamType();
00554                          *alangs[NumApids] = 0;
00555                          SI::Descriptor *d;
00556                          for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
00557                              switch (d->getDescriptorTag()) {
00558                                case SI::ISO639LanguageDescriptorTag: {
00559                                     SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
00560                                     SI::ISO639LanguageDescriptor::Language l;
00561                                     char *s = alangs[NumApids];
00562                                     int n = 0;
00563                                     for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
00564                                         if (*ld->languageCode != '-') { // some use "---" to indicate "none"
00565                                            dbgpatpmt(" '%s'", l.languageCode);
00566                                            if (n > 0)
00567                                               *s++ = '+';
00568                                            strn0cpy(s, I18nNormalizeLanguageCode(l.languageCode), MAXLANGCODE1);
00569                                            s += strlen(s);
00570                                            if (n++ > 1)
00571                                               break;
00572                                            }
00573                                         }
00574                                     }
00575                                     break;
00576                                default: ;
00577                                }
00578                              delete d;
00579                              }
00580                          if (updatePrimaryDevice)
00581                             cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
00582                          NumApids++;
00583                          apids[NumApids]= 0;
00584                          }
00585                       }
00586                       break;
00587            case 0x06: // STREAMTYPE_13818_PES_PRIVATE
00588                       {
00589                       int dpid = 0;
00590                       int dtype = 0;
00591                       char lang[MAXLANGCODE1] = "";
00592                       SI::Descriptor *d;
00593                       for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
00594                           switch (d->getDescriptorTag()) {
00595                             case SI::AC3DescriptorTag:
00596                             case SI::EnhancedAC3DescriptorTag:
00597                                  dbgpatpmt(" AC3");
00598                                  dpid = stream.getPid();
00599                                  dtype = d->getDescriptorTag();
00600                                  break;
00601                             case SI::SubtitlingDescriptorTag:
00602                                  dbgpatpmt(" subtitling");
00603                                  if (NumSpids < MAXSPIDS) {
00604                                     spids[NumSpids] = stream.getPid();
00605                                     *slangs[NumSpids] = 0;
00606                                     subtitlingTypes[NumSpids] = 0;
00607                                     compositionPageIds[NumSpids] = 0;
00608                                     ancillaryPageIds[NumSpids] = 0;
00609                                     SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d;
00610                                     SI::SubtitlingDescriptor::Subtitling sub;
00611                                     char *s = slangs[NumSpids];
00612                                     int n = 0;
00613                                     for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
00614                                         if (sub.languageCode[0]) {
00615                                            dbgpatpmt(" '%s'", sub.languageCode);
00616                                            subtitlingTypes[NumSpids] = sub.getSubtitlingType();
00617                                            compositionPageIds[NumSpids] = sub.getCompositionPageId();
00618                                            ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
00619                                            if (n > 0)
00620                                               *s++ = '+';
00621                                            strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1);
00622                                            s += strlen(s);
00623                                            if (n++ > 1)
00624                                               break;
00625                                            }
00626                                         }
00627                                     if (updatePrimaryDevice)
00628                                        cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
00629                                     NumSpids++;
00630                                     spids[NumSpids]= 0;
00631                                     }
00632                                  break;
00633                             case SI::TeletextDescriptorTag: {
00634                                  dbgpatpmt(" teletext");
00635                                  tpid = stream.getPid();
00636                                  SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d;
00637                                  SI::TeletextDescriptor::Teletext ttxt;
00638                                  if (totalTtxtSubtitlePages < MAXTXTPAGES) {
00639                                     for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
00640                                         bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
00641                                         if (isSubtitlePage && ttxt.languageCode[0]) {
00642                                            dbgpatpmt(" '%s:%x.%x'", ttxt.languageCode, ttxt.getTeletextMagazineNumber(), ttxt.getTeletextPageNumber());
00643                                            strn0cpy(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1);
00644                                            teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage = ttxt.getTeletextPageNumber();
00645                                            teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine = ttxt.getTeletextMagazineNumber();
00646                                            teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType = ttxt.getTeletextType();
00647                                            totalTtxtSubtitlePages++;
00648                                            if (totalTtxtSubtitlePages >= MAXTXTPAGES)
00649                                               break;
00650                                            }
00651                                         }
00652                                     }
00653                                  }
00654                                  break;
00655                             case SI::ISO639LanguageDescriptorTag: {
00656                                  SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
00657                                  dbgpatpmt(" '%s'", ld->languageCode);
00658                                  strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
00659                                  }
00660                                  break;
00661                             default: ;
00662                             }
00663                           delete d;
00664                           }
00665                       if (dpid) {
00666                          if (NumDpids < MAXDPIDS) {
00667                             dpids[NumDpids] = dpid;
00668                             dtypes[NumDpids] = dtype;
00669                             strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
00670                             if (updatePrimaryDevice && Setup.UseDolbyDigital)
00671                                cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
00672                             NumDpids++;
00673                             dpids[NumDpids]= 0;
00674                             }
00675                          }
00676                       }
00677                       break;
00678            default: ;
00679            }
00680          dbgpatpmt("\n");
00681          if (updatePrimaryDevice) {
00682             cDevice::PrimaryDevice()->EnsureAudioTrack(true);
00683             cDevice::PrimaryDevice()->EnsureSubtitleTrack();
00684             }
00685          }
00686      pmtVersion = Pmt.getVersionNumber();
00687      }
00688   else
00689      esyslog("ERROR: can't parse PMT");
00690   pmtSize = 0;
00691 }
00692 
00693 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
00694 {
00695   PatVersion = patVersion;
00696   PmtVersion = pmtVersion;
00697   return patVersion >= 0 && pmtVersion >= 0;
00698 }
00699 
00700 // --- cTsToPes --------------------------------------------------------------
00701 
00702 cTsToPes::cTsToPes(void)
00703 {
00704   data = NULL;
00705   size = 0;
00706   Reset();
00707 }
00708 
00709 cTsToPes::~cTsToPes()
00710 {
00711   free(data);
00712 }
00713 
00714 void cTsToPes::PutTs(const uchar *Data, int Length)
00715 {
00716   if (TsError(Data)) {
00717      Reset();
00718      return; // ignore packets with TEI set, and drop any PES data collected so far
00719      }
00720   if (TsPayloadStart(Data))
00721      Reset();
00722   else if (!size)
00723      return; // skip everything before the first payload start
00724   Length = TsGetPayload(&Data);
00725   if (length + Length > size) {
00726      int NewSize = max(KILOBYTE(2), length + Length);
00727      if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
00728         data = NewData;
00729         size = NewSize;
00730         }
00731      else {
00732         esyslog("ERROR: out of memory");
00733         Reset();
00734         return;
00735         }
00736      }
00737   memcpy(data + length, Data, Length);
00738   length += Length;
00739 }
00740 
00741 #define MAXPESLENGTH 0xFFF0
00742 
00743 const uchar *cTsToPes::GetPes(int &Length)
00744 {
00745   if (repeatLast) {
00746      repeatLast = false;
00747      Length = lastLength;
00748      return lastData;
00749      }
00750   if (offset < length && PesLongEnough(length)) {
00751      if (!PesHasLength(data)) // this is a video PES packet with undefined length
00752         offset = 6; // trigger setting PES length for initial slice
00753      if (offset) {
00754         uchar *p = data + offset - 6;
00755         if (p != data) {
00756            p -= 3;
00757            if (p < data) {
00758               Reset();
00759               return NULL;
00760               }
00761            memmove(p, data, 4);
00762            }
00763         int l = min(length - offset, MAXPESLENGTH);
00764         offset += l;
00765         if (p != data) {
00766            l += 3;
00767            p[6]  = 0x80;
00768            p[7]  = 0x00;
00769            p[8]  = 0x00;
00770            }
00771         p[4] = l / 256;
00772         p[5] = l & 0xFF;
00773         Length = l + 6;
00774         lastLength = Length;
00775         lastData = p;
00776         return p;
00777         }
00778      else {
00779         Length = PesLength(data);
00780         if (Length <= length) {
00781            offset = Length; // to make sure we break out in case of garbage data
00782            lastLength = Length;
00783            lastData = data;
00784            return data;
00785            }
00786         }
00787      }
00788   return NULL;
00789 }
00790 
00791 void cTsToPes::SetRepeatLast(void)
00792 {
00793   repeatLast = true;
00794 }
00795 
00796 void cTsToPes::Reset(void)
00797 {
00798   length = offset = 0;
00799   lastData = NULL;
00800   lastLength = 0;
00801   repeatLast = false;
00802 }
00803 
00804 // --- Some helper functions for debugging -----------------------------------
00805 
00806 void BlockDump(const char *Name, const u_char *Data, int Length)
00807 {
00808   printf("--- %s\n", Name);
00809   for (int i = 0; i < Length; i++) {
00810       if (i && (i % 16) == 0)
00811          printf("\n");
00812       printf(" %02X", Data[i]);
00813       }
00814   printf("\n");
00815 }
00816 
00817 void TsDump(const char *Name, const u_char *Data, int Length)
00818 {
00819   printf("%s: %04X", Name, Length);
00820   int n = min(Length, 20);
00821   for (int i = 0; i < n; i++)
00822       printf(" %02X", Data[i]);
00823   if (n < Length) {
00824      printf(" ...");
00825      n = max(n, Length - 10);
00826      for (n = max(n, Length - 10); n < Length; n++)
00827          printf(" %02X", Data[n]);
00828      }
00829   printf("\n");
00830 }
00831 
00832 void PesDump(const char *Name, const u_char *Data, int Length)
00833 {
00834   TsDump(Name, Data, Length);
00835 }
00836 
00837 // --- cFrameDetector --------------------------------------------------------
00838 
00839 #define EMPTY_SCANNER (0xFFFFFFFF)
00840 
00841 cFrameDetector::cFrameDetector(int Pid, int Type)
00842 {
00843   SetPid(Pid, Type);
00844   synced = false;
00845   newFrame = independentFrame = false;
00846   numPtsValues = 0;
00847   numFrames = 0;
00848   numIFrames = 0;
00849   framesPerSecond = 0;
00850   framesInPayloadUnit = framesPerPayloadUnit = 0;
00851   payloadUnitOfFrame = 0;
00852   scanning = false;
00853   scanner = EMPTY_SCANNER;
00854 }
00855 
00856 static int CmpUint32(const void *p1, const void *p2)
00857 {
00858   if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
00859   if (*(uint32_t *)p1 > *(uint32_t *)p2) return  1;
00860   return 0;
00861 }
00862 
00863 void cFrameDetector::SetPid(int Pid, int Type)
00864 {
00865   pid = Pid;
00866   type = Type;
00867   isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or 4
00868 }
00869 
00870 void cFrameDetector::Reset(void)
00871 {
00872   newFrame = independentFrame = false;
00873   payloadUnitOfFrame = 0;
00874   scanning = false;
00875   scanner = EMPTY_SCANNER;
00876 }
00877 
00878 int cFrameDetector::SkipPackets(const uchar *&Data, int &Length, int &Processed, int &FrameTypeOffset)
00879 {
00880   if (!synced)
00881      dbgframes("%d>", FrameTypeOffset);
00882   while (Length >= TS_SIZE) {
00883         // switch to the next TS packet, but skip those that have a different PID:
00884         Data += TS_SIZE;
00885         Length -= TS_SIZE;
00886         Processed += TS_SIZE;
00887         if (TsPid(Data) == pid)
00888            break;
00889         else if (Length < TS_SIZE)
00890            esyslog("ERROR: out of data while skipping TS packets in cFrameDetector");
00891         }
00892   FrameTypeOffset -= TS_SIZE;
00893   FrameTypeOffset += TsPayloadOffset(Data);
00894   return FrameTypeOffset;
00895 }
00896 
00897 int cFrameDetector::Analyze(const uchar *Data, int Length)
00898 {
00899   int SeenPayloadStart = false;
00900   int Processed = 0;
00901   newFrame = independentFrame = false;
00902   while (Length >= TS_SIZE) {
00903         if (Data[0] != TS_SYNC_BYTE) {
00904            int Skipped = 1;
00905            while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE))
00906                  Skipped++;
00907            esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
00908            return Processed + Skipped;
00909            }
00910         if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
00911            int Pid = TsPid(Data);
00912            if (Pid == pid) {
00913               if (TsPayloadStart(Data)) {
00914                  SeenPayloadStart = true;
00915                  if (synced && Processed)
00916                     return Processed;
00917                  if (Length < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE)
00918                     return Processed; // need more data, in case the frame type is not stored in the first TS packet
00919                  if (framesPerSecond <= 0.0) {
00920                     // frame rate unknown, so collect a sequence of PTS values:
00921                     if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
00922                        const uchar *Pes = Data + TsPayloadOffset(Data);
00923                        if (numIFrames && PesHasPts(Pes)) {
00924                           ptsValues[numPtsValues] = PesGetPts(Pes);
00925                           // check for rollover:
00926                           if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
00927                              dbgframes("#");
00928                              numPtsValues = 0;
00929                              numIFrames = 0;
00930                              numFrames = 0;
00931                              }
00932                           else
00933                              numPtsValues++;
00934                           }
00935                        }
00936                     else {
00937                        // find the smallest PTS delta:
00938                        qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
00939                        numPtsValues--;
00940                        for (int i = 0; i < numPtsValues; i++)
00941                            ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
00942                        qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
00943                        uint32_t Delta = ptsValues[0];
00944                        // determine frame info:
00945                        if (isVideo) {
00946                           if (abs(Delta - 3600) <= 1)
00947                              framesPerSecond = 25.0;
00948                           else if (Delta % 3003 == 0)
00949                              framesPerSecond = 30.0 / 1.001;
00950                           else if (abs(Delta - 1800) <= 1) {
00951                              if (numFrames > 50) {
00952                                 // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
00953                                 framesPerSecond = 25.0;
00954                                 framesPerPayloadUnit = -2;
00955                                 }
00956                              else
00957                                 framesPerSecond = 50.0;
00958                              }
00959                           else if (Delta == 1501)
00960                              if (numFrames > 50) {
00961                                 // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
00962                                 framesPerSecond = 30.0 / 1.001;
00963                                 framesPerPayloadUnit = -2;
00964                                 }
00965                              else
00966                                 framesPerSecond = 60.0 / 1.001;
00967                           else {
00968                              framesPerSecond = DEFAULTFRAMESPERSECOND;
00969                              dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
00970                              }
00971                           }
00972                        else // audio
00973                           framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
00974                        dbgframes("\nDelta = %d  FPS = %5.2f  FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames);
00975                        }
00976                     }
00977                  scanner = EMPTY_SCANNER;
00978                  scanning = true;
00979                  }
00980               if (scanning) {
00981                  int PayloadOffset = TsPayloadOffset(Data);
00982                  if (TsPayloadStart(Data)) {
00983                     PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
00984                     if (!framesPerPayloadUnit)
00985                        framesPerPayloadUnit = framesInPayloadUnit;
00986                     if (DebugFrames && !synced)
00987                        dbgframes("/");
00988                     }
00989                  for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
00990                      scanner <<= 8;
00991                      scanner |= Data[i];
00992                      switch (type) {
00993                        case 0x01: // MPEG 1 video
00994                        case 0x02: // MPEG 2 video
00995                             if (scanner == 0x00000100) { // Picture Start Code
00996                                scanner = EMPTY_SCANNER;
00997                                if (synced && !SeenPayloadStart && Processed)
00998                                   return Processed; // flush everything before this new frame
00999                                int FrameTypeOffset = i + 2;
01000                                if (FrameTypeOffset >= TS_SIZE) // the byte to check is in the next TS packet
01001                                   i = SkipPackets(Data, Length, Processed, FrameTypeOffset);
01002                                newFrame = true;
01003                                uchar FrameType = (Data[FrameTypeOffset] >> 3) & 0x07;
01004                                independentFrame = FrameType == 1; // I-Frame
01005                                if (synced) {
01006                                   if (framesPerPayloadUnit <= 1)
01007                                      scanning = false;
01008                                   }
01009                                else {
01010                                   framesInPayloadUnit++;
01011                                   if (independentFrame)
01012                                      numIFrames++;
01013                                   if (numIFrames == 1)
01014                                      numFrames++;
01015                                   dbgframes("%u ", FrameType);
01016                                   }
01017                                if (synced)
01018                                   return Processed + TS_SIZE; // flag this new frame
01019                                }
01020                             break;
01021                        case 0x1B: // MPEG 4 video
01022                             if (scanner == 0x00000109) { // Access Unit Delimiter
01023                                scanner = EMPTY_SCANNER;
01024                                if (synced && !SeenPayloadStart && Processed)
01025                                   return Processed; // flush everything before this new frame
01026                                int FrameTypeOffset = i + 1;
01027                                if (FrameTypeOffset >= TS_SIZE) // the byte to check is in the next TS packet
01028                                   i = SkipPackets(Data, Length, Processed, FrameTypeOffset);
01029                                newFrame = true;
01030                                uchar FrameType = Data[FrameTypeOffset];
01031                                independentFrame = FrameType == 0x10;
01032                                if (synced) {
01033                                   if (framesPerPayloadUnit < 0) {
01034                                      payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
01035                                      if (payloadUnitOfFrame != 0 && independentFrame)
01036                                         payloadUnitOfFrame = 0;
01037                                      if (payloadUnitOfFrame)
01038                                         newFrame = false;
01039                                      }
01040                                   if (framesPerPayloadUnit <= 1)
01041                                      scanning = false;
01042                                   }
01043                                else {
01044                                   framesInPayloadUnit++;
01045                                   if (independentFrame)
01046                                      numIFrames++;
01047                                   if (numIFrames == 1)
01048                                      numFrames++;
01049                                   dbgframes("%02X ", FrameType);
01050                                   }
01051                                if (synced)
01052                                   return Processed + TS_SIZE; // flag this new frame
01053                                }
01054                             break;
01055                        case 0x04: // MPEG audio
01056                        case 0x06: // AC3 audio
01057                             if (synced && Processed)
01058                                return Processed;
01059                             newFrame = true;
01060                             independentFrame = true;
01061                             if (!synced) {
01062                                framesInPayloadUnit = 1;
01063                                if (TsPayloadStart(Data))
01064                                   numIFrames++;
01065                                }
01066                             scanning = false;
01067                             break;
01068                        default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
01069                                 pid = 0; // let's just ignore any further data
01070                        }
01071                      }
01072                  if (!synced && framesPerSecond > 0.0 && independentFrame) {
01073                     synced = true;
01074                     dbgframes("*\n");
01075                     Reset();
01076                     return Processed + TS_SIZE;
01077                     }
01078                  }
01079               }
01080            else if (Pid == PATPID && synced && Processed)
01081               return Processed; // allow the caller to see any PAT packets
01082            }
01083         Data += TS_SIZE;
01084         Length -= TS_SIZE;
01085         Processed += TS_SIZE;
01086         }
01087   return Processed;
01088 }