00001
00002
00003
00004 #include <algorithm>
00005 using namespace std;
00006
00007
00008 #include <sys/time.h>
00009
00010
00011 #include <qstring.h>
00012 #include <qdeepcopy.h>
00013
00014
00015 #include "mpegstreamdata.h"
00016 #include "mpegtables.h"
00017 #include "RingBuffer.h"
00018 #include "mpegtables.h"
00019
00020 #include "atscstreamdata.h"
00021 #include "atsctables.h"
00022
00023
00024
00025 void init_sections(sections_t §, uint last_section)
00026 {
00027 static const unsigned char init_bits[8] =
00028 { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, };
00029
00030 sect.clear();
00031
00032 uint endz = last_section >> 3;
00033 if (endz)
00034 sect.resize(endz, 0x00);
00035 sect.resize(32, 0xff);
00036 sect[endz] = init_bits[last_section & 0x7];
00037
00038 #if 0
00039 cerr<<"init_sections ls("<<last_section<<"): "<<hex;
00040 for (uint i = 0 ; i < 32; i++)
00041 cerr<<((int)sect[i])<<" ";
00042 cerr<<dec<<endl;
00043 #endif
00044 }
00045
00046 const unsigned char MPEGStreamData::bit_sel[8] =
00047 {
00048 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
00049 };
00050
00064 MPEGStreamData::MPEGStreamData(int desiredProgram, bool cacheTables)
00065 : _sistandard("mpeg"),
00066 _have_CRC_bug(false),
00067 _local_utc_offset(0), _si_time_offset_cnt(0),
00068 _si_time_offset_indx(0),
00069 _eit_helper(NULL), _eit_rate(0.0f),
00070 _encryption_lock(true), _listener_lock(true),
00071 _cache_tables(cacheTables), _cache_lock(true),
00072
00073 _desired_program(desiredProgram),
00074 _recording_type("all"),
00075 _strip_pmt_descriptors(false),
00076 _normalize_stream_type(true),
00077 _pid_video_single_program(0xffffffff),
00078 _pid_pmt_single_program(0xffffffff),
00079 _pmt_single_program_num_video(1),
00080 _pmt_single_program_num_audio(0),
00081 _pat_single_program(NULL), _pmt_single_program(NULL),
00082 _invalid_pat_seen(false), _invalid_pat_warning(false)
00083 {
00084 _local_utc_offset = calc_utc_offset();
00085
00086
00087 memset(_si_time_offsets, 0, sizeof(_si_time_offsets));
00088
00089 AddListeningPID(MPEG_PAT_PID);
00090 }
00091
00092 MPEGStreamData::~MPEGStreamData()
00093 {
00094 Reset(-1);
00095 SetPATSingleProgram(NULL);
00096 SetPMTSingleProgram(NULL);
00097
00098
00099 psip_refcnt_map_t::iterator it = _cached_slated_for_deletion.begin();
00100 for (; it != _cached_slated_for_deletion.end(); ++it)
00101 delete it.key();
00102
00103 QMutexLocker locker(&_listener_lock);
00104 _mpeg_listeners.clear();
00105 _mpeg_sp_listeners.clear();
00106 }
00107
00108 void MPEGStreamData::SetDesiredProgram(int p)
00109 {
00110 bool reset = true;
00111 uint pid = 0;
00112 const ProgramAssociationTable* pat = NULL;
00113 pat_vec_t pats = GetCachedPATs();
00114
00115 for (uint i = (p) ? 0 : pats.size(); i < pats.size() && !pid; i++)
00116 {
00117 pat = pats[i];
00118 pid = pats[i]->FindPID(p);
00119 }
00120
00121 if (pid)
00122 {
00123 reset = false;
00124 _desired_program = p;
00125 ProcessPAT(pat);
00126 pmt_vec_t pmts = GetCachedPMTs();
00127 for (uint i = 0; i < pmts.size(); i++)
00128 {
00129 if (pmts[i]->ProgramNumber() == (uint)p)
00130 ProcessPMT(pmts[i]);
00131 }
00132 ReturnCachedPMTTables(pmts);
00133 }
00134
00135 ReturnCachedPATTables(pats);
00136
00137 if (reset)
00138 Reset(p);
00139 }
00140
00141 void MPEGStreamData::SetRecordingType(const QString &recording_type)
00142 {
00143 _recording_type = QDeepCopy<QString>(recording_type);
00144 uint neededVideo = (_recording_type == "tv") ? 1 : 0;
00145 uint neededAudio = (_recording_type == "audio") ? 1 : 0;
00146 SetVideoStreamsRequired(neededVideo);
00147 SetAudioStreamsRequired(neededAudio);
00148 }
00149
00150 QString MPEGStreamData::GetRecordingType(void) const
00151 {
00152 return QDeepCopy<QString>(_recording_type);
00153 }
00154
00155 void MPEGStreamData::SetEITHelper(EITHelper *eit_helper)
00156 {
00157 QMutexLocker locker(&_listener_lock);
00158 _eit_helper = eit_helper;
00159 }
00160
00161 void MPEGStreamData::SetEITRate(float rate)
00162 {
00163 QMutexLocker locker(&_listener_lock);
00164 _eit_rate = rate;
00165 }
00166
00167 void MPEGStreamData::Reset(int desiredProgram)
00168 {
00169 _desired_program = desiredProgram;
00170 _recording_type = "all";
00171 _strip_pmt_descriptors = false;
00172 _normalize_stream_type = true;
00173
00174 _invalid_pat_seen = false;
00175
00176 SetPATSingleProgram(NULL);
00177 SetPMTSingleProgram(NULL);
00178
00179 pid_pes_map_t old = _partial_pes_packet_cache;
00180 pid_pes_map_t::iterator it = old.begin();
00181 for (; it != old.end(); ++it)
00182 DeletePartialPES(it.key());
00183 _partial_pes_packet_cache.clear();
00184
00185 _pids_listening.clear();
00186 _pids_notlistening.clear();
00187 _pids_writing.clear();
00188 _pids_audio.clear();
00189
00190 _pid_video_single_program = _pid_pmt_single_program = 0xffffffff;
00191
00192 _pat_version.clear();
00193 _pat_section_seen.clear();
00194
00195 _pmt_version.clear();
00196 _pmt_section_seen.clear();
00197
00198 {
00199 QMutexLocker locker(&_cache_lock);
00200
00201 pat_cache_t::iterator it1 = _cached_pats.begin();
00202 for (; it1 != _cached_pats.end(); ++it1)
00203 DeleteCachedTable(*it1);
00204 _cached_pats.clear();
00205
00206 pmt_cache_t::iterator it2 = _cached_pmts.begin();
00207 for (; it2 != _cached_pmts.end(); ++it2)
00208 DeleteCachedTable(*it2);
00209 _cached_pmts.clear();
00210 }
00211
00212 ResetDecryptionMonitoringState();
00213
00214 AddListeningPID(MPEG_PAT_PID);
00215 }
00216
00217 void MPEGStreamData::DeletePartialPES(uint pid)
00218 {
00219 pid_pes_map_t::iterator it = _partial_pes_packet_cache.find(pid);
00220 if (it != _partial_pes_packet_cache.end())
00221 {
00222 PESPacket *pkt = *it;
00223 _partial_pes_packet_cache.erase(it);
00224 delete pkt;
00225 }
00226 }
00227
00249 PSIPTable* MPEGStreamData::AssemblePSIP(const TSPacket* tspacket,
00250 bool &moreTablePackets)
00251 {
00252 bool broken = true;
00253 moreTablePackets = true;
00254
00255 PESPacket* partial = GetPartialPES(tspacket->PID());
00256 if (partial && partial->AddTSPacket(tspacket, broken) && !broken)
00257 {
00258
00259 if ((partial->PSIOffset() + 1 + 3) > partial->TSSizeInBuffer())
00260 {
00261 VERBOSE(VB_RECORD,
00262 QString("Discarding broken PES packet. Packet's length at "
00263 "position %1 isn't in the buffer of %2 bytes.")
00264 .arg(partial->PSIOffset() + 1 + 3)
00265 .arg(partial->TSSizeInBuffer()));
00266 DeletePartialPES(tspacket->PID());
00267 return NULL;
00268 }
00269
00270
00271 bool buggy = _have_CRC_bug &&
00272 ((TableID::PMT == partial->StreamID()) ||
00273 (TableID::PAT == partial->StreamID()));
00274 if (!buggy && !partial->IsGood())
00275 {
00276 VERBOSE(VB_SIPARSER, "Discarding broken PES packet");
00277 DeletePartialPES(tspacket->PID());
00278 return NULL;
00279 }
00280
00281 PSIPTable* psip = new PSIPTable(*partial);
00282
00283
00284
00285 uint packetStart = partial->PSIOffset() + 1 + psip->SectionLength();
00286 if (packetStart < partial->TSSizeInBuffer())
00287 {
00288 if (partial->pesdata()[psip->SectionLength()] != 0xff)
00289 {
00290 #if 0
00291
00292
00293
00294
00295
00296
00297 if ((partial->TSSizeInBuffer() > TSPacket::SIZE) &&
00298 (packetStart >
00299 partial->TSSizeInBuffer() - TSPacket::PAYLOAD_SIZE))
00300 {
00301
00302 SavePartialPES(tspacket->PID(),
00303 new PESPacket(*tspacket));
00304 }
00305 else
00306 #endif
00307 {
00308 partial->SetPSIOffset(partial->PSIOffset() +
00309 psip->SectionLength());
00310 }
00311 return psip;
00312 }
00313 }
00314
00315 if (packetStart > partial->TSSizeInBuffer())
00316 {
00317 VERBOSE(VB_RECORD, QString("Discarding broken PES packet. ") +
00318 QString("Packet with %1 bytes doesn't fit "
00319 "into a buffer of %2 bytes.")
00320 .arg(packetStart).arg(partial->TSSizeInBuffer()));
00321 delete psip;
00322 psip = NULL;
00323 }
00324
00325 moreTablePackets = false;
00326 DeletePartialPES(tspacket->PID());
00327 return psip;
00328 }
00329 else if (partial)
00330 {
00331 if (broken)
00332 DeletePartialPES(tspacket->PID());
00333
00334 moreTablePackets = false;
00335 return 0;
00336 }
00337
00338 if (!tspacket->PayloadStart())
00339 {
00340
00341
00342 moreTablePackets = false;
00343 return 0;
00344 }
00345
00346 const int offset = tspacket->AFCOffset() + tspacket->StartOfFieldPointer();
00347 if (offset>181)
00348 {
00349 VERBOSE(VB_IMPORTANT, "Error: offset>181, pes length & "
00350 "current can not be queried");
00351 return 0;
00352 }
00353
00354
00355
00356 const int extra_offset = 4;
00357
00358 const unsigned char* pesdata = tspacket->data() + offset;
00359 const int pes_length = (pesdata[2] & 0x0f) << 8 | pesdata[3];
00360 if ((pes_length + offset + extra_offset) > 188)
00361 {
00362 SavePartialPES(tspacket->PID(), new PESPacket(*tspacket));
00363 moreTablePackets = false;
00364 return 0;
00365 }
00366
00367 PSIPTable *psip = new PSIPTable(*tspacket);
00368
00369
00370
00371
00372 if ((offset + psip->SectionLength() < TSPacket::SIZE) &&
00373 (pesdata[psip->SectionLength() + 1] != 0xff))
00374 {
00375
00376
00377 PESPacket *pesp = new PESPacket(*tspacket);
00378 pesp->SetPSIOffset(offset + psip->SectionLength());
00379 SavePartialPES(tspacket->PID(), pesp);
00380 return psip;
00381 }
00382
00383 moreTablePackets = false;
00384 return psip;
00385 }
00386
00387 bool MPEGStreamData::CreatePATSingleProgram(
00388 const ProgramAssociationTable& pat)
00389 {
00390 VERBOSE(VB_RECORD, "CreatePATSingleProgram()");
00391 VERBOSE(VB_RECORD, "PAT in input stream");
00392 VERBOSE(VB_RECORD, pat.toString());
00393 if (_desired_program < 0)
00394 {
00395 VERBOSE(VB_RECORD, "Desired program not set yet");
00396 return false;
00397 }
00398 _pid_pmt_single_program = pat.FindPID(_desired_program);
00399 VERBOSE(VB_RECORD, QString("desired_program(%1) pid(0x%2)").
00400 arg(_desired_program).arg(_pid_pmt_single_program, 0, 16));
00401
00402 if (!_pid_pmt_single_program)
00403 {
00404 _pid_pmt_single_program = pat.FindAnyPID();
00405 if (!_pid_pmt_single_program)
00406 {
00407 VERBOSE(VB_IMPORTANT,
00408 QString("No program found in PAT."
00409 " This recording will not play in MythTV."));
00410 }
00411 VERBOSE(VB_IMPORTANT,
00412 QString("Desired program #%1 not found in PAT."
00413 "\n\t\t\tCan Not create single program PAT.")
00414 .arg(_desired_program));
00415 SetPATSingleProgram(NULL);
00416 return false;
00417 }
00418
00419 AddListeningPID(_pid_pmt_single_program);
00420
00421 vector<uint> pnums, pids;
00422
00423 pnums.push_back(1);
00424 pids.push_back(_pid_pmt_single_program);
00425
00426 uint tsid = pat.TableIDExtension();
00427 uint ver = pat.Version();
00428 ProgramAssociationTable* pat2 =
00429 ProgramAssociationTable::Create(tsid, ver, pnums, pids);
00430
00431 if (!pat2)
00432 {
00433 VERBOSE(VB_IMPORTANT, "MPEGStreamData::CreatePATSingleProgram: "
00434 "Failed to create Program Association Table.");
00435 return false;
00436 }
00437
00438 pat2->tsheader()->SetContinuityCounter(pat.tsheader()->ContinuityCounter());
00439
00440 VERBOSE(VB_RECORD, QString("pmt_pid(0x%1)")
00441 .arg(_pid_pmt_single_program, 0, 16));
00442 VERBOSE(VB_RECORD, "PAT for output stream");
00443 VERBOSE(VB_RECORD, pat2->toString());
00444
00445 SetPATSingleProgram(pat2);
00446
00447 return true;
00448
00449 }
00450
00451 desc_list_t extract_atsc_desc(const tvct_vec_t &tvct,
00452 const cvct_vec_t &cvct,
00453 uint pnum)
00454 {
00455 desc_list_t desc;
00456
00457 vector<const VirtualChannelTable*> vct;
00458
00459 for (uint i = 0; i < tvct.size(); i++)
00460 vct.push_back(tvct[i]);
00461
00462 for (uint i = 0; i < cvct.size(); i++)
00463 vct.push_back(cvct[i]);
00464
00465 for (uint i = 0; i < tvct.size(); i++)
00466 {
00467 for (uint j = 0; j < vct[i]->ChannelCount(); j++)
00468 {
00469 if (vct[i]->ProgramNumber(j) == pnum)
00470 {
00471 desc_list_t ldesc = MPEGDescriptor::ParseOnlyInclude(
00472 vct[i]->Descriptors(j), vct[i]->DescriptorsLength(j),
00473 DescriptorID::caption_service);
00474
00475 if (ldesc.size())
00476 desc.insert(desc.end(), ldesc.begin(), ldesc.end());
00477 }
00478 }
00479
00480 if (0 != vct[i]->GlobalDescriptorsLength())
00481 {
00482 desc_list_t vdesc = MPEGDescriptor::ParseOnlyInclude(
00483 vct[i]->GlobalDescriptors(),
00484 vct[i]->GlobalDescriptorsLength(),
00485 DescriptorID::caption_service);
00486
00487 if (vdesc.size())
00488 desc.insert(desc.end(), vdesc.begin(), vdesc.end());
00489 }
00490 }
00491
00492 return desc;
00493 }
00494
00495 bool MPEGStreamData::CreatePMTSingleProgram(const ProgramMapTable &pmt)
00496 {
00497 VERBOSE(VB_RECORD, "CreatePMTSingleProgram()");
00498 VERBOSE(VB_RECORD, "PMT in input stream");
00499 VERBOSE(VB_RECORD, pmt.toString());
00500
00501 if (!PATSingleProgram())
00502 {
00503 VERBOSE(VB_RECORD, "no PAT yet...");
00504 return false;
00505 }
00506 pmt.Parse();
00507
00508 uint programNumber = 1;
00509
00510 ATSCStreamData *sd = NULL;
00511 tvct_vec_t tvct;
00512 cvct_vec_t cvct;
00513
00514 desc_list_t gdesc;
00515
00516 if (!_strip_pmt_descriptors)
00517 {
00518 gdesc = MPEGDescriptor::ParseAndExclude(
00519 pmt.ProgramInfo(), pmt.ProgramInfoLength(),
00520 DescriptorID::conditional_access);
00521
00522
00523
00524 sd = dynamic_cast<ATSCStreamData*>(this);
00525 if (sd && !MPEGDescriptor::Find(gdesc, DescriptorID::caption_service))
00526 {
00527 tvct = sd->GetAllCachedTVCTs();
00528 cvct = sd->GetAllCachedCVCTs();
00529
00530 desc_list_t vdesc = extract_atsc_desc(
00531 tvct, cvct, pmt.ProgramNumber());
00532
00533 if (vdesc.size())
00534 gdesc.insert(gdesc.end(), vdesc.begin(), vdesc.end());
00535 }
00536 }
00537
00538 vector<uint> pids;
00539 vector<uint> types;
00540 vector<desc_list_t> pdesc;
00541
00542 uint video_cnt = 0;
00543 uint audio_cnt = 0;
00544
00545 vector<uint> videoPIDs, audioPIDs, dataPIDs;
00546
00547 for (uint i = 0; i < pmt.StreamCount(); i++)
00548 {
00549 desc_list_t desc = MPEGDescriptor::ParseAndExclude(
00550 pmt.StreamInfo(i), pmt.StreamInfoLength(i),
00551 DescriptorID::conditional_access);
00552
00553 uint type = StreamID::Normalize(
00554 pmt.StreamType(i), desc, _sistandard);
00555
00556 bool is_video = StreamID::IsVideo(type);
00557 bool is_audio = StreamID::IsAudio(type);
00558
00559 uint pid = pmt.StreamPID(i);
00560
00561 if (is_audio)
00562 {
00563 audio_cnt++;
00564 audioPIDs.push_back(pid);
00565 }
00566
00567 #ifdef DEBUG_MPEG_RADIO
00568 if (is_video)
00569 continue;
00570 #endif // DEBUG_MPEG_RADIO
00571
00572 if (is_video)
00573 {
00574 video_cnt++;
00575 videoPIDs.push_back(pid);
00576 }
00577
00578 if (_strip_pmt_descriptors)
00579 desc.clear();
00580
00581
00582 if (_recording_type == "tv" && !is_audio && !is_video &&
00583 !MPEGDescriptor::Find(desc, DescriptorID::teletext) &&
00584 !MPEGDescriptor::Find(desc, DescriptorID::subtitling))
00585 {
00586 continue;
00587 }
00588
00589 if (!is_audio && !is_video)
00590 dataPIDs.push_back(pid);
00591
00592 pdesc.push_back(desc);
00593 pids.push_back(pid);
00594 types.push_back(type);
00595 }
00596
00597 if (video_cnt < _pmt_single_program_num_video)
00598 {
00599 VERBOSE(VB_RECORD, "Only "<<video_cnt<<" video streams seen in PMT, "
00600 "but "<<_pmt_single_program_num_video<<" are required.");
00601 return false;
00602 }
00603
00604 if (audioPIDs.size() < _pmt_single_program_num_audio)
00605 {
00606 VERBOSE(VB_RECORD, "Only "<<audioPIDs.size()
00607 <<" audio streams seen in PMT, but "
00608 <<_pmt_single_program_num_audio<<" are required.");
00609 return false;
00610 }
00611
00612 _pids_audio.clear();
00613 for (uint i = 0; i < audioPIDs.size(); i++)
00614 AddAudioPID(audioPIDs[i]);
00615
00616 if (videoPIDs.size() >= 1)
00617 _pid_video_single_program = videoPIDs[0];
00618 for (uint i = 1; i < videoPIDs.size(); i++)
00619 AddWritingPID(videoPIDs[i]);
00620
00621 for (uint i = 0; i < dataPIDs.size(); i++)
00622 AddWritingPID(dataPIDs[i]);
00623
00624
00625 int pcrpidIndex = pmt.FindPID(pmt.PCRPID());
00626 if (pcrpidIndex < 0)
00627 {
00628
00629
00630 AddWritingPID(pmt.PCRPID());
00631 }
00632
00633
00634 ProgramMapTable *pmt2 = ProgramMapTable::Create(
00635 programNumber, _pid_pmt_single_program, pmt.PCRPID(),
00636 pmt.Version(), gdesc, pids, types, pdesc);
00637
00638
00639 if (sd)
00640 {
00641 sd->ReturnCachedTVCTTables(tvct);
00642 sd->ReturnCachedCVCTTables(cvct);
00643 }
00644
00645
00646 uint cc_cnt = pmt.tsheader()->ContinuityCounter();
00647 pmt2->tsheader()->SetContinuityCounter(cc_cnt);
00648 SetPMTSingleProgram(pmt2);
00649
00650 VERBOSE(VB_RECORD, "PMT for output stream");
00651 VERBOSE(VB_RECORD, pmt2->toString());
00652
00653 return true;
00654 }
00655
00659 bool MPEGStreamData::IsRedundant(uint pid, const PSIPTable &psip) const
00660 {
00661 (void) pid;
00662 const int table_id = psip.TableID();
00663 const int version = psip.Version();
00664
00665 if (TableID::PAT == table_id)
00666 {
00667 if (VersionPAT(psip.TableIDExtension()) != version)
00668 return false;
00669 return PATSectionSeen(psip.TableIDExtension(), psip.Section());
00670 }
00671
00672 if (TableID::CAT == table_id)
00673 return false;
00674
00675 if (TableID::PMT == table_id)
00676 {
00677 if (VersionPMT(psip.TableIDExtension()) != version)
00678 return false;
00679 return PMTSectionSeen(psip.TableIDExtension(), psip.Section());
00680 }
00681
00682 return false;
00683 }
00684
00688 bool MPEGStreamData::HandleTables(uint pid, const PSIPTable &psip)
00689 {
00690 if (IsRedundant(pid, psip))
00691 return true;
00692
00693 const int version = psip.Version();
00694
00695 switch (psip.TableID())
00696 {
00697 case TableID::PAT:
00698 {
00699 uint tsid = psip.TableIDExtension();
00700 SetVersionPAT(tsid, version, psip.LastSection());
00701 SetPATSectionSeen(tsid, psip.Section());
00702
00703 ProgramAssociationTable pat(psip);
00704
00705 if (_cache_tables)
00706 CachePAT(&pat);
00707
00708 ProcessPAT(&pat);
00709
00710 return true;
00711 }
00712 case TableID::CAT:
00713 {
00714 ConditionalAccessTable cat(psip);
00715
00716 _listener_lock.lock();
00717 for (uint i = 0; i < _mpeg_listeners.size(); i++)
00718 _mpeg_listeners[i]->HandleCAT(&cat);
00719 _listener_lock.unlock();
00720
00721 return true;
00722 }
00723 case TableID::PMT:
00724 {
00725 uint prog_num = psip.TableIDExtension();
00726 SetVersionPMT(prog_num, version, psip.LastSection());
00727 SetPMTSectionSeen(prog_num, psip.Section());
00728
00729 ProgramMapTable pmt(psip);
00730
00731 if (_cache_tables)
00732 CachePMT(&pmt);
00733
00734 ProcessPMT(&pmt);
00735
00736 return true;
00737 }
00738 }
00739 return false;
00740 }
00741
00742 void MPEGStreamData::ProcessPAT(const ProgramAssociationTable *pat)
00743 {
00744 bool foundProgram = pat->FindPID(_desired_program);
00745
00746 _listener_lock.lock();
00747 for (uint i = 0; i < _mpeg_listeners.size(); i++)
00748 _mpeg_listeners[i]->HandlePAT(pat);
00749 _listener_lock.unlock();
00750
00751 if (_desired_program < 0)
00752 return;
00753
00754 bool send_single_program = false;
00755 if (!_invalid_pat_seen && !foundProgram)
00756 {
00757 _invalid_pat_seen = true;
00758 _invalid_pat_warning = false;
00759 _invalid_pat_timer.start();
00760 VERBOSE(VB_RECORD, "ProcessPAT: "
00761 "PAT is missing program, setting timeout");
00762 }
00763 else if (_invalid_pat_seen && !foundProgram &&
00764 (_invalid_pat_timer.elapsed() > 400) && !_invalid_pat_warning)
00765 {
00766 _invalid_pat_warning = true;
00767
00768 VERBOSE(VB_IMPORTANT, "ProcessPAT: Program not found in PAT. "
00769 "\n\t\t\tRescan your transports.");
00770
00771 send_single_program = CreatePATSingleProgram(*pat);
00772 }
00773 else if (foundProgram)
00774 {
00775 if (_invalid_pat_seen)
00776 VERBOSE(VB_RECORD, "ProcessPAT: Good PAT seen after a bad PAT");
00777
00778 _invalid_pat_seen = false;
00779
00780 send_single_program = CreatePATSingleProgram(*pat);
00781 }
00782
00783 if (send_single_program)
00784 {
00785 QMutexLocker locker(&_listener_lock);
00786 ProgramAssociationTable *pat_sp = PATSingleProgram();
00787 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++)
00788 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp);
00789 }
00790 }
00791
00792 void MPEGStreamData::ProcessPMT(const ProgramMapTable *pmt)
00793 {
00794 _listener_lock.lock();
00795 for (uint i = 0; i < _mpeg_listeners.size(); i++)
00796 _mpeg_listeners[i]->HandlePMT(pmt->ProgramNumber(), pmt);
00797 _listener_lock.unlock();
00798
00799 bool desired = pmt->ProgramNumber() == (uint) _desired_program;
00800 if (desired && CreatePMTSingleProgram(*pmt))
00801 {
00802 QMutexLocker locker(&_listener_lock);
00803 ProgramMapTable *pmt_sp = PMTSingleProgram();
00804 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++)
00805 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp);
00806 }
00807 }
00808
00809 double MPEGStreamData::TimeOffset(void) const
00810 {
00811 QMutex locker(&_si_time_lock);
00812 if (!_si_time_offset_cnt)
00813 return 0.0;
00814
00815 double avg_offset = 0.0;
00816 double mult = 1.0 / _si_time_offset_cnt;
00817 for (uint i = 0; i < _si_time_offset_cnt; i++)
00818 avg_offset += _si_time_offsets[i] * mult;
00819
00820 return avg_offset;
00821 }
00822
00823 void MPEGStreamData::UpdateTimeOffset(uint64_t _si_utc_time)
00824 {
00825 struct timeval tm;
00826 if (gettimeofday(&tm, NULL) != 0)
00827 return;
00828
00829 double utc_time = tm.tv_sec + (tm.tv_usec * 0.000001);
00830 double si_time = _si_utc_time;
00831
00832 QMutex locker(&_si_time_lock);
00833 _si_time_offsets[_si_time_offset_indx] = si_time - utc_time;
00834
00835 if (_si_time_offset_indx + 1 > _si_time_offset_cnt)
00836 _si_time_offset_cnt = _si_time_offset_indx + 1;
00837
00838 _si_time_offset_indx = (_si_time_offset_indx + 1) & 0xf;
00839
00840 }
00841
00842 #define DONE_WITH_PES_PACKET() { if (psip) delete psip; \
00843 if (morePSIPPackets) goto HAS_ANOTHER_PES; else return; }
00844
00848 void MPEGStreamData::HandleTSTables(const TSPacket* tspacket)
00849 {
00850 bool morePSIPPackets;
00851 HAS_ANOTHER_PES:
00852
00853 PSIPTable *psip = AssemblePSIP(tspacket, morePSIPPackets);
00854 if (!psip)
00855 return;
00856
00857
00858 if (TableID::TDT == psip->TableID())
00859 {
00860 HandleTables(tspacket->PID(), *psip);
00861 DONE_WITH_PES_PACKET();
00862 }
00863
00864
00865 if ((TableID::ST == psip->TableID()) ||
00866 (TableID::STUFFING == psip->TableID()))
00867 DONE_WITH_PES_PACKET();
00868
00869
00870
00871 bool buggy = _have_CRC_bug &&
00872 ((TableID::PMT == psip->TableID()) ||
00873 (TableID::PAT == psip->TableID()));
00874 if (!buggy && !psip->IsGood())
00875 {
00876 VERBOSE(VB_RECORD, QString("PSIP packet failed CRC check. "
00877 "pid(0x%1) type(0x%2)")
00878 .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16));
00879 DONE_WITH_PES_PACKET();
00880 }
00881
00882 if (!psip->IsCurrent())
00883 DONE_WITH_PES_PACKET();
00884
00885 if (tspacket->ScramplingControl())
00886 {
00887 VERBOSE(VB_RECORD,
00888 "PSIP packet is scrambled, not ATSC/DVB compiant");
00889 DONE_WITH_PES_PACKET();
00890 }
00891
00892 if (!psip->VerifyPSIP(!_have_CRC_bug))
00893 {
00894 VERBOSE(VB_RECORD, "PSIP table is invalid");
00895 DONE_WITH_PES_PACKET();
00896 }
00897
00898
00899
00900 if (IsRedundant(tspacket->PID(), *psip))
00901 {
00902 if (TableID::PAT == psip->TableID())
00903 {
00904 QMutexLocker locker(&_listener_lock);
00905 ProgramAssociationTable *pat_sp = PATSingleProgram();
00906 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++)
00907 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp);
00908 }
00909 if (TableID::PMT == psip->TableID() &&
00910 tspacket->PID() == _pid_pmt_single_program)
00911 {
00912 QMutexLocker locker(&_listener_lock);
00913 ProgramMapTable *pmt_sp = PMTSingleProgram();
00914 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++)
00915 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp);
00916 }
00917 DONE_WITH_PES_PACKET();
00918 }
00919
00920 HandleTables(tspacket->PID(), *psip);
00921
00922 DONE_WITH_PES_PACKET();
00923 }
00924 #undef DONE_WITH_PES_PACKET
00925
00926 int MPEGStreamData::ProcessData(const unsigned char *buffer, int len)
00927 {
00928 int pos = 0;
00929 bool resync = false;
00930
00931 while (pos + 187 < len)
00932 {
00933 if (buffer[pos] != SYNC_BYTE || resync)
00934 {
00935 int newpos = ResyncStream(buffer, pos+1, len);
00936 if (newpos == -1)
00937 return len - pos;
00938 if (newpos == -2)
00939 return TSPacket::SIZE;
00940
00941 pos = newpos;
00942 }
00943
00944 const TSPacket *pkt = reinterpret_cast<const TSPacket*>(&buffer[pos]);
00945 if (ProcessTSPacket(*pkt))
00946 {
00947 pos += TSPacket::SIZE;
00948 resync = false;
00949 }
00950 else
00951 resync = true;
00952 }
00953
00954 return len - pos;
00955 }
00956
00957 bool MPEGStreamData::ProcessTSPacket(const TSPacket& tspacket)
00958 {
00959 bool ok = !tspacket.TransportError();
00960
00961 if (IsEncryptionTestPID(tspacket.PID()))
00962 {
00963 ProcessEncryptedPacket(tspacket);
00964 }
00965
00966 if (!ok)
00967 return false;
00968
00969 if (!tspacket.ScramplingControl() && tspacket.HasPayload())
00970 {
00971 if (IsVideoPID(tspacket.PID()))
00972 {
00973 for (uint j = 0; j < _ts_av_listeners.size(); j++)
00974 _ts_av_listeners[j]->ProcessVideoTSPacket(tspacket);
00975
00976 return true;
00977 }
00978
00979 if (IsAudioPID(tspacket.PID()))
00980 {
00981 for (uint j = 0; j < _ts_av_listeners.size(); j++)
00982 _ts_av_listeners[j]->ProcessAudioTSPacket(tspacket);
00983
00984 return true;
00985 }
00986
00987 if (IsWritingPID(tspacket.PID()) && _ts_writing_listeners.size())
00988 {
00989 for (uint j = 0; j < _ts_writing_listeners.size(); j++)
00990 _ts_writing_listeners[j]->ProcessTSPacket(tspacket);
00991 }
00992
00993 if (IsListeningPID(tspacket.PID()))
00994 {
00995 HandleTSTables(&tspacket);
00996 }
00997 }
00998
00999 return true;
01000 }
01001
01002 int MPEGStreamData::ResyncStream(const unsigned char *buffer, int curr_pos,
01003 int len)
01004 {
01005
01006 int pos = curr_pos;
01007 int nextpos = pos + TSPacket::SIZE;
01008 if (nextpos >= len)
01009 return -1;
01010
01011 while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE)
01012 {
01013 pos++;
01014 nextpos++;
01015 if (nextpos == len)
01016 return -2;
01017 }
01018
01019 return pos;
01020 }
01021
01022 bool MPEGStreamData::IsListeningPID(uint pid) const
01023 {
01024 pid_map_t::const_iterator it = _pids_listening.find(pid);
01025 return it != _pids_listening.end();
01026 }
01027
01028 bool MPEGStreamData::IsNotListeningPID(uint pid) const
01029 {
01030 pid_map_t::const_iterator it = _pids_notlistening.find(pid);
01031 return it != _pids_notlistening.end();
01032 }
01033
01034 bool MPEGStreamData::IsWritingPID(uint pid) const
01035 {
01036 pid_map_t::const_iterator it = _pids_writing.find(pid);
01037 return it != _pids_writing.end();
01038 }
01039
01040 bool MPEGStreamData::IsAudioPID(uint pid) const
01041 {
01042 pid_map_t::const_iterator it = _pids_audio.find(pid);
01043 return it != _pids_audio.end();
01044 }
01045
01046 uint MPEGStreamData::GetPIDs(pid_map_t &pids) const
01047 {
01048 uint sz = pids.size();
01049
01050 if (_pid_video_single_program < 0x1fff)
01051 pids[_pid_video_single_program] = kPIDPriorityHigh;
01052
01053 pid_map_t::const_iterator it = _pids_listening.begin();
01054 for (; it != _pids_listening.end(); ++it)
01055 pids[it.key()] = max(pids[it.key()], *it);
01056
01057 it = _pids_audio.begin();
01058 for (; it != _pids_audio.end(); ++it)
01059 pids[it.key()] = max(pids[it.key()], *it);
01060
01061 it = _pids_writing.begin();
01062 for (; it != _pids_writing.end(); ++it)
01063 pids[it.key()] = max(pids[it.key()], *it);
01064
01065 return pids.size() - sz;
01066 }
01067
01068 PIDPriority MPEGStreamData::GetPIDPriority(uint pid) const
01069 {
01070 if (_pid_video_single_program == pid)
01071 return kPIDPriorityHigh;
01072
01073 pid_map_t::const_iterator it;
01074 it = _pids_listening.find(pid);
01075 if (it != _pids_listening.end())
01076 return *it;
01077 it = _pids_notlistening.find(pid);
01078 if (it != _pids_notlistening.end())
01079 return *it;
01080 it = _pids_writing.find(pid);
01081 if (it != _pids_writing.end())
01082 return *it;
01083 it = _pids_audio.find(pid);
01084 if (it != _pids_audio.end())
01085 return *it;
01086
01087 return kPIDPriorityNone;
01088 }
01089
01090 void MPEGStreamData::SavePartialPES(uint pid, PESPacket* packet)
01091 {
01092 pid_pes_map_t::iterator it = _partial_pes_packet_cache.find(pid);
01093 if (it == _partial_pes_packet_cache.end())
01094 _partial_pes_packet_cache[pid] = packet;
01095 else
01096 {
01097 PESPacket *old = *it;
01098 _partial_pes_packet_cache.replace(pid, packet);
01099 delete old;
01100 }
01101 }
01102
01103 void MPEGStreamData::SetPATSectionSeen(uint tsid, uint section)
01104 {
01105 sections_map_t::iterator it = _pat_section_seen.find(tsid);
01106 if (it == _pat_section_seen.end())
01107 {
01108 _pat_section_seen[tsid].resize(32, 0);
01109 it = _pat_section_seen.find(tsid);
01110 }
01111 (*it)[section>>3] |= bit_sel[section & 0x7];
01112 }
01113
01114 bool MPEGStreamData::PATSectionSeen(uint tsid, uint section) const
01115 {
01116 sections_map_t::const_iterator it = _pat_section_seen.find(tsid);
01117 if (it == _pat_section_seen.end())
01118 return false;
01119 return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
01120 }
01121
01122 bool MPEGStreamData::HasAllPATSections(uint tsid) const
01123 {
01124 sections_map_t::const_iterator it = _pat_section_seen.find(tsid);
01125 if (it == _pat_section_seen.end())
01126 return false;
01127 for (uint i = 0; i < 32; i++)
01128 if ((*it)[i] != 0xff)
01129 return false;
01130 return true;
01131 }
01132
01133 void MPEGStreamData::SetPMTSectionSeen(uint prog_num, uint section)
01134 {
01135 sections_map_t::iterator it = _pmt_section_seen.find(prog_num);
01136 if (it == _pmt_section_seen.end())
01137 {
01138 _pmt_section_seen[prog_num].resize(32, 0);
01139 it = _pmt_section_seen.find(prog_num);
01140 }
01141 (*it)[section>>3] |= bit_sel[section & 0x7];
01142 }
01143
01144 bool MPEGStreamData::PMTSectionSeen(uint prog_num, uint section) const
01145 {
01146 sections_map_t::const_iterator it = _pmt_section_seen.find(prog_num);
01147 if (it == _pmt_section_seen.end())
01148 return false;
01149 return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
01150 }
01151
01152 bool MPEGStreamData::HasAllPMTSections(uint prog_num) const
01153 {
01154 sections_map_t::const_iterator it = _pmt_section_seen.find(prog_num);
01155 if (it == _pmt_section_seen.end())
01156 return false;
01157 for (uint i = 0; i < 32; i++)
01158 if ((*it)[i] != 0xff)
01159 return false;
01160 return true;
01161 }
01162
01163 bool MPEGStreamData::HasProgram(uint progNum) const
01164 {
01165 pmt_ptr_t pmt = GetCachedPMT(progNum, 0);
01166 bool hasit = pmt;
01167 ReturnCachedTable(pmt);
01168
01169 return hasit;
01170 }
01171
01172 bool MPEGStreamData::HasCachedAllPAT(uint tsid) const
01173 {
01174 QMutexLocker locker(&_cache_lock);
01175
01176 pat_cache_t::const_iterator it = _cached_pats.find(tsid << 8);
01177 if (it == _cached_pats.end())
01178 return false;
01179
01180 uint last_section = (*it)->LastSection();
01181 if (!last_section)
01182 return true;
01183
01184 for (uint i = 1; i <= last_section; i++)
01185 if (_cached_pats.find((tsid << 8) | i) == _cached_pats.end())
01186 return false;
01187
01188 return true;
01189 }
01190
01191 bool MPEGStreamData::HasCachedAnyPAT(uint tsid) const
01192 {
01193 QMutexLocker locker(&_cache_lock);
01194
01195 for (uint i = 0; i <= 255; i++)
01196 if (_cached_pats.find((tsid << 8) | i) != _cached_pats.end())
01197 return true;
01198
01199 return false;
01200 }
01201
01202 bool MPEGStreamData::HasCachedAnyPAT(void) const
01203 {
01204 QMutexLocker locker(&_cache_lock);
01205 return _cached_pats.size();
01206 }
01207
01208 bool MPEGStreamData::HasCachedAllPMT(uint pnum) const
01209 {
01210 QMutexLocker locker(&_cache_lock);
01211
01212 pmt_cache_t::const_iterator it = _cached_pmts.find(pnum << 8);
01213 if (it == _cached_pmts.end())
01214 return false;
01215
01216 uint last_section = (*it)->LastSection();
01217 if (!last_section)
01218 return true;
01219
01220 for (uint i = 1; i <= last_section; i++)
01221 if (_cached_pmts.find((pnum << 8) | i) == _cached_pmts.end())
01222 return false;
01223
01224 return true;
01225 }
01226
01227 bool MPEGStreamData::HasCachedAnyPMT(uint pnum) const
01228 {
01229 QMutexLocker locker(&_cache_lock);
01230
01231 for (uint i = 0; i <= 255; i++)
01232 if (_cached_pmts.find((pnum << 8) | i) != _cached_pmts.end())
01233 return true;
01234
01235 return false;
01236 }
01237
01238 bool MPEGStreamData::HasCachedAllPMTs(void) const
01239 {
01240 QMutexLocker locker(&_cache_lock);
01241
01242 pat_cache_t::const_iterator it = _cached_pats.begin();
01243 for (; it != _cached_pats.end(); ++it)
01244 {
01245 const ProgramAssociationTable *pat = *it;
01246 if (!HasCachedAllPAT(pat->TransportStreamID()))
01247 return false;
01248
01249 for (uint i = 0; i < pat->ProgramCount(); i++)
01250 if (!HasCachedAllPMT(pat->ProgramNumber(i)))
01251 return false;
01252 }
01253
01254 return true;
01255 }
01256
01257 const pat_ptr_t MPEGStreamData::GetCachedPAT(
01258 uint tsid, uint section_num) const
01259 {
01260 QMutexLocker locker(&_cache_lock);
01261 ProgramAssociationTable *pat = NULL;
01262
01263 uint key = (tsid << 8) | section_num;
01264 pat_cache_t::const_iterator it = _cached_pats.find(key);
01265 if (it != _cached_pats.end())
01266 IncrementRefCnt(pat = *it);
01267
01268 return pat;
01269 }
01270
01271 pat_vec_t MPEGStreamData::GetCachedPATs(void) const
01272 {
01273 QMutexLocker locker(&_cache_lock);
01274 pat_vec_t pats;
01275
01276 pat_cache_t::const_iterator it = _cached_pats.begin();
01277 for (; it != _cached_pats.end(); ++it)
01278 {
01279 ProgramAssociationTable* pat = *it;
01280 IncrementRefCnt(pat);
01281 pats.push_back(pat);
01282 }
01283
01284 return pats;
01285 }
01286
01287 const pmt_ptr_t MPEGStreamData::GetCachedPMT(
01288 uint program_num, uint section_num) const
01289 {
01290 QMutexLocker locker(&_cache_lock);
01291 ProgramMapTable *pmt = NULL;
01292
01293 uint key = (program_num << 8) | section_num;
01294 pmt_cache_t::const_iterator it = _cached_pmts.find(key);
01295 if (it != _cached_pmts.end())
01296 IncrementRefCnt(pmt = *it);
01297
01298 return pmt;
01299 }
01300
01301 pmt_vec_t MPEGStreamData::GetCachedPMTs(void) const
01302 {
01303 QMutexLocker locker(&_cache_lock);
01304 vector<const ProgramMapTable*> pmts;
01305
01306 pmt_cache_t::const_iterator it = _cached_pmts.begin();
01307 for (; it != _cached_pmts.end(); ++it)
01308 {
01309 ProgramMapTable* pmt = *it;
01310 IncrementRefCnt(pmt);
01311 pmts.push_back(pmt);
01312 }
01313
01314 return pmts;
01315 }
01316
01317 pmt_map_t MPEGStreamData::GetCachedPMTMap(void) const
01318 {
01319 QMutexLocker locker(&_cache_lock);
01320 pmt_map_t pmts;
01321
01322 pmt_cache_t::const_iterator it = _cached_pmts.begin();
01323 for (; it != _cached_pmts.end(); ++it)
01324 {
01325 ProgramMapTable* pmt = *it;
01326 IncrementRefCnt(pmt);
01327 pmts[pmt->ProgramNumber()].push_back(pmt);
01328 }
01329
01330 return pmts;
01331 }
01332
01333 void MPEGStreamData::ReturnCachedTable(const PSIPTable *psip) const
01334 {
01335 QMutexLocker locker(&_cache_lock);
01336
01337 int val = _cached_ref_cnt[psip] - 1;
01338 _cached_ref_cnt[psip] = val;
01339
01340
01341 if (val <= 0)
01342 {
01343 psip_refcnt_map_t::iterator it;
01344 it = _cached_slated_for_deletion.find(psip);
01345 if (it != _cached_slated_for_deletion.end())
01346 DeleteCachedTable((PSIPTable*)psip);
01347 }
01348 }
01349
01350 void MPEGStreamData::ReturnCachedPATTables(pat_vec_t &pats) const
01351 {
01352 for (pat_vec_t::iterator it = pats.begin(); it != pats.end(); ++it)
01353 ReturnCachedTable(*it);
01354 pats.clear();
01355 }
01356
01357 void MPEGStreamData::ReturnCachedPATTables(pat_map_t &pats) const
01358 {
01359 for (pat_map_t::iterator it = pats.begin(); it != pats.end(); ++it)
01360 ReturnCachedPATTables(*it);
01361 pats.clear();
01362 }
01363
01364 void MPEGStreamData::ReturnCachedPMTTables(pmt_vec_t &pmts) const
01365 {
01366 for (pmt_vec_t::iterator it = pmts.begin(); it != pmts.end(); ++it)
01367 ReturnCachedTable(*it);
01368 pmts.clear();
01369 }
01370
01371 void MPEGStreamData::ReturnCachedPMTTables(pmt_map_t &pmts) const
01372 {
01373 for (pmt_map_t::iterator it = pmts.begin(); it != pmts.end(); ++it)
01374 ReturnCachedPMTTables(*it);
01375 pmts.clear();
01376 }
01377
01378 void MPEGStreamData::IncrementRefCnt(const PSIPTable *psip) const
01379 {
01380 QMutexLocker locker(&_cache_lock);
01381 _cached_ref_cnt[psip] = _cached_ref_cnt[psip] + 1;
01382 }
01383
01384 void MPEGStreamData::DeleteCachedTable(PSIPTable *psip) const
01385 {
01386 if (!psip)
01387 return;
01388
01389 uint tid = psip->TableIDExtension();
01390
01391 QMutexLocker locker(&_cache_lock);
01392 if (_cached_ref_cnt[psip] > 0)
01393 {
01394 _cached_slated_for_deletion[psip] = 1;
01395 return;
01396 }
01397 else if (TableID::PAT == psip->TableID() &&
01398 (_cached_pats[(tid << 8) | psip->Section()] == psip))
01399 {
01400 _cached_pats[(tid << 8) | psip->Section()] = NULL;
01401 delete psip;
01402 }
01403 else if ((TableID::PMT == psip->TableID()) &&
01404 (_cached_pmts[(tid << 8) | psip->Section()] == psip))
01405 {
01406 _cached_pmts[(tid << 8) | psip->Section()] = NULL;
01407 delete psip;
01408 }
01409 else
01410 {
01411 _cached_slated_for_deletion[psip] = 2;
01412 return;
01413 }
01414 psip_refcnt_map_t::iterator it;
01415 it = _cached_slated_for_deletion.find(psip);
01416 if (it != _cached_slated_for_deletion.end())
01417 _cached_slated_for_deletion.erase(it);
01418 }
01419
01420 void MPEGStreamData::CachePAT(const ProgramAssociationTable *_pat)
01421 {
01422 ProgramAssociationTable *pat = new ProgramAssociationTable(*_pat);
01423 uint key = (_pat->TransportStreamID() << 8) | _pat->Section();
01424
01425 QMutexLocker locker(&_cache_lock);
01426
01427 pat_cache_t::iterator it = _cached_pats.find(key);
01428 if (it != _cached_pats.end())
01429 DeleteCachedTable(*it);
01430
01431 _cached_pats[key] = pat;
01432 }
01433
01434 void MPEGStreamData::CachePMT(const ProgramMapTable *_pmt)
01435 {
01436 ProgramMapTable *pmt = new ProgramMapTable(*_pmt);
01437 uint key = (_pmt->ProgramNumber() << 8) | _pmt->Section();
01438
01439 QMutexLocker locker(&_cache_lock);
01440
01441 pmt_cache_t::iterator it = _cached_pmts.find(key);
01442 if (it != _cached_pmts.end())
01443 DeleteCachedTable(*it);
01444
01445 _cached_pmts[key] = pmt;
01446 }
01447
01448 void MPEGStreamData::AddMPEGListener(MPEGStreamListener *val)
01449 {
01450 QMutexLocker locker(&_listener_lock);
01451
01452 mpeg_listener_vec_t::iterator it = _mpeg_listeners.begin();
01453 for (; it != _mpeg_listeners.end(); ++it)
01454 if (((void*)val) == ((void*)*it))
01455 return;
01456
01457 _mpeg_listeners.push_back(val);
01458 }
01459
01460 void MPEGStreamData::RemoveMPEGListener(MPEGStreamListener *val)
01461 {
01462 QMutexLocker locker(&_listener_lock);
01463
01464 mpeg_listener_vec_t::iterator it = _mpeg_listeners.begin();
01465 for (; it != _mpeg_listeners.end(); ++it)
01466 {
01467 if (((void*)val) == ((void*)*it))
01468 {
01469 _mpeg_listeners.erase(it);
01470 return;
01471 }
01472 }
01473 }
01474
01475 void MPEGStreamData::AddWritingListener(TSPacketListener *val)
01476 {
01477 QMutexLocker locker(&_listener_lock);
01478
01479 ts_listener_vec_t::iterator it = _ts_writing_listeners.begin();
01480 for (; it != _ts_writing_listeners.end(); ++it)
01481 if (((void*)val) == ((void*)*it))
01482 return;
01483
01484 _ts_writing_listeners.push_back(val);
01485 }
01486
01487 void MPEGStreamData::RemoveWritingListener(TSPacketListener *val)
01488 {
01489 QMutexLocker locker(&_listener_lock);
01490
01491 ts_listener_vec_t::iterator it = _ts_writing_listeners.begin();
01492 for (; it != _ts_writing_listeners.end(); ++it)
01493 {
01494 if (((void*)val) == ((void*)*it))
01495 {
01496 _ts_writing_listeners.erase(it);
01497 return;
01498 }
01499 }
01500 }
01501
01502 void MPEGStreamData::AddAVListener(TSPacketListenerAV *val)
01503 {
01504 QMutexLocker locker(&_listener_lock);
01505
01506 ts_av_listener_vec_t::iterator it = _ts_av_listeners.begin();
01507 for (; it != _ts_av_listeners.end(); ++it)
01508 if (((void*)val) == ((void*)*it))
01509 return;
01510
01511 _ts_av_listeners.push_back(val);
01512 }
01513
01514 void MPEGStreamData::RemoveAVListener(TSPacketListenerAV *val)
01515 {
01516 QMutexLocker locker(&_listener_lock);
01517
01518 ts_av_listener_vec_t::iterator it = _ts_av_listeners.begin();
01519 for (; it != _ts_av_listeners.end(); ++it)
01520 {
01521 if (((void*)val) == ((void*)*it))
01522 {
01523 _ts_av_listeners.erase(it);
01524 return;
01525 }
01526 }
01527 }
01528
01529 void MPEGStreamData::AddMPEGSPListener(MPEGSingleProgramStreamListener *val)
01530 {
01531 QMutexLocker locker(&_listener_lock);
01532
01533 mpeg_sp_listener_vec_t::iterator it = _mpeg_sp_listeners.begin();
01534 for (; it != _mpeg_sp_listeners.end(); ++it)
01535 if (((void*)val) == ((void*)*it))
01536 return;
01537
01538 _mpeg_sp_listeners.push_back(val);
01539 }
01540
01541 void MPEGStreamData::RemoveMPEGSPListener(MPEGSingleProgramStreamListener *val)
01542 {
01543 QMutexLocker locker(&_listener_lock);
01544
01545 mpeg_sp_listener_vec_t::iterator it = _mpeg_sp_listeners.begin();
01546 for (; it != _mpeg_sp_listeners.end(); ++it)
01547 {
01548 if (((void*)val) == ((void*)*it))
01549 {
01550 _mpeg_sp_listeners.erase(it);
01551 return;
01552 }
01553 }
01554 }
01555
01556 void MPEGStreamData::AddEncryptionTestPID(uint pnum, uint pid, bool isvideo)
01557 {
01558 QMutexLocker locker(&_encryption_lock);
01559
01560
01561
01562
01563 AddListeningPID(pid);
01564
01565 _encryption_pid_to_info[pid] = CryptInfo((isvideo) ? 10000 : 500, 8);
01566
01567 _encryption_pid_to_pnums[pid].push_back(pnum);
01568 _encryption_pnum_to_pids[pnum].push_back(pid);
01569 _encryption_pnum_to_status[pnum] = kEncUnknown;
01570 }
01571
01572 void MPEGStreamData::RemoveEncryptionTestPIDs(uint pnum)
01573 {
01574 QMutexLocker locker(&_encryption_lock);
01575
01576
01577
01578
01579
01580 QMap<uint, uint_vec_t>::iterator list;
01581 uint_vec_t::iterator it;
01582
01583 uint_vec_t pids = _encryption_pnum_to_pids[pnum];
01584 for (uint i = 0; i < pids.size(); i++)
01585 {
01586 uint pid = pids[i];
01587
01588
01589
01590
01591 RemoveListeningPID(pid);
01592
01593 list = _encryption_pid_to_pnums.find(pid);
01594 if (list != _encryption_pid_to_pnums.end())
01595 {
01596 it = find((*list).begin(), (*list).end(), pnum);
01597
01598 if (it != (*list).end())
01599 (*list).erase(it);
01600
01601 if ((*list).empty())
01602 {
01603 _encryption_pid_to_pnums.erase(pid);
01604 _encryption_pid_to_info.erase(pid);
01605 }
01606 }
01607 }
01608
01609 _encryption_pnum_to_pids.erase(pnum);
01610 }
01611
01612 bool MPEGStreamData::IsEncryptionTestPID(uint pid) const
01613 {
01614 QMutexLocker locker(&_encryption_lock);
01615
01616 QMap<uint, CryptInfo>::const_iterator it =
01617 _encryption_pid_to_info.find(pid);
01618
01619 return it != _encryption_pid_to_info.end();
01620 }
01621
01622 void MPEGStreamData::TestDecryption(const ProgramMapTable *pmt)
01623 {
01624 QMutexLocker locker(&_encryption_lock);
01625
01626
01627
01628
01629
01630 bool encrypted = pmt->IsProgramEncrypted();
01631 for (uint i = 0; i < pmt->StreamCount(); i++)
01632 {
01633 if (!encrypted && !pmt->IsStreamEncrypted(i))
01634 continue;
01635
01636 bool is_vid = pmt->IsVideo(i, _sistandard);
01637 bool is_aud = pmt->IsAudio(i, _sistandard);
01638 if (is_vid || is_aud)
01639 {
01640 AddEncryptionTestPID(
01641 pmt->ProgramNumber(), pmt->StreamPID(i), is_vid);
01642 }
01643 }
01644 }
01645
01646 void MPEGStreamData::ResetDecryptionMonitoringState(void)
01647 {
01648 QMutexLocker locker(&_encryption_lock);
01649
01650 _encryption_pid_to_info.clear();
01651 _encryption_pid_to_pnums.clear();
01652 _encryption_pnum_to_pids.clear();
01653 }
01654
01655 bool MPEGStreamData::IsProgramDecrypted(uint pnum) const
01656 {
01657 QMutexLocker locker(&_encryption_lock);
01658 return _encryption_pnum_to_status[pnum] == kEncDecrypted;
01659 }
01660
01661 bool MPEGStreamData::IsProgramEncrypted(uint pnum) const
01662 {
01663 QMutexLocker locker(&_encryption_lock);
01664 return _encryption_pnum_to_status[pnum] == kEncEncrypted;
01665 }
01666
01667 static QString toString(CryptStatus status)
01668 {
01669 if (kEncDecrypted == status)
01670 return "Decrypted";
01671 else if (kEncEncrypted == status)
01672 return "Encrypted";
01673 else
01674 return "Unknown";
01675 }
01676
01680 void MPEGStreamData::ProcessEncryptedPacket(const TSPacket& tspacket)
01681 {
01682 QMutexLocker locker(&_encryption_lock);
01683
01684 const uint pid = tspacket.PID();
01685 CryptInfo &info = _encryption_pid_to_info[pid];
01686
01687 CryptStatus status = kEncUnknown;
01688
01689 if (tspacket.ScramplingControl())
01690 {
01691 info.decrypted_packets = 0;
01692
01693
01694
01695 if (++info.encrypted_packets >= info.encrypted_min)
01696 status = kEncEncrypted;
01697 }
01698 else
01699 {
01700 info.encrypted_packets = 0;
01701 if (++info.decrypted_packets > info.decrypted_min)
01702 status = kEncDecrypted;
01703 }
01704
01705 if (status == info.status)
01706 return;
01707
01708 info.status = status;
01709
01710 VERBOSE(status != kEncDecrypted ? VB_IMPORTANT : VB_RECORD,
01711 QString("PID 0x%1 status: %2")
01712 .arg(pid,0,16).arg(toString(status)));
01713
01714 uint_vec_t pnum_del_list;
01715 const uint_vec_t &pnums = _encryption_pid_to_pnums[pid];
01716 for (uint i = 0; i < pnums.size(); i++)
01717 {
01718 CryptStatus status = _encryption_pnum_to_status[pnums[i]];
01719
01720 const uint_vec_t &pids = _encryption_pnum_to_pids[pnums[i]];
01721 if (!pids.empty())
01722 {
01723 uint enc_cnt[3] = { 0, 0, 0 };
01724 for (uint j = 0; j < pids.size(); j++)
01725 {
01726 CryptStatus stat = _encryption_pid_to_info[pids[j]].status;
01727 enc_cnt[stat]++;
01728
01729
01730
01731
01732
01733 }
01734 status = kEncUnknown;
01735
01736 if (enc_cnt[kEncEncrypted])
01737 status = kEncEncrypted;
01738 else if (enc_cnt[kEncDecrypted] >= min((size_t) 2, pids.size()))
01739 status = kEncDecrypted;
01740 }
01741
01742 if (status == _encryption_pnum_to_status[pnums[i]])
01743 continue;
01744
01745 VERBOSE(VB_RECORD, QString("Program %1 status: %2")
01746 .arg(pnums[i]).arg(toString(status)));
01747
01748 _encryption_pnum_to_status[pnums[i]] = status;
01749
01750 bool encrypted = kEncUnknown == status || kEncEncrypted == status;
01751 _listener_lock.lock();
01752 for (uint j = 0; j < _mpeg_listeners.size(); j++)
01753 _mpeg_listeners[j]->HandleEncryptionStatus(pnums[i], encrypted);
01754 _listener_lock.unlock();
01755
01756 if (kEncDecrypted == status)
01757 pnum_del_list.push_back(pnums[i]);
01758 }
01759
01760 for (uint i = 0; i < pnum_del_list.size(); i++)
01761 RemoveEncryptionTestPIDs(pnums[i]);
01762 }