00001
00002
00003
00004 #include <algorithm>
00005 using namespace std;
00006
00007
00008 #include <sys/time.h>
00009
00010
00011 #include <QString>
00012
00013
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
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
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
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
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
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
00295
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
00302
00303
00304
00305
00306
00307
00308 if ((partial->TSSizeInBuffer() > TSPacket::kSize) &&
00309 (packetStart >
00310 partial->TSSizeInBuffer() - TSPacket::PAYLOAD_SIZE))
00311 {
00312
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
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;
00348 }
00349
00350 if (!tspacket->PayloadStart())
00351 {
00352
00353
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
00367
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);
00380
00381
00382
00383
00384 if ((offset + psip->SectionLength() < TSPacket::kSize) &&
00385 (pesdata[psip->SectionLength() + 1] != 0xff))
00386 {
00387
00388
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;
00517 }
00518 pmt.Parse();
00519
00520 uint programNumber = 1;
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
00535
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
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
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
00655 int pcrpidIndex = pmt.FindPID(pmt.PCRPID());
00656 if (pcrpidIndex < 0)
00657 {
00658
00659
00660 AddWritingPID(pmt.PCRPID());
00661 }
00662
00663
00664 ProgramMapTable *pmt2 = ProgramMapTable::Create(
00665 programNumber, _pid_pmt_single_program, pmt.PCRPID(),
00666 pmt.Version(), gdesc, pids, types, pdesc);
00667
00668
00669 if (sd)
00670 {
00671 sd->ReturnCachedTVCTTables(tvct);
00672 sd->ReturnCachedCVCTTables(cvct);
00673 }
00674
00675
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
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;
00816
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
00922 PSIPTable *psip = AssemblePSIP(tspacket, morePSIPTables);
00923 if (!psip)
00924 return;
00925
00926
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
00935 if (!psip->HasCRC())
00936 {
00937 HandleTables(tspacket->PID(), *psip);
00938 DONE_WITH_PSIP_PACKET();
00939 }
00940
00941
00942
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 {
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 {
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
00977
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();
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 {
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;
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
01033
01034
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
01093 int pos = curr_pos;
01094 int nextpos = pos + TSPacket::kSize;
01095 if (nextpos >= len)
01096 return -1;
01097
01098 while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE)
01099 {
01100 pos++;
01101 nextpos++;
01102 if (nextpos == len)
01103 return -2;
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
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
01961
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;
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;
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 }