|
MythTV
0.26-pre
|
00001 // -*- Mode: c++ -*- 00002 // Copyright (c) 2003-2004, Daniel Thor Kristjansson 00003 00004 #include <algorithm> // for find & max 00005 using namespace std; 00006 00007 // POSIX headers 00008 #include <sys/time.h> // for gettimeofday 00009 00010 // Qt headers 00011 #include <QString> 00012 00013 // MythTV headers 00014 #include "mpegstreamdata.h" 00015 #include "mpegtables.h" 00016 #include "ringbuffer.h" 00017 #include "mpegtables.h" 00018 00019 #include "atscstreamdata.h" 00020 #include "atsctables.h" 00021 00022 //#define DEBUG_MPEG_RADIO // uncomment to strip video streams from TS stream 00023 00024 void init_sections(sections_t §, uint last_section) 00025 { 00026 static const unsigned char init_bits[8] = 00027 { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, }; 00028 00029 sect.clear(); 00030 00031 uint endz = last_section >> 3; 00032 if (endz) 00033 sect.resize(endz, 0x00); 00034 sect.resize(32, 0xff); 00035 sect[endz] = init_bits[last_section & 0x7]; 00036 00037 #if 0 00038 { 00039 QString msg = QString("init_sections ls(%1): ").arg(last_section); 00040 for (uint i = 0 ; i < 32; i++) 00041 msg += QString("%1 ").arg((int)sect[i], 0, 16); 00042 LOG(VB_GENERAL, LOG_DEBUG, msg); 00043 } 00044 #endif 00045 } 00046 00047 const unsigned char MPEGStreamData::bit_sel[8] = 00048 { 00049 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 00050 }; 00051 00065 MPEGStreamData::MPEGStreamData(int desiredProgram, bool cacheTables) 00066 : _sistandard("mpeg"), 00067 _have_CRC_bug(false), 00068 _local_utc_offset(0), _si_time_offset_cnt(0), 00069 _si_time_offset_indx(0), 00070 _eit_helper(NULL), _eit_rate(0.0f), 00071 _listening_disabled(false), 00072 _encryption_lock(QMutex::Recursive), _listener_lock(QMutex::Recursive), 00073 _cache_tables(cacheTables), _cache_lock(QMutex::Recursive), 00074 // Single program stuff 00075 _desired_program(desiredProgram), 00076 _recording_type("all"), 00077 _strip_pmt_descriptors(false), 00078 _normalize_stream_type(true), 00079 _pid_video_single_program(0xffffffff), 00080 _pid_pmt_single_program(0xffffffff), 00081 _pmt_single_program_num_video(1), 00082 _pmt_single_program_num_audio(0), 00083 _pat_single_program(NULL), _pmt_single_program(NULL), 00084 _invalid_pat_seen(false), _invalid_pat_warning(false) 00085 { 00086 _local_utc_offset = calc_utc_offset(); 00087 00088 memset(_si_time_offsets, 0, sizeof(_si_time_offsets)); 00089 00090 AddListeningPID(MPEG_PAT_PID); 00091 AddListeningPID(MPEG_CAT_PID); 00092 } 00093 00094 MPEGStreamData::~MPEGStreamData() 00095 { 00096 Reset(-1); 00097 SetPATSingleProgram(NULL); 00098 SetPMTSingleProgram(NULL); 00099 00100 // Delete any cached tables that haven't been returned 00101 psip_refcnt_map_t::iterator it = _cached_slated_for_deletion.begin(); 00102 for (; it != _cached_slated_for_deletion.end(); ++it) 00103 delete it.key(); 00104 00105 QMutexLocker locker(&_listener_lock); 00106 _mpeg_listeners.clear(); 00107 _mpeg_sp_listeners.clear(); 00108 } 00109 00110 void MPEGStreamData::SetDesiredProgram(int p) 00111 { 00112 bool reset = true; 00113 uint pid = 0; 00114 const ProgramAssociationTable* pat = NULL; 00115 pat_vec_t pats = GetCachedPATs(); 00116 00117 for (uint i = (p) ? 0 : pats.size(); i < pats.size() && !pid; i++) 00118 { 00119 pat = pats[i]; 00120 pid = pats[i]->FindPID(p); 00121 } 00122 00123 if (pid) 00124 { 00125 reset = false; 00126 _desired_program = p; 00127 ProcessPAT(pat); 00128 pmt_vec_t pmts = GetCachedPMTs(); 00129 for (uint i = 0; i < pmts.size(); i++) 00130 { 00131 if (pmts[i]->ProgramNumber() == (uint)p) 00132 ProcessPMT(pmts[i]); 00133 } 00134 ReturnCachedPMTTables(pmts); 00135 } 00136 00137 ReturnCachedPATTables(pats); 00138 00139 if (reset) 00140 Reset(p); 00141 } 00142 00143 void MPEGStreamData::SetRecordingType(const QString &recording_type) 00144 { 00145 _recording_type = recording_type; 00146 _recording_type.detach(); 00147 uint neededVideo = (_recording_type == "tv") ? 1 : 0; 00148 uint neededAudio = (_recording_type == "audio") ? 1 : 0; 00149 SetVideoStreamsRequired(neededVideo); 00150 SetAudioStreamsRequired(neededAudio); 00151 } 00152 00153 QString MPEGStreamData::GetRecordingType(void) const 00154 { 00155 QString tmp = _recording_type; 00156 tmp.detach(); 00157 return tmp; 00158 } 00159 00160 void MPEGStreamData::SetEITHelper(EITHelper *eit_helper) 00161 { 00162 QMutexLocker locker(&_listener_lock); 00163 _eit_helper = eit_helper; 00164 } 00165 00166 void MPEGStreamData::SetEITRate(float rate) 00167 { 00168 QMutexLocker locker(&_listener_lock); 00169 _eit_rate = rate; 00170 } 00171 00172 void MPEGStreamData::Reset(int desiredProgram) 00173 { 00174 _desired_program = desiredProgram; 00175 _recording_type = "all"; 00176 _strip_pmt_descriptors = false; 00177 _normalize_stream_type = true; 00178 00179 _invalid_pat_seen = false; 00180 00181 SetPATSingleProgram(NULL); 00182 SetPMTSingleProgram(NULL); 00183 00184 pid_psip_map_t old = _partial_psip_packet_cache; 00185 pid_psip_map_t::iterator it = old.begin(); 00186 for (; it != old.end(); ++it) 00187 DeletePartialPSIP(it.key()); 00188 _partial_psip_packet_cache.clear(); 00189 00190 _pids_listening.clear(); 00191 _pids_notlistening.clear(); 00192 _pids_writing.clear(); 00193 _pids_audio.clear(); 00194 00195 _pid_video_single_program = _pid_pmt_single_program = 0xffffffff; 00196 00197 _pat_version.clear(); 00198 _pat_section_seen.clear(); 00199 00200 _pmt_version.clear(); 00201 _pmt_section_seen.clear(); 00202 00203 { 00204 QMutexLocker locker(&_cache_lock); 00205 00206 pat_cache_t::iterator it1 = _cached_pats.begin(); 00207 for (; it1 != _cached_pats.end(); ++it1) 00208 DeleteCachedTable(*it1); 00209 _cached_pats.clear(); 00210 00211 pmt_cache_t::iterator it2 = _cached_pmts.begin(); 00212 for (; it2 != _cached_pmts.end(); ++it2) 00213 DeleteCachedTable(*it2); 00214 _cached_pmts.clear(); 00215 00216 cat_cache_t::iterator it3 = _cached_cats.begin(); 00217 for (; it3 != _cached_cats.end(); ++it3) 00218 DeleteCachedTable(*it3); 00219 _cached_cats.clear(); 00220 } 00221 00222 ResetDecryptionMonitoringState(); 00223 00224 AddListeningPID(MPEG_PAT_PID); 00225 AddListeningPID(MPEG_CAT_PID); 00226 } 00227 00228 void MPEGStreamData::DeletePartialPSIP(uint pid) 00229 { 00230 pid_psip_map_t::iterator it = _partial_psip_packet_cache.find(pid); 00231 if (it != _partial_psip_packet_cache.end()) 00232 { 00233 PSIPTable *pkt = *it; 00234 _partial_psip_packet_cache.erase(it); 00235 delete pkt; 00236 } 00237 } 00238 00260 PSIPTable* MPEGStreamData::AssemblePSIP(const TSPacket* tspacket, 00261 bool &moreTablePackets) 00262 { 00263 bool broken = true; 00264 moreTablePackets = true; 00265 00266 PSIPTable* partial = GetPartialPSIP(tspacket->PID()); 00267 if (partial && partial->AddTSPacket(tspacket, broken) && !broken) 00268 { 00269 // check if it's safe to read pespacket's Length() 00270 if ((partial->PSIOffset() + 1 + 3) > partial->TSSizeInBuffer()) 00271 { 00272 LOG(VB_RECORD, LOG_ERR, 00273 QString("Discarding broken PSIP packet. Packet's length at " 00274 "position %1 isn't in the buffer of %2 bytes.") 00275 .arg(partial->PSIOffset() + 1 + 3) 00276 .arg(partial->TSSizeInBuffer())); 00277 DeletePartialPSIP(tspacket->PID()); 00278 return NULL; 00279 } 00280 00281 // Discard broken packets 00282 bool buggy = _have_CRC_bug && 00283 ((TableID::PMT == partial->StreamID()) || 00284 (TableID::PAT == partial->StreamID())); 00285 if (!buggy && !partial->IsGood()) 00286 { 00287 LOG(VB_SIPARSER, LOG_ERR, "Discarding broken PSIP packet"); 00288 DeletePartialPSIP(tspacket->PID()); 00289 return NULL; 00290 } 00291 00292 PSIPTable* psip = new PSIPTable(*partial); 00293 00294 // Advance to the next packet 00295 // pesdata starts only at PSIOffset()+1 00296 uint packetStart = partial->PSIOffset() + 1 + psip->SectionLength(); 00297 if (packetStart < partial->TSSizeInBuffer()) 00298 { 00299 if (partial->pesdata()[psip->SectionLength()] != 0xff) 00300 { 00301 #if 0 /* This doesn't work, you can't start PSIP packet like this 00302 because the PayloadStart() flag won't be set in this TSPacket 00303 -- dtk May 4th, 2007 00304 */ 00305 00306 // If the next section starts in the new tspacket 00307 // create a new partial packet to prevent overflow 00308 if ((partial->TSSizeInBuffer() > TSPacket::kSize) && 00309 (packetStart > 00310 partial->TSSizeInBuffer() - TSPacket::PAYLOAD_SIZE)) 00311 { 00312 // Saving will handle deleting the old one 00313 SavePartialPSIP(tspacket->PID(), 00314 new PSIPTable(*tspacket)); 00315 } 00316 else 00317 #endif 00318 { 00319 partial->SetPSIOffset(partial->PSIOffset() + 00320 psip->SectionLength()); 00321 } 00322 return psip; 00323 } 00324 } 00325 // discard incomplete packets 00326 if (packetStart > partial->TSSizeInBuffer()) 00327 { 00328 LOG(VB_RECORD, LOG_ERR, 00329 QString("Discarding broken PSIP packet. ") + 00330 QString("Packet with %1 bytes doesn't fit " 00331 "into a buffer of %2 bytes.") 00332 .arg(packetStart).arg(partial->TSSizeInBuffer())); 00333 delete psip; 00334 psip = NULL; 00335 } 00336 00337 moreTablePackets = false; 00338 DeletePartialPSIP(tspacket->PID()); 00339 return psip; 00340 } 00341 else if (partial) 00342 { 00343 if (broken) 00344 DeletePartialPSIP(tspacket->PID()); 00345 00346 moreTablePackets = false; 00347 return 0; // partial packet is not yet complete. 00348 } 00349 00350 if (!tspacket->PayloadStart()) 00351 { 00352 // We didn't see this PSIP packet's start, so this must be the 00353 // tail end of something we missed. Ignore it. 00354 moreTablePackets = false; 00355 return 0; 00356 } 00357 00358 const int offset = tspacket->AFCOffset() + tspacket->StartOfFieldPointer(); 00359 if (offset>181) 00360 { 00361 LOG(VB_GENERAL, LOG_ERR, "Error: offset>181, pes length & " 00362 "current cannot be queried"); 00363 return 0; 00364 } 00365 00366 // table_id (8 bits) and section_length(12), syntax(1), priv(1), res(2) 00367 // pointer_field (+8 bits), since payload start is true if we are here. 00368 const int extra_offset = 4; 00369 00370 const unsigned char* pesdata = tspacket->data() + offset; 00371 const int pes_length = (pesdata[2] & 0x0f) << 8 | pesdata[3]; 00372 if ((pes_length + offset + extra_offset) > 188) 00373 { 00374 SavePartialPSIP(tspacket->PID(), new PSIPTable(*tspacket)); 00375 moreTablePackets = false; 00376 return 0; 00377 } 00378 00379 PSIPTable *psip = new PSIPTable(*tspacket); // must be complete packet 00380 00381 // There might be another section after this one in the 00382 // current packet. We need room before the end of the 00383 // packet, and it must not be packet stuffing. 00384 if ((offset + psip->SectionLength() < TSPacket::kSize) && 00385 (pesdata[psip->SectionLength() + 1] != 0xff)) 00386 { 00387 // This isn't stuffing, so we need to put this 00388 // on as a partial packet. 00389 PSIPTable *pesp = new PSIPTable(*tspacket); 00390 pesp->SetPSIOffset(offset + psip->SectionLength()); 00391 SavePartialPSIP(tspacket->PID(), pesp); 00392 return psip; 00393 } 00394 00395 moreTablePackets = false; 00396 return psip; 00397 } 00398 00399 bool MPEGStreamData::CreatePATSingleProgram( 00400 const ProgramAssociationTable& pat) 00401 { 00402 LOG(VB_RECORD, LOG_INFO, "CreatePATSingleProgram()"); 00403 LOG(VB_RECORD, LOG_INFO, "PAT in input stream"); 00404 LOG(VB_RECORD, LOG_INFO, pat.toString()); 00405 if (_desired_program < 0) 00406 { 00407 LOG(VB_RECORD, LOG_ERR, "Desired program not set yet"); 00408 return false; 00409 } 00410 _pid_pmt_single_program = pat.FindPID(_desired_program); 00411 LOG(VB_RECORD, LOG_INFO, QString("desired_program(%1) pid(0x%2)"). 00412 arg(_desired_program).arg(_pid_pmt_single_program, 0, 16)); 00413 00414 if (!_pid_pmt_single_program) 00415 { 00416 _pid_pmt_single_program = pat.FindAnyPID(); 00417 if (!_pid_pmt_single_program) 00418 { 00419 LOG(VB_GENERAL, LOG_ERR, "No program found in PAT. " 00420 "This recording will not play in MythTV."); 00421 } 00422 LOG(VB_GENERAL, LOG_ERR, 00423 QString("Desired program #%1 not found in PAT." 00424 "\n\t\t\tCannot create single program PAT.") 00425 .arg(_desired_program)); 00426 SetPATSingleProgram(NULL); 00427 return false; 00428 } 00429 00430 AddListeningPID(_pid_pmt_single_program); 00431 00432 vector<uint> pnums, pids; 00433 00434 pnums.push_back(1); 00435 pids.push_back(_pid_pmt_single_program); 00436 00437 uint tsid = pat.TableIDExtension(); 00438 uint ver = pat.Version(); 00439 ProgramAssociationTable* pat2 = 00440 ProgramAssociationTable::Create(tsid, ver, pnums, pids); 00441 00442 if (!pat2) 00443 { 00444 LOG(VB_GENERAL, LOG_ERR, 00445 "MPEGStreamData::CreatePATSingleProgram: " 00446 "Failed to create Program Association Table."); 00447 return false; 00448 } 00449 00450 pat2->tsheader()->SetContinuityCounter(pat.tsheader()->ContinuityCounter()); 00451 00452 LOG(VB_RECORD, LOG_INFO, QString("pmt_pid(0x%1)") 00453 .arg(_pid_pmt_single_program, 0, 16)); 00454 LOG(VB_RECORD, LOG_INFO, "PAT for output stream"); 00455 LOG(VB_RECORD, LOG_INFO, pat2->toString()); 00456 00457 SetPATSingleProgram(pat2); 00458 00459 return true; 00460 00461 } 00462 00463 static desc_list_t extract_atsc_desc(const tvct_vec_t &tvct, 00464 const cvct_vec_t &cvct, 00465 uint pnum) 00466 { 00467 desc_list_t desc; 00468 00469 vector<const VirtualChannelTable*> vct; 00470 00471 for (uint i = 0; i < tvct.size(); i++) 00472 vct.push_back(tvct[i]); 00473 00474 for (uint i = 0; i < cvct.size(); i++) 00475 vct.push_back(cvct[i]); 00476 00477 for (uint i = 0; i < tvct.size(); i++) 00478 { 00479 for (uint j = 0; j < vct[i]->ChannelCount(); j++) 00480 { 00481 if (vct[i]->ProgramNumber(j) == pnum) 00482 { 00483 desc_list_t ldesc = MPEGDescriptor::ParseOnlyInclude( 00484 vct[i]->Descriptors(j), vct[i]->DescriptorsLength(j), 00485 DescriptorID::caption_service); 00486 00487 if (!ldesc.empty()) 00488 desc.insert(desc.end(), ldesc.begin(), ldesc.end()); 00489 } 00490 } 00491 00492 if (0 != vct[i]->GlobalDescriptorsLength()) 00493 { 00494 desc_list_t vdesc = MPEGDescriptor::ParseOnlyInclude( 00495 vct[i]->GlobalDescriptors(), 00496 vct[i]->GlobalDescriptorsLength(), 00497 DescriptorID::caption_service); 00498 00499 if (!vdesc.empty()) 00500 desc.insert(desc.end(), vdesc.begin(), vdesc.end()); 00501 } 00502 } 00503 00504 return desc; 00505 } 00506 00507 bool MPEGStreamData::CreatePMTSingleProgram(const ProgramMapTable &pmt) 00508 { 00509 LOG(VB_RECORD, LOG_INFO, "CreatePMTSingleProgram()"); 00510 LOG(VB_RECORD, LOG_INFO, "PMT in input stream"); 00511 LOG(VB_RECORD, LOG_INFO, pmt.toString()); 00512 00513 if (!PATSingleProgram()) 00514 { 00515 LOG(VB_RECORD, LOG_ERR, "no PAT yet..."); 00516 return false; // no way to properly rewrite pids without PAT 00517 } 00518 pmt.Parse(); 00519 00520 uint programNumber = 1; // MPEG Program Number 00521 00522 ATSCStreamData *sd = NULL; 00523 tvct_vec_t tvct; 00524 cvct_vec_t cvct; 00525 00526 desc_list_t gdesc; 00527 00528 if (!_strip_pmt_descriptors) 00529 { 00530 gdesc = MPEGDescriptor::ParseAndExclude( 00531 pmt.ProgramInfo(), pmt.ProgramInfoLength(), 00532 DescriptorID::conditional_access); 00533 00534 // If there is no caption descriptor in PMT, copy any caption 00535 // descriptor found in VCT to global descriptors... 00536 sd = dynamic_cast<ATSCStreamData*>(this); 00537 if (sd && !MPEGDescriptor::Find(gdesc, DescriptorID::caption_service)) 00538 { 00539 tvct = sd->GetCachedTVCTs(); 00540 cvct = sd->GetCachedCVCTs(); 00541 00542 desc_list_t vdesc = extract_atsc_desc( 00543 tvct, cvct, pmt.ProgramNumber()); 00544 00545 if (!vdesc.empty()) 00546 gdesc.insert(gdesc.end(), vdesc.begin(), vdesc.end()); 00547 } 00548 } 00549 00550 vector<uint> pids; 00551 vector<uint> types; 00552 vector<desc_list_t> pdesc; 00553 00554 uint video_cnt = 0; 00555 uint audio_cnt = 0; 00556 00557 vector<uint> videoPIDs, audioPIDs, dataPIDs; 00558 00559 for (uint i = 0; i < pmt.StreamCount(); i++) 00560 { 00561 uint pid = pmt.StreamPID(i); 00562 00563 desc_list_t desc = MPEGDescriptor::ParseAndExclude( 00564 pmt.StreamInfo(i), pmt.StreamInfoLength(i), 00565 DescriptorID::conditional_access); 00566 00567 uint type = StreamID::Normalize( 00568 pmt.StreamType(i), desc, _sistandard); 00569 00570 // Fixup for ITV HD 00571 if (pid == 3401 && type == StreamID::PrivData && 00572 pmt.ProgramNumber() == 10510) 00573 { 00574 type = StreamID::H264Video; 00575 } 00576 00577 bool is_video = StreamID::IsVideo(type); 00578 bool is_audio = StreamID::IsAudio(type); 00579 00580 if (is_audio) 00581 { 00582 audio_cnt++; 00583 audioPIDs.push_back(pid); 00584 } 00585 00586 #ifdef DEBUG_MPEG_RADIO 00587 if (is_video) 00588 continue; 00589 #endif // DEBUG_MPEG_RADIO 00590 00591 if (is_video) 00592 { 00593 video_cnt++; 00594 videoPIDs.push_back(pid); 00595 } 00596 00597 if (_strip_pmt_descriptors) 00598 desc.clear(); 00599 00600 // Filter out streams not used for basic television 00601 if (_recording_type == "tv" && !is_audio && !is_video && 00602 !MPEGDescriptor::Find(desc, DescriptorID::teletext) && 00603 !MPEGDescriptor::Find(desc, DescriptorID::subtitling)) 00604 { 00605 continue; 00606 } 00607 00608 if (!is_audio && !is_video) 00609 dataPIDs.push_back(pid); 00610 00611 pdesc.push_back(desc); 00612 pids.push_back(pid); 00613 types.push_back(type); 00614 } 00615 00616 if (video_cnt < _pmt_single_program_num_video) 00617 { 00618 LOG(VB_RECORD, LOG_ERR, 00619 QString("Only %1 video streams seen in PMT, but %2 are required.") 00620 .arg(video_cnt).arg(_pmt_single_program_num_video)); 00621 return false; 00622 } 00623 00624 if (audioPIDs.size() < _pmt_single_program_num_audio) 00625 { 00626 LOG(VB_RECORD, LOG_ERR, 00627 QString("Only %1 audio streams seen in PMT, but %2 are required.") 00628 .arg(audioPIDs.size()).arg(_pmt_single_program_num_audio)); 00629 return false; 00630 } 00631 00632 desc_list_t cdesc = MPEGDescriptor::ParseOnlyInclude( 00633 pmt.ProgramInfo(), pmt.ProgramInfoLength(), 00634 DescriptorID::conditional_access); 00635 for (uint i = 0; i < cdesc.size(); i++) 00636 { 00637 ConditionalAccessDescriptor cad(cdesc[i]); 00638 if (cad.IsValid()) 00639 AddListeningPID(cad.PID()); 00640 } 00641 00642 _pids_audio.clear(); 00643 for (uint i = 0; i < audioPIDs.size(); i++) 00644 AddAudioPID(audioPIDs[i]); 00645 00646 if (videoPIDs.size() >= 1) 00647 _pid_video_single_program = videoPIDs[0]; 00648 for (uint i = 1; i < videoPIDs.size(); i++) 00649 AddWritingPID(videoPIDs[i]); 00650 00651 for (uint i = 0; i < dataPIDs.size(); i++) 00652 AddWritingPID(dataPIDs[i]); 00653 00654 // Timebase 00655 int pcrpidIndex = pmt.FindPID(pmt.PCRPID()); 00656 if (pcrpidIndex < 0) 00657 { 00658 // the timecode reference stream is not in the PMT, 00659 // add stream to misc record streams 00660 AddWritingPID(pmt.PCRPID()); 00661 } 00662 00663 // Create the PMT 00664 ProgramMapTable *pmt2 = ProgramMapTable::Create( 00665 programNumber, _pid_pmt_single_program, pmt.PCRPID(), 00666 pmt.Version(), gdesc, pids, types, pdesc); 00667 00668 // Return any TVCT & CVCT tables, once we've copied any descriptors. 00669 if (sd) 00670 { 00671 sd->ReturnCachedTVCTTables(tvct); 00672 sd->ReturnCachedCVCTTables(cvct); 00673 } 00674 00675 // Set Continuity Header 00676 uint cc_cnt = pmt.tsheader()->ContinuityCounter(); 00677 pmt2->tsheader()->SetContinuityCounter(cc_cnt); 00678 SetPMTSingleProgram(pmt2); 00679 00680 LOG(VB_RECORD, LOG_INFO, "PMT for output stream"); 00681 LOG(VB_RECORD, LOG_INFO, pmt2->toString()); 00682 00683 return true; 00684 } 00685 00689 bool MPEGStreamData::IsRedundant(uint pid, const PSIPTable &psip) const 00690 { 00691 (void) pid; 00692 const int table_id = psip.TableID(); 00693 const int version = psip.Version(); 00694 00695 if (TableID::PAT == table_id) 00696 { 00697 if (VersionPAT(psip.TableIDExtension()) != version) 00698 return false; 00699 return PATSectionSeen(psip.TableIDExtension(), psip.Section()); 00700 } 00701 00702 if (TableID::CAT == table_id) 00703 { 00704 if (VersionCAT(psip.TableIDExtension()) != version) 00705 return false; 00706 return CATSectionSeen(psip.TableIDExtension(), psip.Section()); 00707 } 00708 00709 if (TableID::PMT == table_id) 00710 { 00711 if (VersionPMT(psip.TableIDExtension()) != version) 00712 return false; 00713 return PMTSectionSeen(psip.TableIDExtension(), psip.Section()); 00714 } 00715 00716 return false; 00717 } 00718 00722 bool MPEGStreamData::HandleTables(uint pid, const PSIPTable &psip) 00723 { 00724 if (IsRedundant(pid, psip)) 00725 return true; 00726 00727 const int version = psip.Version(); 00728 // If we get this far decode table 00729 switch (psip.TableID()) 00730 { 00731 case TableID::PAT: 00732 { 00733 uint tsid = psip.TableIDExtension(); 00734 SetVersionPAT(tsid, version, psip.LastSection()); 00735 SetPATSectionSeen(tsid, psip.Section()); 00736 00737 ProgramAssociationTable pat(psip); 00738 00739 if (_cache_tables) 00740 CachePAT(&pat); 00741 00742 ProcessPAT(&pat); 00743 00744 return true; 00745 } 00746 case TableID::CAT: 00747 { 00748 uint tsid = psip.TableIDExtension(); 00749 SetVersionCAT(tsid, version, psip.LastSection()); 00750 SetCATSectionSeen(tsid, psip.Section()); 00751 00752 ConditionalAccessTable cat(psip); 00753 00754 if (_cache_tables) 00755 CacheCAT(&cat); 00756 00757 ProcessCAT(&cat); 00758 00759 return true; 00760 } 00761 case TableID::PMT: 00762 { 00763 uint prog_num = psip.TableIDExtension(); 00764 SetVersionPMT(prog_num, version, psip.LastSection()); 00765 SetPMTSectionSeen(prog_num, psip.Section()); 00766 00767 ProgramMapTable pmt(psip); 00768 00769 if (_cache_tables) 00770 CachePMT(&pmt); 00771 00772 ProcessPMT(&pmt); 00773 00774 return true; 00775 } 00776 case TableID::SITscte: 00777 { 00778 SpliceInformationTable sit(psip); 00779 00780 _listener_lock.lock(); 00781 for (uint i = 0; i < _mpeg_listeners.size(); i++) 00782 _mpeg_listeners[i]->HandleSplice(&sit); 00783 _listener_lock.unlock(); 00784 00785 return true; 00786 } 00787 } 00788 return false; 00789 } 00790 00791 void MPEGStreamData::ProcessPAT(const ProgramAssociationTable *pat) 00792 { 00793 bool foundProgram = pat->FindPID(_desired_program); 00794 00795 _listener_lock.lock(); 00796 for (uint i = 0; i < _mpeg_listeners.size(); i++) 00797 _mpeg_listeners[i]->HandlePAT(pat); 00798 _listener_lock.unlock(); 00799 00800 if (_desired_program < 0) 00801 return; 00802 00803 bool send_single_program = false; 00804 if (!_invalid_pat_seen && !foundProgram) 00805 { 00806 _invalid_pat_seen = true; 00807 _invalid_pat_warning = false; 00808 _invalid_pat_timer.start(); 00809 LOG(VB_RECORD, LOG_WARNING, 00810 "ProcessPAT: PAT is missing program, setting timeout"); 00811 } 00812 else if (_invalid_pat_seen && !foundProgram && 00813 (_invalid_pat_timer.elapsed() > 400) && !_invalid_pat_warning) 00814 { 00815 _invalid_pat_warning = true; // only emit one warning... 00816 // After 400ms emit error if we haven't found correct PAT. 00817 LOG(VB_GENERAL, LOG_ERR, 00818 "ProcessPAT: Program not found in PAT. " 00819 "Rescan your transports."); 00820 00821 send_single_program = CreatePATSingleProgram(*pat); 00822 } 00823 else if (foundProgram) 00824 { 00825 if (_invalid_pat_seen) 00826 LOG(VB_RECORD, LOG_INFO, 00827 "ProcessPAT: Good PAT seen after a bad PAT"); 00828 00829 _invalid_pat_seen = false; 00830 00831 send_single_program = CreatePATSingleProgram(*pat); 00832 } 00833 00834 if (send_single_program) 00835 { 00836 QMutexLocker locker(&_listener_lock); 00837 ProgramAssociationTable *pat_sp = PATSingleProgram(); 00838 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 00839 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp); 00840 } 00841 } 00842 00843 void MPEGStreamData::ProcessCAT(const ConditionalAccessTable *cat) 00844 { 00845 _listener_lock.lock(); 00846 for (uint i = 0; i < _mpeg_listeners.size(); i++) 00847 _mpeg_listeners[i]->HandleCAT(cat); 00848 _listener_lock.unlock(); 00849 00850 desc_list_t cdesc = MPEGDescriptor::ParseOnlyInclude( 00851 cat->Descriptors(), cat->DescriptorsLength(), 00852 DescriptorID::conditional_access); 00853 for (uint i = 0; i < cdesc.size(); i++) 00854 { 00855 ConditionalAccessDescriptor cad(cdesc[i]); 00856 if (cad.IsValid()) 00857 AddListeningPID(cad.PID()); 00858 } 00859 } 00860 00861 void MPEGStreamData::ProcessPMT(const ProgramMapTable *pmt) 00862 { 00863 _listener_lock.lock(); 00864 for (uint i = 0; i < _mpeg_listeners.size(); i++) 00865 _mpeg_listeners[i]->HandlePMT(pmt->ProgramNumber(), pmt); 00866 _listener_lock.unlock(); 00867 00868 bool desired = pmt->ProgramNumber() == (uint) _desired_program; 00869 if (desired && CreatePMTSingleProgram(*pmt)) 00870 { 00871 QMutexLocker locker(&_listener_lock); 00872 ProgramMapTable *pmt_sp = PMTSingleProgram(); 00873 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 00874 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp); 00875 } 00876 } 00877 00878 double MPEGStreamData::TimeOffset(void) const 00879 { 00880 QMutexLocker locker(&_si_time_lock); 00881 if (!_si_time_offset_cnt) 00882 return 0.0; 00883 00884 double avg_offset = 0.0; 00885 double mult = 1.0 / _si_time_offset_cnt; 00886 for (uint i = 0; i < _si_time_offset_cnt; i++) 00887 avg_offset += _si_time_offsets[i] * mult; 00888 00889 return avg_offset; 00890 } 00891 00892 void MPEGStreamData::UpdateTimeOffset(uint64_t _si_utc_time) 00893 { 00894 struct timeval tm; 00895 if (gettimeofday(&tm, NULL) != 0) 00896 return; 00897 00898 double utc_time = tm.tv_sec + (tm.tv_usec * 0.000001); 00899 double si_time = _si_utc_time; 00900 00901 QMutexLocker locker(&_si_time_lock); 00902 _si_time_offsets[_si_time_offset_indx] = si_time - utc_time; 00903 00904 if (_si_time_offset_indx + 1 > _si_time_offset_cnt) 00905 _si_time_offset_cnt = _si_time_offset_indx + 1; 00906 00907 _si_time_offset_indx = (_si_time_offset_indx + 1) & 0xf; 00908 00909 } 00910 00911 #define DONE_WITH_PSIP_PACKET() { if (psip) delete psip; \ 00912 if (morePSIPTables) goto HAS_ANOTHER_PSIP; else return; } 00913 00917 void MPEGStreamData::HandleTSTables(const TSPacket* tspacket) 00918 { 00919 bool morePSIPTables; 00920 HAS_ANOTHER_PSIP: 00921 // Assemble PSIP 00922 PSIPTable *psip = AssemblePSIP(tspacket, morePSIPTables); 00923 if (!psip) 00924 return; 00925 00926 // drop stuffing packets 00927 if ((TableID::ST == psip->TableID()) || 00928 (TableID::STUFFING == psip->TableID())) 00929 { 00930 LOG(VB_RECORD, LOG_DEBUG, "Dropping Stuffing table"); 00931 DONE_WITH_PSIP_PACKET(); 00932 } 00933 00934 // Don't do validation on tables withotu CRC 00935 if (!psip->HasCRC()) 00936 { 00937 HandleTables(tspacket->PID(), *psip); 00938 DONE_WITH_PSIP_PACKET(); 00939 } 00940 00941 // Validate PSIP 00942 // but don't validate PMT/PAT if our driver has the PMT/PAT CRC bug. 00943 bool buggy = _have_CRC_bug && 00944 ((TableID::PMT == psip->TableID()) || 00945 (TableID::PAT == psip->TableID())); 00946 if (!buggy && !psip->IsGood()) 00947 { 00948 LOG(VB_RECORD, LOG_ERR, 00949 QString("PSIP packet failed CRC check. pid(0x%1) type(0x%2)") 00950 .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16)); 00951 DONE_WITH_PSIP_PACKET(); 00952 } 00953 00954 if (TableID::MGT <= psip->TableID() && psip->TableID() <= TableID::STT && 00955 !psip->IsCurrent()) 00956 { // we don't cache the next table, for now 00957 LOG(VB_RECORD, LOG_DEBUG, QString("Table not current 0x%1") 00958 .arg(psip->TableID(),2,16,QChar('0'))); 00959 DONE_WITH_PSIP_PACKET(); 00960 } 00961 00962 if (tspacket->Scrambled()) 00963 { // scrambled! ATSC, DVB require tables not to be scrambled 00964 LOG(VB_RECORD, LOG_ERR, 00965 "PSIP packet is scrambled, not ATSC/DVB compiant"); 00966 DONE_WITH_PSIP_PACKET(); 00967 } 00968 00969 if (!psip->VerifyPSIP(!_have_CRC_bug)) 00970 { 00971 LOG(VB_RECORD, LOG_ERR, QString("PSIP table 0x%1 is invalid") 00972 .arg(psip->TableID(),2,16,QChar('0'))); 00973 DONE_WITH_PSIP_PACKET(); 00974 } 00975 00976 // Don't decode redundant packets, 00977 // but if it is a desired PAT or PMT emit a "heartbeat" signal. 00978 if (IsRedundant(tspacket->PID(), *psip)) 00979 { 00980 if (TableID::PAT == psip->TableID()) 00981 { 00982 QMutexLocker locker(&_listener_lock); 00983 ProgramAssociationTable *pat_sp = PATSingleProgram(); 00984 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 00985 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp); 00986 } 00987 if (TableID::PMT == psip->TableID() && 00988 tspacket->PID() == _pid_pmt_single_program) 00989 { 00990 QMutexLocker locker(&_listener_lock); 00991 ProgramMapTable *pmt_sp = PMTSingleProgram(); 00992 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 00993 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp); 00994 } 00995 DONE_WITH_PSIP_PACKET(); // already parsed this table, toss it. 00996 } 00997 00998 HandleTables(tspacket->PID(), *psip); 00999 01000 DONE_WITH_PSIP_PACKET(); 01001 } 01002 #undef DONE_WITH_PSIP_PACKET 01003 01004 int MPEGStreamData::ProcessData(const unsigned char *buffer, int len) 01005 { 01006 int pos = 0; 01007 bool resync = false; 01008 01009 while (pos + int(TSPacket::kSize) <= len) 01010 { // while we have a whole packet left... 01011 if (buffer[pos] != SYNC_BYTE || resync) 01012 { 01013 int newpos = ResyncStream(buffer, pos+1, len); 01014 LOG(VB_RECORD, LOG_DEBUG, QString("Resyncing @ %1+1 w/len %2 -> %3") 01015 .arg(pos).arg(len).arg(newpos)); 01016 if (newpos == -1) 01017 return len - pos; 01018 if (newpos == -2) 01019 return TSPacket::kSize; 01020 pos = newpos; 01021 } 01022 01023 const TSPacket *pkt = reinterpret_cast<const TSPacket*>(&buffer[pos]); 01024 pos += TSPacket::kSize; // Advance to next TS packet 01025 resync = false; 01026 if (!ProcessTSPacket(*pkt)) 01027 { 01028 if (pos + int(TSPacket::kSize) > len) 01029 continue; 01030 if (buffer[pos] != SYNC_BYTE) 01031 { 01032 // if ProcessTSPacket fails, and we don't appear to be 01033 // in sync on the next packet, then resync. Otherwise 01034 // just process the next packet normally. 01035 pos -= TSPacket::kSize; 01036 resync = true; 01037 } 01038 } 01039 } 01040 01041 return len - pos; 01042 } 01043 01044 bool MPEGStreamData::ProcessTSPacket(const TSPacket& tspacket) 01045 { 01046 bool ok = !tspacket.TransportError(); 01047 01048 if (IsEncryptionTestPID(tspacket.PID())) 01049 { 01050 ProcessEncryptedPacket(tspacket); 01051 } 01052 01053 if (!ok) 01054 return false; 01055 01056 if (tspacket.Scrambled()) 01057 return true; 01058 01059 if (IsVideoPID(tspacket.PID())) 01060 { 01061 for (uint j = 0; j < _ts_av_listeners.size(); j++) 01062 _ts_av_listeners[j]->ProcessVideoTSPacket(tspacket); 01063 01064 return true; 01065 } 01066 01067 if (IsAudioPID(tspacket.PID())) 01068 { 01069 for (uint j = 0; j < _ts_av_listeners.size(); j++) 01070 _ts_av_listeners[j]->ProcessAudioTSPacket(tspacket); 01071 01072 return true; 01073 } 01074 01075 if (IsWritingPID(tspacket.PID())) 01076 { 01077 for (uint j = 0; j < _ts_writing_listeners.size(); j++) 01078 _ts_writing_listeners[j]->ProcessTSPacket(tspacket); 01079 } 01080 01081 if (IsListeningPID(tspacket.PID()) && tspacket.HasPayload()) 01082 { 01083 HandleTSTables(&tspacket); 01084 } 01085 01086 return true; 01087 } 01088 01089 int MPEGStreamData::ResyncStream(const unsigned char *buffer, int curr_pos, 01090 int len) 01091 { 01092 // Search for two sync bytes 188 bytes apart, 01093 int pos = curr_pos; 01094 int nextpos = pos + TSPacket::kSize; 01095 if (nextpos >= len) 01096 return -1; // not enough bytes; caller should try again 01097 01098 while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE) 01099 { 01100 pos++; 01101 nextpos++; 01102 if (nextpos == len) 01103 return -2; // not found 01104 } 01105 01106 return pos; 01107 } 01108 01109 bool MPEGStreamData::IsListeningPID(uint pid) const 01110 { 01111 if (_listening_disabled || IsNotListeningPID(pid)) 01112 return false; 01113 pid_map_t::const_iterator it = _pids_listening.find(pid); 01114 return it != _pids_listening.end(); 01115 } 01116 01117 bool MPEGStreamData::IsNotListeningPID(uint pid) const 01118 { 01119 pid_map_t::const_iterator it = _pids_notlistening.find(pid); 01120 return it != _pids_notlistening.end(); 01121 } 01122 01123 bool MPEGStreamData::IsWritingPID(uint pid) const 01124 { 01125 pid_map_t::const_iterator it = _pids_writing.find(pid); 01126 return it != _pids_writing.end(); 01127 } 01128 01129 bool MPEGStreamData::IsAudioPID(uint pid) const 01130 { 01131 pid_map_t::const_iterator it = _pids_audio.find(pid); 01132 return it != _pids_audio.end(); 01133 } 01134 01135 uint MPEGStreamData::GetPIDs(pid_map_t &pids) const 01136 { 01137 uint sz = pids.size(); 01138 01139 if (_pid_video_single_program < 0x1fff) 01140 pids[_pid_video_single_program] = kPIDPriorityHigh; 01141 01142 pid_map_t::const_iterator it = _pids_listening.begin(); 01143 for (; it != _pids_listening.end(); ++it) 01144 pids[it.key()] = max(pids[it.key()], *it); 01145 01146 it = _pids_audio.begin(); 01147 for (; it != _pids_audio.end(); ++it) 01148 pids[it.key()] = max(pids[it.key()], *it); 01149 01150 it = _pids_writing.begin(); 01151 for (; it != _pids_writing.end(); ++it) 01152 pids[it.key()] = max(pids[it.key()], *it); 01153 01154 return pids.size() - sz; 01155 } 01156 01157 PIDPriority MPEGStreamData::GetPIDPriority(uint pid) const 01158 { 01159 if (_pid_video_single_program == pid) 01160 return kPIDPriorityHigh; 01161 01162 pid_map_t::const_iterator it; 01163 it = _pids_listening.find(pid); 01164 if (it != _pids_listening.end()) 01165 return *it; 01166 it = _pids_notlistening.find(pid); 01167 if (it != _pids_notlistening.end()) 01168 return *it; 01169 it = _pids_writing.find(pid); 01170 if (it != _pids_writing.end()) 01171 return *it; 01172 it = _pids_audio.find(pid); 01173 if (it != _pids_audio.end()) 01174 return *it; 01175 01176 return kPIDPriorityNone; 01177 } 01178 01179 void MPEGStreamData::SavePartialPSIP(uint pid, PSIPTable* packet) 01180 { 01181 pid_psip_map_t::iterator it = _partial_psip_packet_cache.find(pid); 01182 if (it == _partial_psip_packet_cache.end()) 01183 _partial_psip_packet_cache[pid] = packet; 01184 else 01185 { 01186 PSIPTable *old = *it; 01187 _partial_psip_packet_cache.remove(pid); 01188 _partial_psip_packet_cache.insert(pid, packet); 01189 delete old; 01190 } 01191 } 01192 01193 void MPEGStreamData::SetPATSectionSeen(uint tsid, uint section) 01194 { 01195 sections_map_t::iterator it = _pat_section_seen.find(tsid); 01196 if (it == _pat_section_seen.end()) 01197 { 01198 _pat_section_seen[tsid].resize(32, 0); 01199 it = _pat_section_seen.find(tsid); 01200 } 01201 (*it)[section>>3] |= bit_sel[section & 0x7]; 01202 } 01203 01204 bool MPEGStreamData::PATSectionSeen(uint tsid, uint section) const 01205 { 01206 sections_map_t::const_iterator it = _pat_section_seen.find(tsid); 01207 if (it == _pat_section_seen.end()) 01208 return false; 01209 return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]); 01210 } 01211 01212 bool MPEGStreamData::HasAllPATSections(uint tsid) const 01213 { 01214 sections_map_t::const_iterator it = _pat_section_seen.find(tsid); 01215 if (it == _pat_section_seen.end()) 01216 return false; 01217 for (uint i = 0; i < 32; i++) 01218 if ((*it)[i] != 0xff) 01219 return false; 01220 return true; 01221 } 01222 01223 void MPEGStreamData::SetCATSectionSeen(uint tsid, uint section) 01224 { 01225 sections_map_t::iterator it = _cat_section_seen.find(tsid); 01226 if (it == _cat_section_seen.end()) 01227 { 01228 _cat_section_seen[tsid].resize(32, 0); 01229 it = _cat_section_seen.find(tsid); 01230 } 01231 (*it)[section>>3] |= bit_sel[section & 0x7]; 01232 } 01233 01234 bool MPEGStreamData::CATSectionSeen(uint tsid, uint section) const 01235 { 01236 sections_map_t::const_iterator it = _cat_section_seen.find(tsid); 01237 if (it == _cat_section_seen.end()) 01238 return false; 01239 return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]); 01240 } 01241 01242 bool MPEGStreamData::HasAllCATSections(uint tsid) const 01243 { 01244 sections_map_t::const_iterator it = _cat_section_seen.find(tsid); 01245 if (it == _cat_section_seen.end()) 01246 return false; 01247 for (uint i = 0; i < 32; i++) 01248 if ((*it)[i] != 0xff) 01249 return false; 01250 return true; 01251 } 01252 01253 void MPEGStreamData::SetPMTSectionSeen(uint prog_num, uint section) 01254 { 01255 sections_map_t::iterator it = _pmt_section_seen.find(prog_num); 01256 if (it == _pmt_section_seen.end()) 01257 { 01258 _pmt_section_seen[prog_num].resize(32, 0); 01259 it = _pmt_section_seen.find(prog_num); 01260 } 01261 (*it)[section>>3] |= bit_sel[section & 0x7]; 01262 } 01263 01264 bool MPEGStreamData::PMTSectionSeen(uint prog_num, uint section) const 01265 { 01266 sections_map_t::const_iterator it = _pmt_section_seen.find(prog_num); 01267 if (it == _pmt_section_seen.end()) 01268 return false; 01269 return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]); 01270 } 01271 01272 bool MPEGStreamData::HasAllPMTSections(uint prog_num) const 01273 { 01274 sections_map_t::const_iterator it = _pmt_section_seen.find(prog_num); 01275 if (it == _pmt_section_seen.end()) 01276 return false; 01277 for (uint i = 0; i < 32; i++) 01278 if ((*it)[i] != 0xff) 01279 return false; 01280 return true; 01281 } 01282 01283 bool MPEGStreamData::HasProgram(uint progNum) const 01284 { 01285 pmt_ptr_t pmt = GetCachedPMT(progNum, 0); 01286 bool hasit = pmt; 01287 ReturnCachedTable(pmt); 01288 01289 return hasit; 01290 } 01291 01292 bool MPEGStreamData::HasCachedAllPAT(uint tsid) const 01293 { 01294 QMutexLocker locker(&_cache_lock); 01295 01296 pat_cache_t::const_iterator it = _cached_pats.find(tsid << 8); 01297 if (it == _cached_pats.end()) 01298 return false; 01299 01300 uint last_section = (*it)->LastSection(); 01301 if (!last_section) 01302 return true; 01303 01304 for (uint i = 1; i <= last_section; i++) 01305 if (_cached_pats.find((tsid << 8) | i) == _cached_pats.end()) 01306 return false; 01307 01308 return true; 01309 } 01310 01311 bool MPEGStreamData::HasCachedAnyPAT(uint tsid) const 01312 { 01313 QMutexLocker locker(&_cache_lock); 01314 01315 for (uint i = 0; i <= 255; i++) 01316 if (_cached_pats.find((tsid << 8) | i) != _cached_pats.end()) 01317 return true; 01318 01319 return false; 01320 } 01321 01322 bool MPEGStreamData::HasCachedAnyPAT(void) const 01323 { 01324 QMutexLocker locker(&_cache_lock); 01325 return _cached_pats.size(); 01326 } 01327 01328 bool MPEGStreamData::HasCachedAllCAT(uint tsid) const 01329 { 01330 QMutexLocker locker(&_cache_lock); 01331 01332 cat_cache_t::const_iterator it = _cached_cats.find(tsid << 8); 01333 if (it == _cached_cats.end()) 01334 return false; 01335 01336 uint last_section = (*it)->LastSection(); 01337 if (!last_section) 01338 return true; 01339 01340 for (uint i = 1; i <= last_section; i++) 01341 if (_cached_cats.find((tsid << 8) | i) == _cached_cats.end()) 01342 return false; 01343 01344 return true; 01345 } 01346 01347 bool MPEGStreamData::HasCachedAnyCAT(uint tsid) const 01348 { 01349 QMutexLocker locker(&_cache_lock); 01350 01351 for (uint i = 0; i <= 255; i++) 01352 if (_cached_cats.find((tsid << 8) | i) != _cached_cats.end()) 01353 return true; 01354 01355 return false; 01356 } 01357 01358 bool MPEGStreamData::HasCachedAnyCAT(void) const 01359 { 01360 QMutexLocker locker(&_cache_lock); 01361 return _cached_cats.size(); 01362 } 01363 01364 bool MPEGStreamData::HasCachedAllPMT(uint pnum) const 01365 { 01366 QMutexLocker locker(&_cache_lock); 01367 01368 pmt_cache_t::const_iterator it = _cached_pmts.find(pnum << 8); 01369 if (it == _cached_pmts.end()) 01370 return false; 01371 01372 uint last_section = (*it)->LastSection(); 01373 if (!last_section) 01374 return true; 01375 01376 for (uint i = 1; i <= last_section; i++) 01377 if (_cached_pmts.find((pnum << 8) | i) == _cached_pmts.end()) 01378 return false; 01379 01380 return true; 01381 } 01382 01383 bool MPEGStreamData::HasCachedAnyPMT(uint pnum) const 01384 { 01385 QMutexLocker locker(&_cache_lock); 01386 01387 for (uint i = 0; i <= 255; i++) 01388 if (_cached_pmts.find((pnum << 8) | i) != _cached_pmts.end()) 01389 return true; 01390 01391 return false; 01392 } 01393 01394 bool MPEGStreamData::HasCachedAllPMTs(void) const 01395 { 01396 QMutexLocker locker(&_cache_lock); 01397 01398 pat_cache_t::const_iterator it = _cached_pats.begin(); 01399 for (; it != _cached_pats.end(); ++it) 01400 { 01401 const ProgramAssociationTable *pat = *it; 01402 if (!HasCachedAllPAT(pat->TransportStreamID())) 01403 return false; 01404 01405 for (uint i = 0; i < pat->ProgramCount(); i++) 01406 { 01407 uint prognum = pat->ProgramNumber(i); 01408 if (prognum && !HasCachedAllPMT(prognum)) 01409 return false; 01410 } 01411 } 01412 01413 return true; 01414 } 01415 01416 bool MPEGStreamData::HasCachedAnyPMTs(void) const 01417 { 01418 QMutexLocker locker(&_cache_lock); 01419 return _cached_pmts.size(); 01420 } 01421 01422 pat_ptr_t MPEGStreamData::GetCachedPAT(uint tsid, uint section_num) const 01423 { 01424 QMutexLocker locker(&_cache_lock); 01425 ProgramAssociationTable *pat = NULL; 01426 01427 uint key = (tsid << 8) | section_num; 01428 pat_cache_t::const_iterator it = _cached_pats.find(key); 01429 if (it != _cached_pats.end()) 01430 IncrementRefCnt(pat = *it); 01431 01432 return pat; 01433 } 01434 01435 pat_vec_t MPEGStreamData::GetCachedPATs(uint tsid) const 01436 { 01437 QMutexLocker locker(&_cache_lock); 01438 pat_vec_t pats; 01439 01440 for (uint i=0; i < 256; i++) 01441 { 01442 ProgramAssociationTable *pat = GetCachedPAT(tsid, i); 01443 if (pat) 01444 pats.push_back(pat); 01445 } 01446 01447 return pats; 01448 } 01449 01450 pat_vec_t MPEGStreamData::GetCachedPATs(void) const 01451 { 01452 QMutexLocker locker(&_cache_lock); 01453 pat_vec_t pats; 01454 01455 pat_cache_t::const_iterator it = _cached_pats.begin(); 01456 for (; it != _cached_pats.end(); ++it) 01457 { 01458 ProgramAssociationTable* pat = *it; 01459 IncrementRefCnt(pat); 01460 pats.push_back(pat); 01461 } 01462 01463 return pats; 01464 } 01465 01466 cat_ptr_t MPEGStreamData::GetCachedCAT(uint tsid, uint section_num) const 01467 { 01468 QMutexLocker locker(&_cache_lock); 01469 ConditionalAccessTable *cat = NULL; 01470 01471 uint key = (tsid << 8) | section_num; 01472 cat_cache_t::const_iterator it = _cached_cats.find(key); 01473 if (it != _cached_cats.end()) 01474 IncrementRefCnt(cat = *it); 01475 01476 return cat; 01477 } 01478 01479 cat_vec_t MPEGStreamData::GetCachedCATs(uint tsid) const 01480 { 01481 QMutexLocker locker(&_cache_lock); 01482 cat_vec_t cats; 01483 01484 for (uint i=0; i < 256; i++) 01485 { 01486 ConditionalAccessTable *cat = GetCachedCAT(tsid, i); 01487 if (cat) 01488 cats.push_back(cat); 01489 } 01490 01491 return cats; 01492 } 01493 01494 cat_vec_t MPEGStreamData::GetCachedCATs(void) const 01495 { 01496 QMutexLocker locker(&_cache_lock); 01497 cat_vec_t cats; 01498 01499 cat_cache_t::const_iterator it = _cached_cats.begin(); 01500 for (; it != _cached_cats.end(); ++it) 01501 { 01502 ConditionalAccessTable* cat = *it; 01503 IncrementRefCnt(cat); 01504 cats.push_back(cat); 01505 } 01506 01507 return cats; 01508 } 01509 01510 pmt_ptr_t MPEGStreamData::GetCachedPMT( 01511 uint program_num, uint section_num) const 01512 { 01513 QMutexLocker locker(&_cache_lock); 01514 ProgramMapTable *pmt = NULL; 01515 01516 uint key = (program_num << 8) | section_num; 01517 pmt_cache_t::const_iterator it = _cached_pmts.find(key); 01518 if (it != _cached_pmts.end()) 01519 IncrementRefCnt(pmt = *it); 01520 01521 return pmt; 01522 } 01523 01524 pmt_vec_t MPEGStreamData::GetCachedPMTs(void) const 01525 { 01526 QMutexLocker locker(&_cache_lock); 01527 vector<const ProgramMapTable*> pmts; 01528 01529 pmt_cache_t::const_iterator it = _cached_pmts.begin(); 01530 for (; it != _cached_pmts.end(); ++it) 01531 { 01532 ProgramMapTable* pmt = *it; 01533 IncrementRefCnt(pmt); 01534 pmts.push_back(pmt); 01535 } 01536 01537 return pmts; 01538 } 01539 01540 pmt_map_t MPEGStreamData::GetCachedPMTMap(void) const 01541 { 01542 QMutexLocker locker(&_cache_lock); 01543 pmt_map_t pmts; 01544 01545 pmt_cache_t::const_iterator it = _cached_pmts.begin(); 01546 for (; it != _cached_pmts.end(); ++it) 01547 { 01548 ProgramMapTable* pmt = *it; 01549 IncrementRefCnt(pmt); 01550 pmts[pmt->ProgramNumber()].push_back(pmt); 01551 } 01552 01553 return pmts; 01554 } 01555 01556 void MPEGStreamData::ReturnCachedTable(const PSIPTable *psip) const 01557 { 01558 QMutexLocker locker(&_cache_lock); 01559 01560 int val = _cached_ref_cnt[psip] - 1; 01561 _cached_ref_cnt[psip] = val; 01562 01563 // if ref <= 0 and table was slated for deletion, delete it. 01564 if (val <= 0) 01565 { 01566 psip_refcnt_map_t::iterator it; 01567 it = _cached_slated_for_deletion.find(psip); 01568 if (it != _cached_slated_for_deletion.end()) 01569 DeleteCachedTable(const_cast<PSIPTable*>(psip)); 01570 } 01571 } 01572 01573 void MPEGStreamData::ReturnCachedPATTables(pat_vec_t &pats) const 01574 { 01575 for (pat_vec_t::iterator it = pats.begin(); it != pats.end(); ++it) 01576 ReturnCachedTable(*it); 01577 pats.clear(); 01578 } 01579 01580 void MPEGStreamData::ReturnCachedPATTables(pat_map_t &pats) const 01581 { 01582 for (pat_map_t::iterator it = pats.begin(); it != pats.end(); ++it) 01583 ReturnCachedPATTables(*it); 01584 pats.clear(); 01585 } 01586 01587 void MPEGStreamData::ReturnCachedCATTables(cat_vec_t &cats) const 01588 { 01589 for (cat_vec_t::iterator it = cats.begin(); it != cats.end(); ++it) 01590 ReturnCachedTable(*it); 01591 cats.clear(); 01592 } 01593 01594 void MPEGStreamData::ReturnCachedCATTables(cat_map_t &cats) const 01595 { 01596 for (cat_map_t::iterator it = cats.begin(); it != cats.end(); ++it) 01597 ReturnCachedCATTables(*it); 01598 cats.clear(); 01599 } 01600 01601 void MPEGStreamData::ReturnCachedPMTTables(pmt_vec_t &pmts) const 01602 { 01603 for (pmt_vec_t::iterator it = pmts.begin(); it != pmts.end(); ++it) 01604 ReturnCachedTable(*it); 01605 pmts.clear(); 01606 } 01607 01608 void MPEGStreamData::ReturnCachedPMTTables(pmt_map_t &pmts) const 01609 { 01610 for (pmt_map_t::iterator it = pmts.begin(); it != pmts.end(); ++it) 01611 ReturnCachedPMTTables(*it); 01612 pmts.clear(); 01613 } 01614 01615 void MPEGStreamData::IncrementRefCnt(const PSIPTable *psip) const 01616 { 01617 QMutexLocker locker(&_cache_lock); 01618 _cached_ref_cnt[psip] = _cached_ref_cnt[psip] + 1; 01619 } 01620 01621 bool MPEGStreamData::DeleteCachedTable(PSIPTable *psip) const 01622 { 01623 if (!psip) 01624 return false; 01625 01626 uint tid = psip->TableIDExtension(); 01627 01628 QMutexLocker locker(&_cache_lock); 01629 if (_cached_ref_cnt[psip] > 0) 01630 { 01631 _cached_slated_for_deletion[psip] = 1; 01632 return false; 01633 } 01634 else if (TableID::PAT == psip->TableID() && 01635 (_cached_pats[(tid << 8) | psip->Section()] == psip)) 01636 { 01637 _cached_pats[(tid << 8) | psip->Section()] = NULL; 01638 delete psip; 01639 } 01640 else if (TableID::CAT == psip->TableID() && 01641 (_cached_cats[(tid << 8) | psip->Section()] == psip)) 01642 { 01643 _cached_cats[(tid << 8) | psip->Section()] = NULL; 01644 delete psip; 01645 } 01646 else if ((TableID::PMT == psip->TableID()) && 01647 (_cached_pmts[(tid << 8) | psip->Section()] == psip)) 01648 { 01649 _cached_pmts[(tid << 8) | psip->Section()] = NULL; 01650 delete psip; 01651 } 01652 else 01653 { 01654 _cached_slated_for_deletion[psip] = 2; 01655 return false; 01656 } 01657 psip_refcnt_map_t::iterator it; 01658 it = _cached_slated_for_deletion.find(psip); 01659 if (it != _cached_slated_for_deletion.end()) 01660 _cached_slated_for_deletion.erase(it); 01661 01662 return true; 01663 } 01664 01665 void MPEGStreamData::CachePAT(const ProgramAssociationTable *_pat) 01666 { 01667 ProgramAssociationTable *pat = new ProgramAssociationTable(*_pat); 01668 uint key = (_pat->TransportStreamID() << 8) | _pat->Section(); 01669 01670 QMutexLocker locker(&_cache_lock); 01671 01672 pat_cache_t::iterator it = _cached_pats.find(key); 01673 if (it != _cached_pats.end()) 01674 DeleteCachedTable(*it); 01675 01676 _cached_pats[key] = pat; 01677 } 01678 01679 void MPEGStreamData::CacheCAT(const ConditionalAccessTable *_cat) 01680 { 01681 ConditionalAccessTable *cat = new ConditionalAccessTable(*_cat); 01682 uint key = (_cat->TableIDExtension() << 8) | _cat->Section(); 01683 01684 QMutexLocker locker(&_cache_lock); 01685 01686 cat_cache_t::iterator it = _cached_cats.find(key); 01687 if (it != _cached_cats.end()) 01688 DeleteCachedTable(*it); 01689 01690 _cached_cats[key] = cat; 01691 } 01692 01693 void MPEGStreamData::CachePMT(const ProgramMapTable *_pmt) 01694 { 01695 ProgramMapTable *pmt = new ProgramMapTable(*_pmt); 01696 uint key = (_pmt->ProgramNumber() << 8) | _pmt->Section(); 01697 01698 QMutexLocker locker(&_cache_lock); 01699 01700 pmt_cache_t::iterator it = _cached_pmts.find(key); 01701 if (it != _cached_pmts.end()) 01702 DeleteCachedTable(*it); 01703 01704 _cached_pmts[key] = pmt; 01705 } 01706 01707 void MPEGStreamData::AddMPEGListener(MPEGStreamListener *val) 01708 { 01709 QMutexLocker locker(&_listener_lock); 01710 01711 mpeg_listener_vec_t::iterator it = _mpeg_listeners.begin(); 01712 for (; it != _mpeg_listeners.end(); ++it) 01713 if (((void*)val) == ((void*)*it)) 01714 return; 01715 01716 _mpeg_listeners.push_back(val); 01717 } 01718 01719 void MPEGStreamData::RemoveMPEGListener(MPEGStreamListener *val) 01720 { 01721 QMutexLocker locker(&_listener_lock); 01722 01723 mpeg_listener_vec_t::iterator it = _mpeg_listeners.begin(); 01724 for (; it != _mpeg_listeners.end(); ++it) 01725 { 01726 if (((void*)val) == ((void*)*it)) 01727 { 01728 _mpeg_listeners.erase(it); 01729 return; 01730 } 01731 } 01732 } 01733 01734 void MPEGStreamData::AddWritingListener(TSPacketListener *val) 01735 { 01736 QMutexLocker locker(&_listener_lock); 01737 01738 ts_listener_vec_t::iterator it = _ts_writing_listeners.begin(); 01739 for (; it != _ts_writing_listeners.end(); ++it) 01740 if (((void*)val) == ((void*)*it)) 01741 return; 01742 01743 _ts_writing_listeners.push_back(val); 01744 } 01745 01746 void MPEGStreamData::RemoveWritingListener(TSPacketListener *val) 01747 { 01748 QMutexLocker locker(&_listener_lock); 01749 01750 ts_listener_vec_t::iterator it = _ts_writing_listeners.begin(); 01751 for (; it != _ts_writing_listeners.end(); ++it) 01752 { 01753 if (((void*)val) == ((void*)*it)) 01754 { 01755 _ts_writing_listeners.erase(it); 01756 return; 01757 } 01758 } 01759 } 01760 01761 void MPEGStreamData::AddAVListener(TSPacketListenerAV *val) 01762 { 01763 QMutexLocker locker(&_listener_lock); 01764 01765 ts_av_listener_vec_t::iterator it = _ts_av_listeners.begin(); 01766 for (; it != _ts_av_listeners.end(); ++it) 01767 if (((void*)val) == ((void*)*it)) 01768 return; 01769 01770 _ts_av_listeners.push_back(val); 01771 } 01772 01773 void MPEGStreamData::RemoveAVListener(TSPacketListenerAV *val) 01774 { 01775 QMutexLocker locker(&_listener_lock); 01776 01777 ts_av_listener_vec_t::iterator it = _ts_av_listeners.begin(); 01778 for (; it != _ts_av_listeners.end(); ++it) 01779 { 01780 if (((void*)val) == ((void*)*it)) 01781 { 01782 _ts_av_listeners.erase(it); 01783 return; 01784 } 01785 } 01786 } 01787 01788 void MPEGStreamData::AddMPEGSPListener(MPEGSingleProgramStreamListener *val) 01789 { 01790 QMutexLocker locker(&_listener_lock); 01791 01792 mpeg_sp_listener_vec_t::iterator it = _mpeg_sp_listeners.begin(); 01793 for (; it != _mpeg_sp_listeners.end(); ++it) 01794 if (((void*)val) == ((void*)*it)) 01795 return; 01796 01797 _mpeg_sp_listeners.push_back(val); 01798 } 01799 01800 void MPEGStreamData::RemoveMPEGSPListener(MPEGSingleProgramStreamListener *val) 01801 { 01802 QMutexLocker locker(&_listener_lock); 01803 01804 mpeg_sp_listener_vec_t::iterator it = _mpeg_sp_listeners.begin(); 01805 for (; it != _mpeg_sp_listeners.end(); ++it) 01806 { 01807 if (((void*)val) == ((void*)*it)) 01808 { 01809 _mpeg_sp_listeners.erase(it); 01810 return; 01811 } 01812 } 01813 } 01814 01815 void MPEGStreamData::AddEncryptionTestPID(uint pnum, uint pid, bool isvideo) 01816 { 01817 QMutexLocker locker(&_encryption_lock); 01818 01819 #if 0 01820 LOG(VB_GENERAL, LOG_DEBUG, QString("AddEncryptionTestPID(%1, 0x%2)") 01821 .arg(pnum) .arg(pid, 0, 16)); 01822 #endif 01823 01824 AddListeningPID(pid); 01825 01826 _encryption_pid_to_info[pid] = CryptInfo((isvideo) ? 10000 : 500, 8); 01827 01828 _encryption_pid_to_pnums[pid].push_back(pnum); 01829 _encryption_pnum_to_pids[pnum].push_back(pid); 01830 _encryption_pnum_to_status[pnum] = kEncUnknown; 01831 } 01832 01833 void MPEGStreamData::RemoveEncryptionTestPIDs(uint pnum) 01834 { 01835 QMutexLocker locker(&_encryption_lock); 01836 01837 #if 0 01838 LOG(VB_RECORD, LOG_DEBUG, 01839 QString("Tearing down up decryption monitoring for program %1") 01840 .arg(pnum)); 01841 #endif 01842 01843 QMap<uint, uint_vec_t>::iterator list; 01844 uint_vec_t::iterator it; 01845 01846 uint_vec_t pids = _encryption_pnum_to_pids[pnum]; 01847 for (uint i = 0; i < pids.size(); i++) 01848 { 01849 uint pid = pids[i]; 01850 01851 #if 0 01852 LOG(VB_GENERAL, LOG_DEBUG, QString("Removing 0x%1 PID Enc monitoring") 01853 .arg(pid,0,16)); 01854 #endif 01855 01856 RemoveListeningPID(pid); 01857 01858 list = _encryption_pid_to_pnums.find(pid); 01859 if (list != _encryption_pid_to_pnums.end()) 01860 { 01861 it = find((*list).begin(), (*list).end(), pnum); 01862 01863 if (it != (*list).end()) 01864 (*list).erase(it); 01865 01866 if ((*list).empty()) 01867 { 01868 _encryption_pid_to_pnums.remove(pid); 01869 _encryption_pid_to_info.remove(pid); 01870 } 01871 } 01872 } 01873 01874 _encryption_pnum_to_pids.remove(pnum); 01875 } 01876 01877 bool MPEGStreamData::IsEncryptionTestPID(uint pid) const 01878 { 01879 QMutexLocker locker(&_encryption_lock); 01880 01881 QMap<uint, CryptInfo>::const_iterator it = 01882 _encryption_pid_to_info.find(pid); 01883 01884 return it != _encryption_pid_to_info.end(); 01885 } 01886 01887 void MPEGStreamData::TestDecryption(const ProgramMapTable *pmt) 01888 { 01889 QMutexLocker locker(&_encryption_lock); 01890 01891 #if 0 01892 LOG(VB_RECORD, LOG_DEBUG, 01893 QString("Setting up decryption monitoring for program %1") 01894 .arg(pmt->ProgramNumber())); 01895 #endif 01896 01897 bool encrypted = pmt->IsProgramEncrypted(); 01898 for (uint i = 0; i < pmt->StreamCount(); i++) 01899 { 01900 if (!encrypted && !pmt->IsStreamEncrypted(i)) 01901 continue; 01902 01903 bool is_vid = pmt->IsVideo(i, _sistandard); 01904 bool is_aud = pmt->IsAudio(i, _sistandard); 01905 if (is_vid || is_aud) 01906 { 01907 AddEncryptionTestPID( 01908 pmt->ProgramNumber(), pmt->StreamPID(i), is_vid); 01909 } 01910 } 01911 } 01912 01913 void MPEGStreamData::ResetDecryptionMonitoringState(void) 01914 { 01915 QMutexLocker locker(&_encryption_lock); 01916 01917 _encryption_pid_to_info.clear(); 01918 _encryption_pid_to_pnums.clear(); 01919 _encryption_pnum_to_pids.clear(); 01920 } 01921 01922 bool MPEGStreamData::IsProgramDecrypted(uint pnum) const 01923 { 01924 QMutexLocker locker(&_encryption_lock); 01925 return _encryption_pnum_to_status[pnum] == kEncDecrypted; 01926 } 01927 01928 bool MPEGStreamData::IsProgramEncrypted(uint pnum) const 01929 { 01930 QMutexLocker locker(&_encryption_lock); 01931 return _encryption_pnum_to_status[pnum] == kEncEncrypted; 01932 } 01933 01934 static QString toString(CryptStatus status) 01935 { 01936 if (kEncDecrypted == status) 01937 return "Decrypted"; 01938 else if (kEncEncrypted == status) 01939 return "Encrypted"; 01940 else 01941 return "Unknown"; 01942 } 01943 01947 void MPEGStreamData::ProcessEncryptedPacket(const TSPacket& tspacket) 01948 { 01949 QMutexLocker locker(&_encryption_lock); 01950 01951 const uint pid = tspacket.PID(); 01952 CryptInfo &info = _encryption_pid_to_info[pid]; 01953 01954 CryptStatus status = kEncUnknown; 01955 01956 if (tspacket.Scrambled()) 01957 { 01958 info.decrypted_packets = 0; 01959 01960 // If a fair amount of encrypted packets is passed assume that 01961 // the stream is not decryptable 01962 if (++info.encrypted_packets >= info.encrypted_min) 01963 status = kEncEncrypted; 01964 } 01965 else 01966 { 01967 info.encrypted_packets = 0; 01968 if (++info.decrypted_packets > info.decrypted_min) 01969 status = kEncDecrypted; 01970 } 01971 01972 if (status == info.status) 01973 return; // pid encryption status unchanged 01974 01975 info.status = status; 01976 01977 LOG(status != kEncDecrypted ? VB_GENERAL : VB_RECORD, LOG_INFO, 01978 QString("PID 0x%1 status: %2") .arg(pid,0,16).arg(toString(status))); 01979 01980 uint_vec_t pnum_del_list; 01981 const uint_vec_t &pnums = _encryption_pid_to_pnums[pid]; 01982 for (uint i = 0; i < pnums.size(); i++) 01983 { 01984 CryptStatus status = _encryption_pnum_to_status[pnums[i]]; 01985 01986 const uint_vec_t &pids = _encryption_pnum_to_pids[pnums[i]]; 01987 if (!pids.empty()) 01988 { 01989 uint enc_cnt[3] = { 0, 0, 0 }; 01990 for (uint j = 0; j < pids.size(); j++) 01991 { 01992 CryptStatus stat = _encryption_pid_to_info[pids[j]].status; 01993 enc_cnt[stat]++; 01994 01995 #if 0 01996 LOG(VB_GENERAL, LOG_DEBUG, 01997 QString("\tpnum %1 PID 0x%2 status: %3") 01998 .arg(pnums[i]).arg(pids[j],0,16) .arg(toString(stat))); 01999 #endif 02000 } 02001 status = kEncUnknown; 02002 02003 if (enc_cnt[kEncEncrypted]) 02004 status = kEncEncrypted; 02005 else if (enc_cnt[kEncDecrypted] >= min((size_t) 2, pids.size())) 02006 status = kEncDecrypted; 02007 } 02008 02009 if (status == _encryption_pnum_to_status[pnums[i]]) 02010 continue; // program encryption status unchanged 02011 02012 LOG(VB_RECORD, LOG_INFO, QString("Program %1 status: %2") 02013 .arg(pnums[i]).arg(toString(status))); 02014 02015 _encryption_pnum_to_status[pnums[i]] = status; 02016 02017 bool encrypted = kEncUnknown == status || kEncEncrypted == status; 02018 _listener_lock.lock(); 02019 for (uint j = 0; j < _mpeg_listeners.size(); j++) 02020 _mpeg_listeners[j]->HandleEncryptionStatus(pnums[i], encrypted); 02021 _listener_lock.unlock(); 02022 02023 if (kEncDecrypted == status) 02024 pnum_del_list.push_back(pnums[i]); 02025 } 02026 02027 for (uint i = 0; i < pnum_del_list.size(); i++) 02028 RemoveEncryptionTestPIDs(pnums[i]); 02029 }
1.7.6.1