Ticket #438: multiplePMT.patch
File multiplePMT.patch, 11.7 KB (added by , 20 years ago) |
---|
-
mpegstreamdata.cpp
89 89 /** \fn MPEGStreamData::AssemblePSIP(const TSPacket* tspacket) 90 90 * \brief PES packet assembler. 91 91 * 92 * This only assembles PES packets when new PES packets 93 * start in their own TSPacket. This is always true of 94 * ATSC & DVB tables, but not true of Audio and Video 95 * PES packets. 92 * This only starts assembling PES packets when new PES 93 * packets start in their own TSPacket. 94 * 95 * DVB TSPackets may contain multiple segments of the PSI 96 * stream. (see ISO 13818-1 section 2.4.3.3, particularly 97 * the definition of payload_unit_start_indicator, which 98 * indicates there is at least one segment start, but not 99 * limited to only one segment start.) 100 * 101 * PSI stuffing bytes are 0xFF and will complete the 102 * remaining portion of the TSPacket. (Section 2.4.4) 103 * 104 * \note This method makes the assumption that AddTSPacket 105 * correctly handles duplicate packets. 96 106 */ 97 PSIPTable* MPEGStreamData::AssemblePSIP(const TSPacket* tspacket )107 PSIPTable* MPEGStreamData::AssemblePSIP(const TSPacket* tspacket, bool &moreTablePackets) 98 108 { 109 moreTablePackets = true; 110 111 PESPacket* partial = GetPartialPES(tspacket->PID()); 112 if (partial) 113 { 114 if (partial->AddTSPacket(tspacket)) 115 { 116 PSIPTable* psip = new PSIPTable(*partial); 117 118 // Advance to the next packet 119 unsigned int packetStart = partial->PSIOffset() + psip->SectionLength(); 120 if (packetStart < partial->TSSizeInBuffer()) { 121 if (partial->pesdata()[psip->SectionLength() + 1] != 0xff) { 122 // If the next section starts in the new tspacket 123 // create a new partial packet to prevent overflow 124 if ((partial->TSSizeInBuffer() > TSPacket::HEADER_SIZE + TSPacket::PAYLOAD_SIZE) 125 && (packetStart > partial->TSSizeInBuffer() - TSPacket::PAYLOAD_SIZE)) { 126 // Saving will handle deleting the old one 127 SavePartialPES(tspacket->PID(), new PESPacket(*tspacket)); 128 } else { 129 partial->SetPSIOffset(partial->PSIOffset() + psip->SectionLength()); 130 } 131 return psip; 132 } 133 } 134 135 moreTablePackets = false; 136 DeletePartialPES(tspacket->PID()); 137 return psip; 138 } 139 moreTablePackets = false; 140 return 0; // partial packet is not yet complete. 141 } 142 99 143 if (tspacket->PayloadStart()) 100 144 { 101 145 const int offset = tspacket->AFCOffset() + 102 146 tspacket->StartOfFieldPointer(); 147 103 148 if (offset>181) 104 149 { 105 150 VERBOSE(VB_IMPORTANT, "Error: offset>181, pes length & " … … 111 156 const PESPacket pes = PESPacket::View(*tspacket); 112 157 if ((pes_length + offset)>188) 113 158 { 114 if (!bool(pes.pesdata()[6]&1)/*current*/)115 return 0; // we only care about current psip packets for now116 159 SavePartialPES(tspacket->PID(), new PESPacket(*tspacket)); 160 moreTablePackets = false; 117 161 return 0; 118 162 } 119 return new PSIPTable(*tspacket); // must be complete packet120 }121 163 122 PESPacket* partial = GetPartialPES(tspacket->PID()); 123 if (partial) 124 { 125 if (partial->AddTSPacket(tspacket)) 126 { 127 PSIPTable* psip = new PSIPTable(*partial); 128 DeletePartialPES(tspacket->PID()); 129 return psip; 164 PSIPTable *psip = new PSIPTable(*tspacket); // must be complete packet 165 166 /* There might be another section after this one in the current packet. 167 * We need room before the end of the packet, and it must not be packet stuffing. 168 */ 169 if (offset + psip->SectionLength() < 188) { 170 if (pesdata[psip->SectionLength() + 1] != 0xff) { 171 // This isn't sutffing, so we need to put this on as a partial packet 172 PESPacket *pesp = new PESPacket(*tspacket); 173 pesp->SetPSIOffset(offset + psip->SectionLength()); 174 SavePartialPES(tspacket->PID(), pesp); 175 return psip; 176 } 130 177 } 131 return 0; // partial packet is not yet complete. 178 179 moreTablePackets = false; 180 return psip; 132 181 } 182 133 183 // We didn't see this PES packet's start, so this must be the 134 184 // tail end of something we missed. Ignore it. 185 moreTablePackets = false; 135 186 return 0; 136 187 } 137 188 … … 359 410 */ 360 411 bool MPEGStreamData::HandleTSTables(const TSPacket* tspacket) 361 412 { 362 #define HT_RETURN(HANDLED) { delete psip; return HANDLED; }363 413 // Assemble PSIP 364 PSIPTable *psip = AssemblePSIP(tspacket); 365 if (!psip) 366 return true; 414 bool morePSIPPackets = true; 415 while (morePSIPPackets) { 416 PSIPTable *psip = AssemblePSIP(tspacket, morePSIPPackets); 417 if (!psip) 418 return true; 367 419 368 // Validate PSIP 369 // but don't validate PMT if our driver has the PMT CRC bug. 370 bool validate = !_have_pmt_CRC_bug || (TableID::PMT != psip->TableID()); 371 if (validate && !psip->IsGood()) 372 { 373 VERBOSE(VB_RECORD, QString("PSIP packet failed CRC check. " 374 "pid(0x%1) type(0x%2)") 375 .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16)); 376 HT_RETURN(true); 377 } 420 // Validate PSIP 421 // but don't validate PMT if our driver has the PMT CRC bug. 422 bool validate = !_have_pmt_CRC_bug || (TableID::PMT != psip->TableID()); 423 if (validate && !psip->IsGood()) 424 { 425 VERBOSE(VB_RECORD, QString("PSIP packet failed CRC check. " 426 "pid(0x%1) type(0x%2)") 427 .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16)); 428 delete psip; 429 continue; 430 } 378 431 379 if (!psip->IsCurrent()) // we don't cache the next table, for now 380 HT_RETURN(true); 432 if (!psip->IsCurrent()) { // we don't cache the next table, for now 433 delete psip; 434 continue; 435 } 381 436 382 if (1!=tspacket->AdaptationFieldControl()) 383 { // payload only, ATSC req. 384 VERBOSE(VB_RECORD, 385 "PSIP packet has Adaptation Field Control, not ATSC compiant"); 386 HT_RETURN(true); 387 } 437 if (1!=tspacket->AdaptationFieldControl()) 438 { // payload only, ATSC req. 439 VERBOSE(VB_RECORD, 440 "PSIP packet has Adaptation Field Control, not ATSC compiant"); 441 delete psip; 442 continue; 443 } 388 444 389 if (tspacket->ScramplingControl()) 390 { // scrambled! ATSC, DVB require tables not to be scrambled 391 VERBOSE(VB_RECORD, 392 "PSIP packet is scrambled, not ATSC/DVB compiant"); 393 HT_RETURN(true); 394 } 445 if (tspacket->ScramplingControl()) 446 { // scrambled! ATSC, DVB require tables not to be scrambled 447 VERBOSE(VB_RECORD, 448 "PSIP packet is scrambled, not ATSC/DVB compiant"); 449 delete psip; 450 continue; 451 } 395 452 396 // Don't decode redundant packets, 397 // but if it is a desired PAT or PMT emit a "heartbeat" signal. 398 if (IsRedundant(*psip)) 399 { 400 if (TableID::PAT == psip->TableID()) 401 emit UpdatePATSingleProgram(PATSingleProgram()); 402 if (TableID::PMT == psip->TableID() && 403 tspacket->PID() == _pid_pmt_single_program) 404 emit UpdatePMTSingleProgram(PMTSingleProgram()); 405 HT_RETURN(true); // already parsed this table, toss it. 406 } 453 // Don't decode redundant packets, 454 // but if it is a desired PAT or PMT emit a "heartbeat" signal. 455 if (IsRedundant(*psip)) 456 { 457 if (TableID::PAT == psip->TableID()) 458 emit UpdatePATSingleProgram(PATSingleProgram()); 459 if (TableID::PMT == psip->TableID() && 460 tspacket->PID() == _pid_pmt_single_program) 461 emit UpdatePMTSingleProgram(PMTSingleProgram()); 462 delete psip; // already parsed this table, toss it. 463 continue; 464 } 407 465 408 bool handled = HandleTables(tspacket->PID(), *psip); 409 HT_RETURN(handled); 410 #undef HT_RETURN 466 HandleTables(tspacket->PID(), *psip); 467 delete psip; 468 }; 469 return true; 411 470 } 412 471 413 472 int MPEGStreamData::ProcessData(unsigned char *buffer, int len) -
mpegstreamdata.h
128 128 129 129 protected: 130 130 // Table processing -- for internal use 131 PSIPTable* AssemblePSIP(const TSPacket* tspacket );131 PSIPTable* AssemblePSIP(const TSPacket* tspacket, bool& moreTablePackets); 132 132 bool AssemblePSIP(PSIPTable& psip, TSPacket* tspacket); 133 133 void SavePartialPES(uint pid, PESPacket* packet); 134 134 PESPacket* GetPartialPES(uint pid) -
pespacket.h
32 32 { 33 33 _pesdata = tspacket.data() + tspacket.AFCOffset() + 34 34 tspacket.StartOfFieldPointer(); 35 _PSIOffset = tspacket.AFCOffset() + tspacket.StartOfFieldPointer(); 35 36 } 36 37 else 37 38 { 38 39 cerr<<"Started PESPacket, but !payloadStart()"<<endl; 39 40 _pesdata = tspacket.data() + tspacket.AFCOffset(); 41 _PSIOffset = tspacket.AFCOffset(); 40 42 } 41 43 42 44 _badPacket = true; … … 49 51 protected: 50 52 // does not create it's own data 51 53 PESPacket(const TSPacket* tspacket, bool) 52 : _pesdata(0), _fullbuffer(0), _allocSize(0) 54 : _pesdata(0), _fullbuffer(0), _allocSize(0), _PSIOffset(0) 53 55 { 54 56 InitPESPacket(const_cast<TSPacket&>(*tspacket)); 55 57 _fullbuffer = const_cast<unsigned char*>(tspacket->data()); … … 64 66 _allocSize = pkt._allocSize; 65 67 _fullbuffer = new unsigned char[_allocSize+188]; 66 68 memcpy(_fullbuffer, pkt._fullbuffer, _allocSize+188); 67 _pesdata = _fullbuffer + (pkt._pesdata - pkt._fullbuffer); 69 _PSIOffset = pkt._PSIOffset; 70 _pesdata = _fullbuffer + _PSIOffset; 68 71 _ccLast = pkt._ccLast; 69 72 _cnt = pkt._cnt; 70 73 _badPacket = pkt._badPacket; … … 76 79 InitPESPacket(const_cast<TSPacket&>(tspacket)); 77 80 78 81 int len = (4*1024) - 188; 79 int offset = _pesdata - tspacket.data(); 80 _allocSize=((len+offset)/188)*188+188; 82 _allocSize=((len+_PSIOffset)/188)*188+188; 81 83 _fullbuffer = new unsigned char[_allocSize+188]; 82 _pesdata = _fullbuffer + offset;84 _pesdata = _fullbuffer + _PSIOffset; 83 85 memcpy(_fullbuffer, tspacket.data(), 188); 84 86 _ccLast = tspacket.ContinuityCounter(); 85 87 _cnt = 1; … … 116 118 unsigned int Length() const 117 119 { return (pesdata()[2] & 0x0f) << 8 | pesdata()[3]; } 118 120 121 unsigned int TSSizeInBuffer() { return (_cnt*TSPacket::PAYLOAD_SIZE)+TSPacket::HEADER_SIZE; } 122 unsigned int PSIOffset() const { return _PSIOffset; } 123 119 124 const unsigned char* pesdata() const { return _pesdata; } 120 125 unsigned char* pesdata() { return _pesdata; } 121 126 … … 153 158 _pesdata[Length()+3] = (crc & 0x000000ff); 154 159 } 155 160 161 void SetPSIOffset(unsigned int offset) { 162 _PSIOffset = offset; 163 _pesdata = _fullbuffer + _PSIOffset; 164 } 165 156 166 bool VerifyCRC() const { return CalcCRC() == CRC(); } 157 167 158 168 /* … … 177 187 unsigned int _ccLast; 178 188 unsigned int _cnt; 179 189 unsigned int _allocSize; 190 unsigned int _PSIOffset; 180 191 bool _badPacket; 181 192 }; 182 193