vdr
1.7.27
|
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 }