MythTV  master
mpegstreamdata.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // Copyright (c) 2003-2004, Daniel Thor Kristjansson
3 
4 #include <algorithm> // for find & max
5 using namespace std;
6 
7 // POSIX headers
8 #include <sys/time.h> // for gettimeofday
9 
10 // Qt headers
11 #include <QString>
12 
13 // MythTV headers
14 #include "mpegstreamdata.h"
15 #include "mpegtables.h"
16 #include "mpegtables.h"
17 
18 #include "atscstreamdata.h"
19 #include "atsctables.h"
20 
21 //#define DEBUG_MPEG_RADIO // uncomment to strip video streams from TS stream
22 #define LOC QString("MPEGStream[%1](0x%2): ").arg(m_cardId).arg((intptr_t)this, QT_POINTER_SIZE, 16, QChar('0'))
23 
40 MPEGStreamData::MPEGStreamData(int desiredProgram, int cardnum,
41  bool cacheTables)
42  : m_cardId(cardnum),
43  m_cacheTables(cacheTables),
44  // Single program stuff
45  m_desiredProgram(desiredProgram)
46 {
49 }
50 
52 {
54  SetPATSingleProgram(nullptr);
55  SetPMTSingleProgram(nullptr);
56 
57  // Delete any cached tables that haven't been returned
58  for (auto it = m_cachedSlatedForDeletion.cbegin();
59  it != m_cachedSlatedForDeletion.cend(); ++it)
60  delete it.key();
61 
62  QMutexLocker locker(&m_listenerLock);
63  m_mpegListeners.clear();
64  m_mpegSpListeners.clear();
65 }
66 
68 {
69  bool reset = true;
70  uint pid = 0;
71  const ProgramAssociationTable* pat = nullptr;
72  pat_vec_t pats = GetCachedPATs();
73 
74  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetDesiredProgram(%2)").arg(p));
75 
76  for (uint i = (p) ? 0 : pats.size(); i < pats.size() && !pid; i++)
77  {
78  pat = pats[i];
79  pid = pats[i]->FindPID(p);
80  }
81 
82  if (pid)
83  {
84  reset = false;
86  ProcessPAT(pat);
87  pmt_vec_t pmts = GetCachedPMTs();
88  for (auto & pmt : pmts)
89  {
90  if (pmt->ProgramNumber() == (uint)p)
91  ProcessPMT(pmt);
92  }
94  }
95 
97 
98  if (reset)
99  Reset(p);
100 }
101 
102 void MPEGStreamData::SetRecordingType(const QString &recording_type)
103 {
104  m_recordingType = recording_type;
105  uint neededAudio = (m_recordingType == "audio") ? 1 : 0;
107  SetAudioStreamsRequired(neededAudio);
108 }
109 
111 {
112  QMutexLocker locker(&m_listenerLock);
113  m_eitHelper = eit_helper;
114 }
115 
117 {
118  QMutexLocker locker(&m_listenerLock);
119  m_eitRate = rate;
120 }
121 
122 void MPEGStreamData::Reset(int desiredProgram)
123 {
124  m_desiredProgram = desiredProgram;
125  m_recordingType = "all";
126  m_stripPmtDescriptors = false;
127  m_normalizeStreamType = true;
128 
129  m_invalidPatSeen = false;
130 
131  SetPATSingleProgram(nullptr);
132  SetPMTSingleProgram(nullptr);
133 
135  for (auto it = old.begin(); it != old.end(); ++it)
136  DeletePartialPSIP(it.key());
137  m_partialPsipPacketCache.clear();
138 
139  m_pidsListening.clear();
140  m_pidsNotListening.clear();
141  m_pidsWriting.clear();
142  m_pidsAudio.clear();
143 
145 
146  m_patStatus.clear();
147 
148  m_pmtStatus.clear();
149 
150  {
151  QMutexLocker locker(&m_cacheLock);
152 
153  for (const auto & cached : qAsConst(m_cachedPats))
154  DeleteCachedTable(cached);
155  m_cachedPats.clear();
156 
157  for (const auto & cached : qAsConst(m_cachedPmts))
158  DeleteCachedTable(cached);
159  m_cachedPmts.clear();
160 
161  for (const auto & cached : qAsConst(m_cachedCats))
162  DeleteCachedTable(cached);
163  m_cachedCats.clear();
164  }
165 
167 
170 }
171 
173 {
174  pid_psip_map_t::iterator it = m_partialPsipPacketCache.find(pid);
175  if (it != m_partialPsipPacketCache.end())
176  {
177  PSIPTable *pkt = *it;
178  m_partialPsipPacketCache.erase(it);
179  delete pkt;
180  }
181 }
182 
206  bool &moreTablePackets)
207 {
208  bool broken = true;
209  moreTablePackets = true;
210 
211  PSIPTable* partial = GetPartialPSIP(tspacket->PID());
212  if (partial && partial->AddTSPacket(tspacket, broken) && !broken)
213  {
214  // check if it's safe to read pespacket's Length()
215  if ((partial->PSIOffset() + 1 + 3) > partial->TSSizeInBuffer())
216  {
217  LOG(VB_RECORD, LOG_ERR, LOC +
218  QString("Discarding broken PSIP packet. Packet's length at "
219  "position %1 isn't in the buffer of %2 bytes.")
220  .arg(partial->PSIOffset() + 1 + 3)
221  .arg(partial->TSSizeInBuffer()));
222  DeletePartialPSIP(tspacket->PID());
223  return nullptr;
224  }
225 
226  // Discard broken packets
227  bool buggy = m_haveCrcBug &&
228  ((TableID::PMT == partial->StreamID()) ||
229  (TableID::PAT == partial->StreamID()));
230  if (!buggy && !partial->IsGood())
231  {
232  LOG(VB_SIPARSER, LOG_ERR, LOC + "Discarding broken PSIP packet");
233  DeletePartialPSIP(tspacket->PID());
234  return nullptr;
235  }
236 
237  auto* psip = new PSIPTable(*partial);
238 
239  // Advance to the next packet
240  // pesdata starts only at PSIOffset()+1
241  uint packetStart = partial->PSIOffset() + 1 + psip->SectionLength();
242  if (packetStart < partial->TSSizeInBuffer())
243  {
244  if (partial->pesdata()[psip->SectionLength()] != 0xff)
245  {
246 #if 0 /* This doesn't work, you can't start PSIP packet like this
247  because the PayloadStart() flag won't be set in this TSPacket
248  -- dtk May 4th, 2007
249  */
250 
251  // If the next section starts in the new tspacket
252  // create a new partial packet to prevent overflow
253  if ((partial->TSSizeInBuffer() > TSPacket::kSize) &&
254  (packetStart >
256  {
257  // Saving will handle deleting the old one
258  SavePartialPSIP(tspacket->PID(),
259  new PSIPTable(*tspacket));
260  }
261  else
262 #endif
263  {
264  partial->SetPSIOffset(partial->PSIOffset() +
265  psip->SectionLength());
266  }
267  return psip;
268  }
269  }
270  // discard incomplete packets
271  if (packetStart > partial->TSSizeInBuffer())
272  {
273  LOG(VB_RECORD, LOG_ERR, LOC +
274  QString("Discarding broken PSIP packet. ") +
275  QString("Packet with %1 bytes doesn't fit "
276  "into a buffer of %2 bytes.")
277  .arg(packetStart).arg(partial->TSSizeInBuffer()));
278  delete psip;
279  psip = nullptr;
280  }
281 
282  moreTablePackets = false;
283  DeletePartialPSIP(tspacket->PID());
284  return psip;
285  }
286  if (partial)
287  {
288  if (broken)
289  DeletePartialPSIP(tspacket->PID());
290 
291  moreTablePackets = false;
292  return nullptr; // partial packet is not yet complete.
293  }
294 
295  if (!tspacket->PayloadStart())
296  {
297  // We didn't see this PSIP packet's start, so this must be the
298  // tail end of something we missed. Ignore it.
299  moreTablePackets = false;
300  return nullptr;
301  }
302 
303  // table_id (8 bits) and section_length(12), syntax(1), priv(1), res(2)
304  // pointer_field (+8 bits), since payload start is true if we are here.
305  const unsigned int extra_offset = 4;
306 
307  const unsigned int offset = tspacket->AFCOffset() + tspacket->StartOfFieldPointer();
308  if (offset + extra_offset > TSPacket::kSize)
309  {
310  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error: "
311  "AFCOffset(%1)+StartOfFieldPointer(%2)>184, "
312  "pes length & current cannot be queried")
313  .arg(tspacket->AFCOffset()).arg(tspacket->StartOfFieldPointer()));
314  return nullptr;
315  }
316 
317  const unsigned char* pesdata = tspacket->data() + offset;
318  const unsigned int pes_length = (pesdata[2] & 0x0f) << 8 | pesdata[3];
319  if ((pes_length + offset + extra_offset) > TSPacket::kSize)
320  {
321  SavePartialPSIP(tspacket->PID(), new PSIPTable(*tspacket));
322  moreTablePackets = false;
323  return nullptr;
324  }
325 
326  auto *psip = new PSIPTable(*tspacket); // must be complete packet
327 
328  // There might be another section after this one in the
329  // current packet. We need room before the end of the
330  // packet, and it must not be packet stuffing.
331  if ((offset + psip->SectionLength() < TSPacket::kSize) &&
332  (pesdata[psip->SectionLength() + 1] != 0xff))
333  {
334  // This isn't stuffing, so we need to put this
335  // on as a partial packet.
336  auto *pesp = new PSIPTable(*tspacket);
337  pesp->SetPSIOffset(offset + psip->SectionLength());
338  SavePartialPSIP(tspacket->PID(), pesp);
339  return psip;
340  }
341 
342  moreTablePackets = false;
343  return psip;
344 }
345 
347  const ProgramAssociationTable& pat)
348 {
349  LOG(VB_RECORD, LOG_DEBUG, LOC + "CreatePATSingleProgram()");
350  LOG(VB_RECORD, LOG_DEBUG, LOC + "PAT in input stream");
351  LOG(VB_RECORD, LOG_DEBUG, LOC + pat.toString());
352  if (m_desiredProgram < 0)
353  {
354  LOG(VB_RECORD, LOG_ERR, LOC + "Desired program not set yet");
355  return false;
356  }
358  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("desired_program(%1) pid(0x%2)").
360 
362  {
365  {
366  LOG(VB_GENERAL, LOG_ERR, LOC + "No program found in PAT. "
367  "This recording will not play in MythTV.");
368  }
369  LOG(VB_GENERAL, LOG_ERR, LOC +
370  QString("Desired program #%1 not found in PAT."
371  "\n\t\t\tCannot create single program PAT.")
373  SetPATSingleProgram(nullptr);
374  return false;
375  }
376 
378 
379  vector<uint> pnums;
380  vector<uint> pids;
381 
382  pnums.push_back(1);
383  pids.push_back(m_pidPmtSingleProgram);
384 
385  uint tsid = pat.TableIDExtension();
386  uint ver = pat.Version();
388  ProgramAssociationTable::Create(tsid, ver, pnums, pids);
389 
390  if (!pat2)
391  {
392  LOG(VB_GENERAL, LOG_ERR, LOC +
393  "MPEGStreamData::CreatePATSingleProgram: "
394  "Failed to create Program Association Table.");
395  return false;
396  }
397 
399 
400  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("pmt_pid(0x%1)")
401  .arg(m_pidPmtSingleProgram, 0, 16));
402  LOG(VB_RECORD, LOG_DEBUG, LOC + "PAT for output stream");
403  LOG(VB_RECORD, LOG_DEBUG, LOC + pat2->toString());
404 
405  SetPATSingleProgram(pat2);
406 
407  return true;
408 
409 }
410 
412  const cvct_vec_t &cvct,
413  uint pnum)
414 {
415  desc_list_t desc;
416 
417  vector<const VirtualChannelTable*> vct;
418 
419  for (const auto *i : tvct)
420  vct.push_back(i);
421 
422  for (const auto *i : cvct)
423  vct.push_back(i);
424 
425  for (size_t i = 0; i < tvct.size(); i++)
426  {
427  for (uint j = 0; j < vct[i]->ChannelCount(); j++)
428  {
429  if (vct[i]->ProgramNumber(j) == pnum)
430  {
432  vct[i]->Descriptors(j), vct[i]->DescriptorsLength(j),
434 
435  if (!ldesc.empty())
436  desc.insert(desc.end(), ldesc.begin(), ldesc.end());
437  }
438  }
439 
440  if (0 != vct[i]->GlobalDescriptorsLength())
441  {
443  vct[i]->GlobalDescriptors(),
444  vct[i]->GlobalDescriptorsLength(),
446 
447  if (!vdesc.empty())
448  desc.insert(desc.end(), vdesc.begin(), vdesc.end());
449  }
450  }
451 
452  return desc;
453 }
454 
456 {
457  LOG(VB_RECORD, LOG_DEBUG, LOC + "CreatePMTSingleProgram()");
458  LOG(VB_RECORD, LOG_DEBUG, LOC + "PMT in input stream");
459  LOG(VB_RECORD, LOG_DEBUG, LOC + pmt.toString());
460 
461  if (!PATSingleProgram())
462  {
463  LOG(VB_RECORD, LOG_ERR, LOC + "no PAT yet...");
464  return false; // no way to properly rewrite pids without PAT
465  }
466  pmt.Parse();
467 
468  uint programNumber = 1; // MPEG Program Number
469 
470  ATSCStreamData *sd = nullptr;
471  tvct_vec_t tvct;
472  cvct_vec_t cvct;
473 
474  desc_list_t gdesc;
475 
477  {
479  pmt.ProgramInfo(), pmt.ProgramInfoLength(),
481 
482  // If there is no caption descriptor in PMT, copy any caption
483  // descriptor found in VCT to global descriptors...
484  sd = dynamic_cast<ATSCStreamData*>(this);
486  {
487  tvct = sd->GetCachedTVCTs();
488  cvct = sd->GetCachedCVCTs();
489 
491  tvct, cvct, pmt.ProgramNumber());
492 
493  if (!vdesc.empty())
494  gdesc.insert(gdesc.end(), vdesc.begin(), vdesc.end());
495  }
496  }
497 
498  vector<uint> pids;
499  vector<uint> types;
500  vector<desc_list_t> pdesc;
501 
502  uint video_cnt = 0;
503  uint audio_cnt = 0;
504 
505  vector<uint> videoPIDs;
506  vector<uint> audioPIDs;
507  vector<uint> dataPIDs;
508 
509  for (uint i = 0; i < pmt.StreamCount(); i++)
510  {
511  uint pid = pmt.StreamPID(i);
512 
514  pmt.StreamInfo(i), pmt.StreamInfoLength(i),
516 
518  pmt.StreamType(i), desc, m_siStandard);
519 
520  bool is_video = StreamID::IsVideo(type);
521  bool is_audio = StreamID::IsAudio(type);
522 
523  if (is_audio)
524  {
525  audio_cnt++;
526  audioPIDs.push_back(pid);
527  }
528  else if (m_recordingType == "audio" )
529  {
530  // If not an audio PID but we only want audio,
531  // ignore this PID.
532  continue;
533  }
534 
535 #ifdef DEBUG_MPEG_RADIO
536  if (is_video)
537  continue;
538 #endif // DEBUG_MPEG_RADIO
539 
540  if (is_video)
541  {
542  video_cnt++;
543  videoPIDs.push_back(pid);
544  }
545 
547  desc.clear();
548 
549  // Filter out streams not used for basic television
550  if (m_recordingType == "tv" && !is_audio && !is_video &&
553  pid != pmt.PCRPID()) // We must not strip the PCR!
554  {
555  continue;
556  }
557 
558  if (!is_audio && !is_video) //NOTE: Anything which isn't audio or video is data
559  dataPIDs.push_back(pid);
560 
561  pdesc.push_back(desc);
562  pids.push_back(pid);
563  types.push_back(type);
564  }
565 
566  if (video_cnt < m_pmtSingleProgramNumVideo)
567  {
568  LOG(VB_RECORD, LOG_ERR, LOC +
569  QString("Only %1 video streams seen in PMT, but %2 are required.")
570  .arg(video_cnt).arg(m_pmtSingleProgramNumVideo));
571  return false;
572  }
573 
574  if (audioPIDs.size() < m_pmtSingleProgramNumAudio)
575  {
576  LOG(VB_RECORD, LOG_ERR, LOC +
577  QString("Only %1 audio streams seen in PMT, but %2 are required.")
578  .arg(audioPIDs.size()).arg(m_pmtSingleProgramNumAudio));
579  return false;
580  }
581 
583  pmt.ProgramInfo(), pmt.ProgramInfoLength(),
585  for (auto & i : cdesc)
586  {
588  if (cad.IsValid())
589  AddListeningPID(cad.PID());
590  }
591 
592  m_pidsAudio.clear();
593  for (uint pid : audioPIDs)
594  AddAudioPID(pid);
595 
596  m_pidsWriting.clear();
597  m_pidVideoSingleProgram = !videoPIDs.empty() ? videoPIDs[0] : 0xffffffff;
598  for (size_t i = 1; i < videoPIDs.size(); i++)
599  AddWritingPID(videoPIDs[i]);
600 
601  for (uint pid : dataPIDs)
602  AddWritingPID(pid);
603 
604  // Timebase
605  int pcrpidIndex = pmt.FindPID(pmt.PCRPID());
606  if (pcrpidIndex < 0)
607  {
608  // the timecode reference stream is not in the PMT,
609  // add stream to misc record streams
610  AddWritingPID(pmt.PCRPID());
611  }
612 
613  // Create the PMT
615  programNumber, m_pidPmtSingleProgram, pmt.PCRPID(),
616  pmt.Version(), gdesc, pids, types, pdesc);
617 
618  // Return any TVCT & CVCT tables, once we've copied any descriptors.
619  if (sd)
620  {
621  sd->ReturnCachedTVCTTables(tvct);
622  sd->ReturnCachedCVCTTables(cvct);
623  }
624 
625  // Set Continuity Header
626  uint cc_cnt = pmt.tsheader()->ContinuityCounter();
627  pmt2->tsheader()->SetContinuityCounter(cc_cnt);
628  SetPMTSingleProgram(pmt2);
629 
630  LOG(VB_RECORD, LOG_DEBUG, LOC + "PMT for output stream");
631  LOG(VB_RECORD, LOG_DEBUG, LOC + pmt2->toString());
632 
633  return true;
634 }
635 
639 bool MPEGStreamData::IsRedundant(uint pid, const PSIPTable &psip) const
640 {
641  (void) pid;
642  const int table_id = psip.TableID();
643  const int version = psip.Version();
644 
645  if (TableID::PAT == table_id)
646  {
647  return m_patStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
648  }
649 
650  if (TableID::CAT == table_id)
651  {
652  return m_catStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
653  }
654 
655  if (TableID::PMT == table_id)
656  {
657  return m_pmtStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
658  }
659 
660  return false;
661 }
662 
667 {
668  if (MPEGStreamData::IsRedundant(pid, psip))
669  return true;
670 
671  const int version = psip.Version();
672  // If we get this far decode table
673  switch (psip.TableID())
674  {
675  case TableID::PAT:
676  {
677  uint tsid = psip.TableIDExtension();
678  m_patStatus.SetSectionSeen(tsid, version, psip.Section(), psip.LastSection());
679 
680  ProgramAssociationTable pat(psip);
681 
682  if (m_cacheTables)
683  CachePAT(&pat);
684 
685  ProcessPAT(&pat);
686 
687  return true;
688  }
689  case TableID::CAT:
690  {
691  uint tsid = psip.TableIDExtension();
692  m_catStatus.SetSectionSeen(tsid, version, psip.Section(), psip.LastSection());
693 
695 
696  if (m_cacheTables)
697  CacheCAT(&cat);
698 
699  ProcessCAT(&cat);
700 
701  return true;
702  }
703  case TableID::PMT:
704  {
705  uint prog_num = psip.TableIDExtension();
706  m_pmtStatus.SetSectionSeen(prog_num, version, psip.Section(), psip.LastSection());
707 
708  ProgramMapTable pmt(psip);
709 
710  if (m_cacheTables)
711  CachePMT(&pmt);
712 
713  ProcessPMT(&pmt);
714 
715  return true;
716  }
717  case TableID::SITscte:
718  {
719  SpliceInformationTable sit(psip);
720  sit.setSCTEPID(pid);
721 
722  m_listenerLock.lock();
723  for (auto & listener : m_mpegListeners)
724  listener->HandleSplice(&sit);
725  m_listenerLock.unlock();
726 
727  return true;
728  }
729  }
730  return false;
731 }
732 
734 {
735  bool foundProgram = pat->FindPID(m_desiredProgram) != 0U;
736 
737  m_listenerLock.lock();
738  for (auto & listener : m_mpegListeners)
739  listener->HandlePAT(pat);
740  m_listenerLock.unlock();
741 
742  if (m_desiredProgram < 0)
743  return;
744 
745  bool send_single_program = false;
746  if (!m_invalidPatSeen && !foundProgram)
747  {
748  m_invalidPatSeen = true;
749  m_invalidPatWarning = false;
751  LOG(VB_RECORD, LOG_WARNING, LOC +
752  "ProcessPAT: PAT is missing program, setting timeout");
753  }
754  else if (m_invalidPatSeen && !foundProgram &&
756  {
757  m_invalidPatWarning = true; // only emit one warning...
758  // After 400ms emit error if we haven't found correct PAT.
759  LOG(VB_GENERAL, LOG_ERR, LOC + "ProcessPAT: Program not found in PAT. "
760  "Rescan your transports.");
761 
762  send_single_program = CreatePATSingleProgram(*pat);
763  }
764  else if (foundProgram)
765  {
766  if (m_invalidPatSeen)
767  LOG(VB_RECORD, LOG_INFO, LOC +
768  "ProcessPAT: Good PAT seen after a bad PAT");
769 
770  m_invalidPatSeen = false;
771 
772  send_single_program = CreatePATSingleProgram(*pat);
773  }
774 
775  if (send_single_program)
776  {
777  QMutexLocker locker(&m_listenerLock);
779  for (auto & listener : m_mpegSpListeners)
780  listener->HandleSingleProgramPAT(pat_sp, false);
781  }
782 }
783 
785 {
786  m_listenerLock.lock();
787  for (auto & listener : m_mpegListeners)
788  listener->HandleCAT(cat);
789  m_listenerLock.unlock();
790 
792  cat->Descriptors(), cat->DescriptorsLength(),
794  for (auto & i : cdesc)
795  {
797  if (cad.IsValid())
798  AddListeningPID(cad.PID());
799  }
800 }
801 
803 {
804  m_listenerLock.lock();
805  for (auto & listener : m_mpegListeners)
806  listener->HandlePMT(pmt->ProgramNumber(), pmt);
807  m_listenerLock.unlock();
808 
809  bool desired = pmt->ProgramNumber() == (uint) m_desiredProgram;
810  if (desired && CreatePMTSingleProgram(*pmt))
811  {
812  QMutexLocker locker(&m_listenerLock);
813  ProgramMapTable *pmt_sp = PMTSingleProgram();
814  for (auto & listener : m_mpegSpListeners)
815  listener->HandleSingleProgramPMT(pmt_sp, false);
816  }
817 }
818 
819 double MPEGStreamData::TimeOffset(void) const
820 {
821  QMutexLocker locker(&m_siTimeLock);
822  if (!m_siTimeOffsetCnt)
823  return 0.0;
824 
825  double avg_offset = 0.0;
826  double mult = 1.0 / m_siTimeOffsetCnt;
827  for (uint i = 0; i < m_siTimeOffsetCnt; i++)
828  avg_offset += m_siTimeOffsets[i] * mult;
829 
830  return avg_offset;
831 }
832 
833 void MPEGStreamData::UpdateTimeOffset(uint64_t _si_utc_time)
834 {
835  struct timeval tm {};
836  if (gettimeofday(&tm, nullptr) != 0)
837  return;
838 
839  double utc_time = tm.tv_sec + (tm.tv_usec * 0.000001);
840  double si_time = _si_utc_time;
841 
842  QMutexLocker locker(&m_siTimeLock);
843  m_siTimeOffsets[m_siTimeOffsetIndx] = si_time - utc_time;
844 
847 
849 
850 }
851 
852 #define DONE_WITH_PSIP_PACKET() { delete psip; \
853  if (morePSIPTables) goto HAS_ANOTHER_PSIP; else return; }
854 
859 {
860  bool morePSIPTables = false;
861  HAS_ANOTHER_PSIP:
862  // Assemble PSIP
863  PSIPTable *psip = AssemblePSIP(tspacket, morePSIPTables);
864  if (!psip)
865  return;
866 
867  // drop stuffing packets
868  if ((TableID::ST == psip->TableID()) ||
869  (TableID::STUFFING == psip->TableID()))
870  {
871  LOG(VB_RECORD, LOG_DEBUG, LOC + "Dropping Stuffing table");
873  }
874 
875  // Don't do validation on tables without CRC
876  if (!psip->HasCRC())
877  {
878  HandleTables(tspacket->PID(), *psip);
880  }
881 
882  // Validate PSIP
883  // but don't validate PMT/PAT if our driver has the PMT/PAT CRC bug.
884  bool buggy = m_haveCrcBug &&
885  ((TableID::PMT == psip->TableID()) ||
886  (TableID::PAT == psip->TableID()));
887  if (!buggy && !psip->IsGood())
888  {
889  LOG(VB_RECORD, LOG_ERR, LOC +
890  QString("PSIP packet failed CRC check. pid(0x%1) type(0x%2)")
891  .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16));
893  }
894 
895  if (TableID::MGT <= psip->TableID() && psip->TableID() <= TableID::STT &&
896  !psip->IsCurrent())
897  { // we don't cache the next table, for now
898  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Table not current 0x%1")
899  .arg(psip->TableID(),2,16,QChar('0')));
901  }
902 
903  if (tspacket->Scrambled())
904  { // scrambled! ATSC, DVB require tables not to be scrambled
905  LOG(VB_RECORD, LOG_ERR, LOC +
906  "PSIP packet is scrambled, not ATSC/DVB compiant");
908  }
909 
910  if (!psip->VerifyPSIP(!m_haveCrcBug))
911  {
912  LOG(VB_RECORD, LOG_ERR, LOC + QString("PSIP table 0x%1 is invalid")
913  .arg(psip->TableID(),2,16,QChar('0')));
915  }
916 
917  // Don't decode redundant packets,
918  // but if it is a desired PAT or PMT emit a "heartbeat" signal.
919  if (MPEGStreamData::IsRedundant(tspacket->PID(), *psip))
920  {
921  if (TableID::PAT == psip->TableID())
922  {
923  QMutexLocker locker(&m_listenerLock);
925  for (auto & listener : m_mpegSpListeners)
926  listener->HandleSingleProgramPAT(pat_sp, false);
927  }
928  if (TableID::PMT == psip->TableID() &&
929  tspacket->PID() == m_pidPmtSingleProgram)
930  {
931  QMutexLocker locker(&m_listenerLock);
932  ProgramMapTable *pmt_sp = PMTSingleProgram();
933  for (auto & listener : m_mpegSpListeners)
934  listener->HandleSingleProgramPMT(pmt_sp, false);
935  }
936  DONE_WITH_PSIP_PACKET(); // already parsed this table, toss it.
937  }
938 
939  HandleTables(tspacket->PID(), *psip);
940 
942 }
943 #undef DONE_WITH_PSIP_PACKET
944 
945 int MPEGStreamData::ProcessData(const unsigned char *buffer, int len)
946 {
947  int pos = 0;
948  bool resync = false;
949 
950  if (!m_psListeners.empty())
951  {
952 
953  for (auto & listener : m_psListeners)
954  listener->FindPSKeyFrames(buffer, len);
955 
956  return 0;
957  }
958 
959  while (pos + int(TSPacket::kSize) <= len)
960  { // while we have a whole packet left...
961  if (buffer[pos] != SYNC_BYTE || resync)
962  {
963  int newpos = ResyncStream(buffer, pos+1, len);
964  LOG(VB_RECORD, LOG_DEBUG, LOC +
965  QString("Resyncing @ %1+1 w/len %2 -> %3")
966  .arg(pos).arg(len).arg(newpos));
967  if (newpos == -1)
968  return len - pos;
969  if (newpos == -2)
970  return TSPacket::kSize;
971  pos = newpos;
972  }
973 
974  const auto *pkt = reinterpret_cast<const TSPacket*>(&buffer[pos]);
975  pos += TSPacket::kSize; // Advance to next TS packet
976  resync = false;
977  if (!ProcessTSPacket(*pkt))
978  {
979  if (pos + int(TSPacket::kSize) > len)
980  continue;
981  if (buffer[pos] != SYNC_BYTE)
982  {
983  // if ProcessTSPacket fails, and we don't appear to be
984  // in sync on the next packet, then resync. Otherwise
985  // just process the next packet normally.
986  pos -= TSPacket::kSize;
987  resync = true;
988  }
989  }
990  }
991 
992  return len - pos;
993 }
994 
996 {
997  bool ok = !tspacket.TransportError();
998 
999  if (IsEncryptionTestPID(tspacket.PID()))
1000  {
1001  ProcessEncryptedPacket(tspacket);
1002  }
1003 
1004  if (!ok)
1005  return false;
1006 
1007  if (tspacket.Scrambled())
1008  return true;
1009 
1010  if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_DEBUG))
1011  {
1012  if (m_pmtSingleProgram && tspacket.PID() ==
1014  {
1015  if (tspacket.HasPCR())
1016  {
1017  LOG(VB_RECORD, LOG_DEBUG, LOC +
1018  QString("PID %1 (0x%2) has PCR %3μs")
1020  .arg(m_pmtSingleProgram->PCRPID(), 0, 16)
1021  .arg(std::chrono::duration_cast<std::chrono::microseconds>
1022  (tspacket.GetPCR().time_since_epoch()).count()));
1023  }
1024  }
1025  }
1026 
1027  if (IsVideoPID(tspacket.PID()))
1028  {
1029  for (auto & listener : m_tsAvListeners)
1030  listener->ProcessVideoTSPacket(tspacket);
1031 
1032  return true;
1033  }
1034 
1035  if (IsAudioPID(tspacket.PID()))
1036  {
1037  for (auto & listener : m_tsAvListeners)
1038  listener->ProcessAudioTSPacket(tspacket);
1039 
1040  return true;
1041  }
1042 
1043  if (IsWritingPID(tspacket.PID()))
1044  {
1045  for (auto & listener : m_tsWritingListeners)
1046  listener->ProcessTSPacket(tspacket);
1047  }
1048 
1049  if (IsListeningPID(tspacket.PID()) && tspacket.HasPayload())
1050  {
1051  HandleTSTables(&tspacket);
1052  }
1053 
1054  return true;
1055 }
1056 
1057 int MPEGStreamData::ResyncStream(const unsigned char *buffer, int curr_pos,
1058  int len)
1059 {
1060  // Search for two sync bytes 188 bytes apart,
1061  int pos = curr_pos;
1062  int nextpos = pos + TSPacket::kSize;
1063  if (nextpos >= len)
1064  return -1; // not enough bytes; caller should try again
1065 
1066  while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE)
1067  {
1068  pos++;
1069  nextpos++;
1070  if (nextpos == len)
1071  return -2; // not found
1072  }
1073 
1074  return pos;
1075 }
1076 
1078 {
1080  return false;
1081  pid_map_t::const_iterator it = m_pidsListening.find(pid);
1082  return it != m_pidsListening.end();
1083 }
1084 
1086 {
1087  pid_map_t::const_iterator it = m_pidsNotListening.find(pid);
1088  return it != m_pidsNotListening.end();
1089 }
1090 
1092 {
1093  pid_map_t::const_iterator it = m_pidsWriting.find(pid);
1094  return it != m_pidsWriting.end();
1095 }
1096 
1098 {
1099  pid_map_t::const_iterator it = m_pidsAudio.find(pid);
1100  return it != m_pidsAudio.end();
1101 }
1102 
1104 {
1105  uint sz = pids.size();
1106 
1107  if (m_pidVideoSingleProgram < 0x1fff)
1109 
1110  for (auto it = m_pidsListening.cbegin(); it != m_pidsListening.cend(); ++it)
1111  pids[it.key()] = max(pids[it.key()], *it);
1112 
1113  for (auto it = m_pidsAudio.cbegin(); it != m_pidsAudio.cend(); ++it)
1114  pids[it.key()] = max(pids[it.key()], *it);
1115 
1116  for (auto it = m_pidsWriting.cbegin(); it != m_pidsWriting.cend(); ++it)
1117  pids[it.key()] = max(pids[it.key()], *it);
1118 
1119  return pids.size() - sz;
1120 }
1121 
1123 {
1124  if (m_pidVideoSingleProgram == pid)
1125  return kPIDPriorityHigh;
1126 
1127  pid_map_t::const_iterator it;
1128  it = m_pidsListening.find(pid);
1129  if (it != m_pidsListening.end())
1130  return *it;
1131  it = m_pidsNotListening.find(pid);
1132  if (it != m_pidsNotListening.end())
1133  return *it;
1134  it = m_pidsWriting.find(pid);
1135  if (it != m_pidsWriting.end())
1136  return *it;
1137  it = m_pidsAudio.find(pid);
1138  if (it != m_pidsAudio.end())
1139  return *it;
1140 
1141  return kPIDPriorityNone;
1142 }
1143 
1145 {
1146  pid_psip_map_t::iterator it = m_partialPsipPacketCache.find(pid);
1147  if (it == m_partialPsipPacketCache.end())
1148  m_partialPsipPacketCache[pid] = packet;
1149  else
1150  {
1151  PSIPTable *old = *it;
1152  m_partialPsipPacketCache.remove(pid);
1153  m_partialPsipPacketCache.insert(pid, packet);
1154  delete old;
1155  }
1156 }
1157 
1159 {
1160  return m_patStatus.HasAllSections(tsid);
1161 }
1162 
1164 {
1165  return m_catStatus.HasAllSections(tsid);
1166 }
1167 
1169 {
1170  return m_pmtStatus.HasAllSections(prog_num);
1171 }
1172 
1174 {
1175  pmt_const_ptr_t pmt = GetCachedPMT(progNum, 0);
1176  bool hasit = pmt;
1177  ReturnCachedTable(pmt);
1178 
1179  return hasit;
1180 }
1181 
1183 {
1184  QMutexLocker locker(&m_cacheLock);
1185 
1186  pat_cache_t::const_iterator it = m_cachedPats.find(tsid << 8);
1187  if (it == m_cachedPats.end())
1188  return false;
1189 
1190  uint last_section = (*it)->LastSection();
1191  if (!last_section)
1192  return true;
1193 
1194  for (uint i = 1; i <= last_section; i++)
1195  if (m_cachedPats.find((tsid << 8) | i) == m_cachedPats.end())
1196  return false;
1197 
1198  return true;
1199 }
1200 
1202 {
1203  QMutexLocker locker(&m_cacheLock);
1204 
1205  for (uint i = 0; i <= 255; i++)
1206  if (m_cachedPats.find((tsid << 8) | i) != m_cachedPats.end())
1207  return true;
1208 
1209  return false;
1210 }
1211 
1213 {
1214  QMutexLocker locker(&m_cacheLock);
1215  return !m_cachedPats.empty();
1216 }
1217 
1219 {
1220  QMutexLocker locker(&m_cacheLock);
1221 
1222  cat_cache_t::const_iterator it = m_cachedCats.find(tsid << 8);
1223  if (it == m_cachedCats.end())
1224  return false;
1225 
1226  uint last_section = (*it)->LastSection();
1227  if (!last_section)
1228  return true;
1229 
1230  for (uint i = 1; i <= last_section; i++)
1231  if (m_cachedCats.find((tsid << 8) | i) == m_cachedCats.end())
1232  return false;
1233 
1234  return true;
1235 }
1236 
1238 {
1239  QMutexLocker locker(&m_cacheLock);
1240 
1241  for (uint i = 0; i <= 255; i++)
1242  if (m_cachedCats.find((tsid << 8) | i) != m_cachedCats.end())
1243  return true;
1244 
1245  return false;
1246 }
1247 
1249 {
1250  QMutexLocker locker(&m_cacheLock);
1251  return !m_cachedCats.empty();
1252 }
1253 
1255 {
1256  QMutexLocker locker(&m_cacheLock);
1257 
1258  pmt_cache_t::const_iterator it = m_cachedPmts.find(pnum << 8);
1259  if (it == m_cachedPmts.end())
1260  return false;
1261 
1262  uint last_section = (*it)->LastSection();
1263  if (!last_section)
1264  return true;
1265 
1266  for (uint i = 1; i <= last_section; i++)
1267  if (m_cachedPmts.find((pnum << 8) | i) == m_cachedPmts.end())
1268  return false;
1269 
1270  return true;
1271 }
1272 
1274 {
1275  QMutexLocker locker(&m_cacheLock);
1276 
1277  for (uint i = 0; i <= 255; i++)
1278  if (m_cachedPmts.find((pnum << 8) | i) != m_cachedPmts.end())
1279  return true;
1280 
1281  return false;
1282 }
1283 
1285 {
1286  QMutexLocker locker(&m_cacheLock);
1287 
1288  if (m_cachedPats.empty())
1289  return false;
1290 
1291  for (auto *pat : qAsConst(m_cachedPats))
1292  {
1293  if (!HasCachedAllPAT(pat->TransportStreamID()))
1294  return false;
1295 
1296  for (uint i = 0; i < pat->ProgramCount(); i++)
1297  {
1298  uint prognum = pat->ProgramNumber(i);
1299  if (prognum && !HasCachedAllPMT(prognum))
1300  return false;
1301  }
1302  }
1303 
1304  return true;
1305 }
1306 
1308 {
1309  QMutexLocker locker(&m_cacheLock);
1310  return !m_cachedPmts.empty();
1311 }
1312 
1314 {
1315  QMutexLocker locker(&m_cacheLock);
1316  ProgramAssociationTable *pat = nullptr;
1317 
1318  uint key = (tsid << 8) | section_num;
1319  pat_cache_t::const_iterator it = m_cachedPats.find(key);
1320  if (it != m_cachedPats.end())
1321  IncrementRefCnt(pat = *it);
1322 
1323  return pat;
1324 }
1325 
1327 {
1328  QMutexLocker locker(&m_cacheLock);
1329  pat_vec_t pats;
1330 
1331  for (uint i=0; i < 256; i++)
1332  {
1333  pat_const_ptr_t pat = GetCachedPAT(tsid, i);
1334  if (pat)
1335  pats.push_back(pat);
1336  }
1337 
1338  return pats;
1339 }
1340 
1342 {
1343  QMutexLocker locker(&m_cacheLock);
1344  pat_vec_t pats;
1345 
1346  for (auto *pat : qAsConst(m_cachedPats))
1347  {
1348  IncrementRefCnt(pat);
1349  pats.push_back(pat);
1350  }
1351 
1352  return pats;
1353 }
1354 
1356 {
1357  QMutexLocker locker(&m_cacheLock);
1358  ConditionalAccessTable *cat = nullptr;
1359 
1360  uint key = (tsid << 8) | section_num;
1361  cat_cache_t::const_iterator it = m_cachedCats.find(key);
1362  if (it != m_cachedCats.end())
1363  IncrementRefCnt(cat = *it);
1364 
1365  return cat;
1366 }
1367 
1369 {
1370  QMutexLocker locker(&m_cacheLock);
1371  cat_vec_t cats;
1372 
1373  for (uint i=0; i < 256; i++)
1374  {
1375  cat_const_ptr_t cat = GetCachedCAT(tsid, i);
1376  if (cat)
1377  cats.push_back(cat);
1378  }
1379 
1380  return cats;
1381 }
1382 
1384 {
1385  QMutexLocker locker(&m_cacheLock);
1386  cat_vec_t cats;
1387 
1388  for (auto *cat : qAsConst(m_cachedCats))
1389  {
1391  cats.push_back(cat);
1392  }
1393 
1394  return cats;
1395 }
1396 
1398  uint program_num, uint section_num) const
1399 {
1400  QMutexLocker locker(&m_cacheLock);
1401  ProgramMapTable *pmt = nullptr;
1402 
1403  uint key = (program_num << 8) | section_num;
1404  pmt_cache_t::const_iterator it = m_cachedPmts.find(key);
1405  if (it != m_cachedPmts.end())
1406  IncrementRefCnt(pmt = *it);
1407 
1408  return pmt;
1409 }
1410 
1412 {
1413  QMutexLocker locker(&m_cacheLock);
1414  vector<const ProgramMapTable*> pmts;
1415 
1416  for (auto *pmt : m_cachedPmts)
1417  {
1418  IncrementRefCnt(pmt);
1419  pmts.push_back(pmt);
1420  }
1421 
1422  return pmts;
1423 }
1424 
1426 {
1427  QMutexLocker locker(&m_cacheLock);
1428  pmt_map_t pmts;
1429 
1430  for (auto *pmt : m_cachedPmts)
1431  {
1432  IncrementRefCnt(pmt);
1433  pmts[pmt->ProgramNumber()].push_back(pmt);
1434  }
1435 
1436  return pmts;
1437 }
1438 
1440 {
1441  QMutexLocker locker(&m_cacheLock);
1442 
1443  int val = m_cachedRefCnt[psip] - 1;
1444  m_cachedRefCnt[psip] = val;
1445 
1446  // if ref <= 0 and table was slated for deletion, delete it.
1447  if (val <= 0)
1448  {
1449  psip_refcnt_map_t::iterator it;
1450  it = m_cachedSlatedForDeletion.find(psip);
1451  if (it != m_cachedSlatedForDeletion.end())
1452  DeleteCachedTable(psip);
1453  }
1454 }
1455 
1457 {
1458  for (auto & pat : pats)
1459  ReturnCachedTable(pat);
1460  pats.clear();
1461 }
1462 
1464 {
1465  // NOLINTNEXTLINE(modernize-loop-convert)
1466  for (pat_map_t::iterator it = pats.begin(); it != pats.end(); ++it)
1467  ReturnCachedPATTables(*it);
1468  pats.clear();
1469 }
1470 
1472 {
1473  for (auto & cat : cats)
1475  cats.clear();
1476 }
1477 
1479 {
1480  // NOLINTNEXTLINE(modernize-loop-convert)
1481  for (cat_map_t::iterator it = cats.begin(); it != cats.end(); ++it)
1482  ReturnCachedCATTables(*it);
1483  cats.clear();
1484 }
1485 
1487 {
1488  for (auto & pmt : pmts)
1489  ReturnCachedTable(pmt);
1490  pmts.clear();
1491 }
1492 
1494 {
1495  // NOLINTNEXTLINE(modernize-loop-convert)
1496  for (pmt_map_t::iterator it = pmts.begin(); it != pmts.end(); ++it)
1497  ReturnCachedPMTTables(*it);
1498  pmts.clear();
1499 }
1500 
1502 {
1503  QMutexLocker locker(&m_cacheLock);
1504  m_cachedRefCnt[psip] = m_cachedRefCnt[psip] + 1;
1505 }
1506 
1508 {
1509  if (!psip)
1510  return false;
1511 
1512  uint tid = psip->TableIDExtension();
1513 
1514  QMutexLocker locker(&m_cacheLock);
1515  if (m_cachedRefCnt[psip] > 0)
1516  {
1517  m_cachedSlatedForDeletion[psip] = 1;
1518  return false;
1519  }
1520  if (TableID::PAT == psip->TableID() &&
1521  (m_cachedPats[(tid << 8) | psip->Section()] == psip))
1522  {
1523  m_cachedPats[(tid << 8) | psip->Section()] = nullptr;
1524  delete psip;
1525  }
1526  else if (TableID::CAT == psip->TableID() &&
1527  (m_cachedCats[(tid << 8) | psip->Section()] == psip))
1528  {
1529  m_cachedCats[(tid << 8) | psip->Section()] = nullptr;
1530  delete psip;
1531  }
1532  else if ((TableID::PMT == psip->TableID()) &&
1533  (m_cachedPmts[(tid << 8) | psip->Section()] == psip))
1534  {
1535  m_cachedPmts[(tid << 8) | psip->Section()] = nullptr;
1536  delete psip;
1537  }
1538  else
1539  {
1540  m_cachedSlatedForDeletion[psip] = 2;
1541  return false;
1542  }
1543  psip_refcnt_map_t::iterator it;
1544  it = m_cachedSlatedForDeletion.find(psip);
1545  if (it != m_cachedSlatedForDeletion.end())
1546  m_cachedSlatedForDeletion.erase(it);
1547 
1548  return true;
1549 }
1550 
1552 {
1553  auto *pat = new ProgramAssociationTable(*_pat);
1554  uint key = (_pat->TransportStreamID() << 8) | _pat->Section();
1555 
1556  QMutexLocker locker(&m_cacheLock);
1557 
1558  pat_cache_t::iterator it = m_cachedPats.find(key);
1559  if (it != m_cachedPats.end())
1560  DeleteCachedTable(*it);
1561 
1562  m_cachedPats[key] = pat;
1563 }
1564 
1566 {
1567  auto *cat = new ConditionalAccessTable(*_cat);
1568  uint key = (_cat->TableIDExtension() << 8) | _cat->Section();
1569 
1570  QMutexLocker locker(&m_cacheLock);
1571 
1572  cat_cache_t::iterator it = m_cachedCats.find(key);
1573  if (it != m_cachedCats.end())
1574  DeleteCachedTable(*it);
1575 
1576  m_cachedCats[key] = cat;
1577 }
1578 
1580 {
1581  auto *pmt = new ProgramMapTable(*_pmt);
1582  uint key = (_pmt->ProgramNumber() << 8) | _pmt->Section();
1583 
1584  QMutexLocker locker(&m_cacheLock);
1585 
1586  pmt_cache_t::iterator it = m_cachedPmts.find(key);
1587  if (it != m_cachedPmts.end())
1588  DeleteCachedTable(*it);
1589 
1590  m_cachedPmts[key] = pmt;
1591 }
1592 
1594 {
1595  QMutexLocker locker(&m_listenerLock);
1596 
1597  for (auto & listener : m_mpegListeners)
1598  if (((void*)val) == ((void*)listener))
1599  return;
1600 
1601  m_mpegListeners.push_back(val);
1602 }
1603 
1605 {
1606  QMutexLocker locker(&m_listenerLock);
1607 
1608  for (auto it = m_mpegListeners.begin(); it != m_mpegListeners.end(); ++it)
1609  {
1610  if (((void*)val) == ((void*)*it))
1611  {
1612  m_mpegListeners.erase(it);
1613  return;
1614  }
1615  }
1616 }
1617 
1619 {
1620  QMutexLocker locker(&m_listenerLock);
1621 
1622  for (auto & listener : m_tsWritingListeners)
1623  if (((void*)val) == ((void*)listener))
1624  return;
1625 
1626  m_tsWritingListeners.push_back(val);
1627 }
1628 
1630 {
1631  QMutexLocker locker(&m_listenerLock);
1632 
1633  for (auto it = m_tsWritingListeners.begin(); it != m_tsWritingListeners.end(); ++it)
1634  {
1635  if (((void*)val) == ((void*)*it))
1636  {
1637  m_tsWritingListeners.erase(it);
1638  return;
1639  }
1640  }
1641 }
1642 
1644 {
1645  QMutexLocker locker(&m_listenerLock);
1646 
1647  for (auto & listener : m_tsAvListeners)
1648  if (((void*)val) == ((void*)listener))
1649  return;
1650 
1651  m_tsAvListeners.push_back(val);
1652 }
1653 
1655 {
1656  QMutexLocker locker(&m_listenerLock);
1657 
1658  for (auto it = m_tsAvListeners.begin(); it != m_tsAvListeners.end(); ++it)
1659  {
1660  if (((void*)val) == ((void*)*it))
1661  {
1662  m_tsAvListeners.erase(it);
1663  return;
1664  }
1665  }
1666 }
1667 
1669 {
1670  QMutexLocker locker(&m_listenerLock);
1671 
1672  for (auto & listener : m_mpegSpListeners)
1673  if (((void*)val) == ((void*)listener))
1674  return;
1675 
1676  m_mpegSpListeners.push_back(val);
1677 }
1678 
1680 {
1681  QMutexLocker locker(&m_listenerLock);
1682 
1683  for (auto it = m_mpegSpListeners.begin(); it != m_mpegSpListeners.end(); ++it)
1684  {
1685  if (((void*)val) == ((void*)*it))
1686  {
1687  m_mpegSpListeners.erase(it);
1688  return;
1689  }
1690  }
1691 }
1692 
1694 {
1695  QMutexLocker locker(&m_listenerLock);
1696 
1697  for (auto & listener : m_psListeners)
1698  if (((void*)val) == ((void*)listener))
1699  return;
1700 
1701  m_psListeners.push_back(val);
1702 }
1703 
1705 {
1706  QMutexLocker locker(&m_listenerLock);
1707 
1708  for (auto it = m_psListeners.begin(); it != m_psListeners.end(); ++it)
1709  {
1710  if (((void*)val) == ((void*)*it))
1711  {
1712  m_psListeners.erase(it);
1713  return;
1714  }
1715  }
1716 }
1717 
1718 void MPEGStreamData::AddEncryptionTestPID(uint pnum, uint pid, bool isvideo)
1719 {
1720  QMutexLocker locker(&m_encryptionLock);
1721 
1722 #if 0
1723  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("AddEncryptionTestPID(%1, 0x%2)")
1724  .arg(pnum) .arg(pid, 0, 16));
1725 #endif
1726 
1727  AddListeningPID(pid);
1728 
1729  m_encryptionPidToInfo[pid] = CryptInfo((isvideo) ? 10000 : 500, 8);
1730 
1731  m_encryptionPidToPnums[pid].push_back(pnum);
1732  m_encryptionPnumToPids[pnum].push_back(pid);
1734 }
1735 
1737 {
1738  QMutexLocker locker(&m_encryptionLock);
1739 
1740 #if 0
1741  LOG(VB_RECORD, LOG_DEBUG, LOC +
1742  QString("Tearing down up decryption monitoring for program %1")
1743  .arg(pnum));
1744 #endif
1745 
1746  QMap<uint, uint_vec_t>::iterator list;
1747  uint_vec_t::iterator it;
1748 
1749  uint_vec_t pids = m_encryptionPnumToPids[pnum];
1750  for (uint pid : pids)
1751  {
1752 #if 0
1753  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1754  QString("Removing 0x%1 PID Enc monitoring").arg(pid,0,16));
1755 #endif
1756 
1757  RemoveListeningPID(pid);
1758 
1759  list = m_encryptionPidToPnums.find(pid);
1760  if (list != m_encryptionPidToPnums.end())
1761  {
1762  it = find((*list).begin(), (*list).end(), pnum);
1763 
1764  if (it != (*list).end())
1765  (*list).erase(it);
1766 
1767  if ((*list).empty())
1768  {
1769  m_encryptionPidToPnums.remove(pid);
1770  m_encryptionPidToInfo.remove(pid);
1771  }
1772  }
1773  }
1774 
1775  m_encryptionPnumToPids.remove(pnum);
1776 }
1777 
1779 {
1780  QMutexLocker locker(&m_encryptionLock);
1781 
1782  QMap<uint, CryptInfo>::const_iterator it =
1783  m_encryptionPidToInfo.find(pid);
1784 
1785  return it != m_encryptionPidToInfo.end();
1786 }
1787 
1789 {
1790  QMutexLocker locker(&m_encryptionLock);
1791 
1792 #if 0
1793  LOG(VB_RECORD, LOG_DEBUG, LOC +
1794  QString("Setting up decryption monitoring for program %1")
1795  .arg(pmt->ProgramNumber()));
1796 #endif
1797 
1798  bool encrypted = pmt->IsProgramEncrypted();
1799  for (uint i = 0; i < pmt->StreamCount(); i++)
1800  {
1801  if (!encrypted && !pmt->IsStreamEncrypted(i))
1802  continue;
1803 
1804  bool is_vid = pmt->IsVideo(i, m_siStandard);
1805  bool is_aud = pmt->IsAudio(i, m_siStandard);
1806  if (is_vid || is_aud)
1807  {
1809  pmt->ProgramNumber(), pmt->StreamPID(i), is_vid);
1810  }
1811  }
1812 }
1813 
1815 {
1816  QMutexLocker locker(&m_encryptionLock);
1817 
1818  m_encryptionPidToInfo.clear();
1819  m_encryptionPidToPnums.clear();
1820  m_encryptionPnumToPids.clear();
1821 }
1822 
1824 {
1825  QMutexLocker locker(&m_encryptionLock);
1826  return m_encryptionPnumToStatus[pnum] == kEncDecrypted;
1827 }
1828 
1830 {
1831  QMutexLocker locker(&m_encryptionLock);
1832  return m_encryptionPnumToStatus[pnum] == kEncEncrypted;
1833 }
1834 
1835 static QString toString(CryptStatus status)
1836 {
1837  if (kEncDecrypted == status)
1838  return "Decrypted";
1839  if (kEncEncrypted == status)
1840  return "Encrypted";
1841  return "Unknown";
1842 }
1843 
1848 {
1849  QMutexLocker locker(&m_encryptionLock);
1850 
1851  const uint pid = tspacket.PID();
1852  CryptInfo &info = m_encryptionPidToInfo[pid];
1853 
1854  CryptStatus status = kEncUnknown;
1855 
1856  if (tspacket.Scrambled())
1857  {
1858  info.m_decryptedPackets = 0;
1859 
1860  // If a fair amount of encrypted packets is passed assume that
1861  // the stream is not decryptable
1862  if (++info.m_encryptedPackets >= info.m_encryptedMin)
1863  status = kEncEncrypted;
1864  }
1865  else
1866  {
1867  info.m_encryptedPackets = 0;
1868  if (++info.m_decryptedPackets > info.m_decryptedMin)
1869  status = kEncDecrypted;
1870  }
1871 
1872  if (status == info.m_status)
1873  return; // pid encryption status unchanged
1874 
1875  info.m_status = status;
1876 
1877  LOG(status != kEncDecrypted ? VB_GENERAL : VB_RECORD, LOG_DEBUG, LOC +
1878  QString("PID 0x%1 status: %2") .arg(pid,0,16).arg(toString(status)));
1879 
1880  uint_vec_t pnum_del_list;
1881  const uint_vec_t &pnums = m_encryptionPidToPnums[pid];
1882  for (uint pnum : pnums)
1883  {
1884  status = m_encryptionPnumToStatus[pnum];
1885 
1886  const uint_vec_t &pids = m_encryptionPnumToPids[pnum];
1887  if (!pids.empty())
1888  {
1889  std::array<uint,3> enc_cnt { 0, 0, 0 };
1890  for (uint pid2 : pids)
1891  {
1892  CryptStatus stat = m_encryptionPidToInfo[pid2].m_status;
1893  enc_cnt[stat]++;
1894 
1895 #if 0
1896  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1897  QString("\tpnum %1 PID 0x%2 status: %3")
1898  .arg(pnum).arg(pid2,0,16) .arg(toString(stat)));
1899 #endif
1900  }
1901  status = kEncUnknown;
1902 
1903  if (enc_cnt[kEncEncrypted])
1904  status = kEncEncrypted;
1905  else if (enc_cnt[kEncDecrypted] >= min((size_t) 2, pids.size()))
1906  status = kEncDecrypted;
1907  }
1908 
1909  if (status == m_encryptionPnumToStatus[pnum])
1910  continue; // program encryption status unchanged
1911 
1912  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Program %1 status: %2")
1913  .arg(pnum).arg(toString(status)));
1914 
1915  m_encryptionPnumToStatus[pnum] = status;
1916 
1917  bool encrypted = kEncUnknown == status || kEncEncrypted == status;
1918  m_listenerLock.lock();
1919  for (auto & listener : m_mpegListeners)
1920  listener->HandleEncryptionStatus(pnum, encrypted);
1921  m_listenerLock.unlock();
1922 
1923  if (kEncDecrypted == status)
1924  pnum_del_list.push_back(pnum);
1925  }
1926 
1927  for (size_t i = 0; i < pnum_del_list.size(); i++)
1928  RemoveEncryptionTestPIDs(pnums[i]);
1929 }
ProgramMapTable::ProgramInfo
const unsigned char * ProgramInfo(void) const
Definition: mpegtables.h:709
MPEGStreamData::m_cachedRefCnt
psip_refcnt_map_t m_cachedRefCnt
Definition: mpegstreamdata.h:354
ProgramMapTable::Parse
void Parse(void) const
Definition: mpegtables.cpp:468
pat_vec_t
vector< const ProgramAssociationTable * > pat_vec_t
Definition: mpegstreamdata.h:31
ProgramAssociationTable::FindAnyPID
uint FindAnyPID(void) const
Definition: mpegtables.h:636
MPEGStreamData::m_siTimeLock
QMutex m_siTimeLock
Definition: mpegstreamdata.h:309
pmt_vec_t
vector< const ProgramMapTable * > pmt_vec_t
Definition: channelscan_sm.h:63
MPEGStreamData::m_partialPsipPacketCache
pid_psip_map_t m_partialPsipPacketCache
Definition: mpegstreamdata.h:346
kEncUnknown
@ kEncUnknown
Definition: mpegstreamdata.h:57
MPEGStreamData::SetEITHelper
void SetEITHelper(EITHelper *eit_helper) override
Definition: mpegstreamdata.cpp:110
PSStreamListener
Definition: streamlisteners.h:103
TSHeader::PayloadStart
bool PayloadStart(void) const
Definition: tspacket.h:67
kEncEncrypted
@ kEncEncrypted
Definition: mpegstreamdata.h:59
MPEGStreamData::IsProgramDecrypted
bool IsProgramDecrypted(uint pnum) const
Definition: mpegstreamdata.cpp:1823
MPEGStreamData::m_pidsListening
pid_map_t m_pidsListening
Definition: mpegstreamdata.h:319
MPEGStreamData::SetVideoStreamsRequired
void SetVideoStreamsRequired(uint num)
Definition: mpegstreamdata.h:245
MPEGStreamData::ReturnCachedCATTables
virtual void ReturnCachedCATTables(cat_vec_t &cats) const
Definition: mpegstreamdata.cpp:1471
MPEGStreamData::m_pidsWriting
pid_map_t m_pidsWriting
Definition: mpegstreamdata.h:321
MPEGStreamData::~MPEGStreamData
~MPEGStreamData() override
Definition: mpegstreamdata.cpp:51
MPEGStreamData::m_invalidPatTimer
MythTimer m_invalidPatTimer
Definition: mpegstreamdata.h:373
MPEGStreamData::ProcessEncryptedPacket
void ProcessEncryptedPacket(const TSPacket &tspacket)
counts en/decrypted packets to decide if a stream is en/decrypted
Definition: mpegstreamdata.cpp:1847
TSPacket::StartOfFieldPointer
unsigned int StartOfFieldPointer(void) const
Definition: tspacket.h:213
TableID::PMT
@ PMT
Definition: mpegtables.h:255
CryptInfo::m_decryptedPackets
uint m_decryptedPackets
Definition: mpegstreamdata.h:71
ProgramMapTable::StreamCount
uint StreamCount(void) const
Definition: mpegtables.h:724
MPEGStreamData::SetDesiredProgram
void SetDesiredProgram(int p)
Definition: mpegstreamdata.cpp:67
TSHeader::HasPCR
bool HasPCR(void) const
Definition: tspacket.h:99
CryptInfo::m_decryptedMin
uint m_decryptedMin
Definition: mpegstreamdata.h:73
MPEGStreamData::ProcessPMT
void ProcessPMT(const ProgramMapTable *pmt)
Definition: mpegstreamdata.cpp:802
ProgramAssociationTable::Create
static ProgramAssociationTable * Create(uint tsid, uint version, const vector< uint > &pnum, const vector< uint > &pid)
Definition: mpegtables.cpp:346
MPEGStreamData::AddMPEGSPListener
void AddMPEGSPListener(MPEGSingleProgramStreamListener *val)
Definition: mpegstreamdata.cpp:1668
MPEGStreamData::m_invalidPatWarning
bool m_invalidPatWarning
Definition: mpegstreamdata.h:372
TableID::STUFFING
@ STUFFING
Definition: mpegtables.h:361
TableStatusMap::SetSectionSeen
void SetSectionSeen(uint32_t key, int32_t version, uint32_t section, uint32_t last_section, uint32_t segment_last_section=0xffff)
Definition: tablestatus.cpp:65
TableStatusMap::HasAllSections
bool HasAllSections(uint32_t key) const
Definition: tablestatus.cpp:81
MPEGStreamData::DeleteCachedTable
virtual bool DeleteCachedTable(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1507
PSIPTable::IsCurrent
bool IsCurrent(void) const
Definition: mpegtables.h:519
MPEGStreamData::CachePMT
void CachePMT(const ProgramMapTable *pmt)
Definition: mpegstreamdata.cpp:1579
toString
static QString toString(CryptStatus status)
Definition: mpegstreamdata.cpp:1835
MPEGStreamData::m_listeningDisabled
bool m_listeningDisabled
Definition: mpegstreamdata.h:323
ProgramMapTable::StreamInfo
const unsigned char * StreamInfo(uint i) const
Definition: mpegtables.h:721
MPEGStreamData::AssemblePSIP
PSIPTable * AssemblePSIP(const TSPacket *tspacket, bool &moreTablePackets)
PSIP packet assembler.
Definition: mpegstreamdata.cpp:205
MPEGStreamData::m_encryptionPidToInfo
QMap< uint, CryptInfo > m_encryptionPidToInfo
Definition: mpegstreamdata.h:327
pid_psip_map_t
QMap< unsigned int, PSIPTable * > pid_psip_map_t
Definition: mpegstreamdata.h:26
pat_map_t
QMap< uint, pat_vec_t > pat_map_t
Definition: mpegstreamdata.h:32
ATSCStreamData::GetCachedCVCTs
cvct_vec_t GetCachedCVCTs(bool current=true) const
Definition: atscstreamdata.cpp:831
hardwareprofile.devicelist.cat
def cat(file_name)
Definition: devicelist.py:95
PESPacket::pesdata
const unsigned char * pesdata() const
Definition: pespacket.h:159
ProgramMapTable
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:666
MPEGStreamData::GetCachedPATs
pat_vec_t GetCachedPATs(void) const
Definition: mpegstreamdata.cpp:1341
PESPacket::tsheader
const TSHeader * tsheader() const
Definition: pespacket.h:85
TSHeader::PID
unsigned int PID(void) const
Definition: tspacket.h:71
MPEGStreamData::m_siTimeOffsets
std::array< double, 16 > m_siTimeOffsets
Definition: mpegstreamdata.h:312
MPEGStreamData::IsRedundant
virtual bool IsRedundant(uint pid, const PSIPTable &psip) const
Returns true if table already seen.
Definition: mpegstreamdata.cpp:639
DescriptorID::conditional_access
@ conditional_access
Definition: mpegdescriptors.h:33
ProgramMapTable::FindPID
int FindPID(uint pid) const
Locates stream index of pid.
Definition: mpegtables.h:771
ProgramMapTable::PCRPID
uint PCRPID(void) const
stream that contains program clock reference.
Definition: mpegtables.h:700
SpliceInformationTable
Definition: mpegtables.h:1001
TSPacket::AFCOffset
unsigned int AFCOffset(void) const
Definition: tspacket.h:208
arg
arg(title).arg(filename).arg(doDelete))
MPEGStreamData::RemoveMPEGListener
void RemoveMPEGListener(MPEGStreamListener *val)
Definition: mpegstreamdata.cpp:1604
desc_list_t
vector< const unsigned char * > desc_list_t
Definition: mpegdescriptors.h:18
ProgramMapTable::IsVideo
bool IsVideo(uint i, const QString &sistandard) const
Returns true iff the stream at index i is a video stream.
Definition: mpegtables.cpp:513
MPEGStreamData::IsVideoPID
bool IsVideoPID(uint pid) const
Definition: mpegstreamdata.h:141
MPEGStreamData::MPEGStreamData
MPEGStreamData(int desiredProgram, int cardnum, bool cacheTables)
Initializes MPEGStreamData.
Definition: mpegstreamdata.cpp:40
MPEGStreamData::m_cacheLock
QMutex m_cacheLock
Definition: mpegstreamdata.h:350
atscstreamdata.h
MPEGStreamData::m_siTimeOffsetIndx
uint m_siTimeOffsetIndx
Definition: mpegstreamdata.h:311
ProgramMapTable::ProgramNumber
uint ProgramNumber(void) const
Definition: mpegtables.h:703
MPEGStreamData::HasCachedAnyPAT
bool HasCachedAnyPAT(void) const
Definition: mpegstreamdata.cpp:1212
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
PESPacket::PSIOffset
uint PSIOffset() const
Definition: pespacket.h:157
TSHeader::Scrambled
bool Scrambled(void) const
Definition: tspacket.h:90
MPEGStreamData::m_normalizeStreamType
bool m_normalizeStreamType
Definition: mpegstreamdata.h:361
TableID::SITscte
@ SITscte
Definition: mpegtables.h:328
MPEGStreamData::AddEncryptionTestPID
void AddEncryptionTestPID(uint pnum, uint pid, bool isvideo)
Definition: mpegstreamdata.cpp:1718
MPEGStreamData::ProcessCAT
void ProcessCAT(const ConditionalAccessTable *cat)
Definition: mpegstreamdata.cpp:784
MPEG_PAT_PID
@ MPEG_PAT_PID
Definition: mpegtables.h:205
TSPacketListener
Definition: streamlisteners.h:62
MPEGStreamData::IsNotListeningPID
virtual bool IsNotListeningPID(uint pid) const
Definition: mpegstreamdata.cpp:1085
MPEGSingleProgramStreamListener
Definition: streamlisteners.h:93
MPEGStreamData::m_encryptionLock
QMutex m_encryptionLock
Definition: mpegstreamdata.h:326
kPIDPriorityNone
@ kPIDPriorityNone
Definition: mpegstreamdata.h:78
PESPacket::StreamID
uint StreamID() const
Definition: pespacket.h:93
MPEGStreamData::SetPMTSingleProgram
void SetPMTSingleProgram(ProgramMapTable *pmt)
Definition: mpegstreamdata.h:384
MPEG_CAT_PID
@ MPEG_CAT_PID
Definition: mpegtables.h:206
MPEGStreamData::IsAudioPID
virtual bool IsAudioPID(uint pid) const
Definition: mpegstreamdata.cpp:1097
MPEGStreamData::m_eitHelper
EITHelper * m_eitHelper
Definition: mpegstreamdata.h:315
MPEGStreamData::IsProgramEncrypted
bool IsProgramEncrypted(uint pnum) const
Definition: mpegstreamdata.cpp:1829
cat_vec_t
vector< const ConditionalAccessTable * > cat_vec_t
Definition: mpegstreamdata.h:37
MPEGStreamData::PMTSingleProgram
const ProgramMapTable * PMTSingleProgram(void) const
Definition: mpegstreamdata.h:262
PSIPTable::Section
uint Section(void) const
Definition: mpegtables.h:522
MPEGStreamData::GetPIDs
uint GetPIDs(pid_map_t &pids) const
Definition: mpegstreamdata.cpp:1103
MPEGStreamData::ResyncStream
static int ResyncStream(const unsigned char *buffer, int curr_pos, int len)
Definition: mpegstreamdata.cpp:1057
StreamID::IsVideo
static bool IsVideo(uint type)
Returns true iff video is an MPEG1/2/3, H264 or open cable video stream.
Definition: mpegtables.h:168
MPEGStreamData::GetPIDPriority
PIDPriority GetPIDPriority(uint pid) const
Definition: mpegstreamdata.cpp:1122
MPEGStreamData::CacheCAT
void CacheCAT(const ConditionalAccessTable *_cat)
Definition: mpegstreamdata.cpp:1565
MPEGStreamData::UpdateTimeOffset
void UpdateTimeOffset(uint64_t si_utc_time)
Definition: mpegstreamdata.cpp:833
PESPacket::SetPSIOffset
void SetPSIOffset(uint offset)
Definition: pespacket.h:178
MPEGStreamData::m_haveCrcBug
bool m_haveCrcBug
Definition: mpegstreamdata.h:307
MPEGDescriptor::ParseAndExclude
static desc_list_t ParseAndExclude(const unsigned char *data, uint len, int excluded_descid)
Definition: mpegdescriptors.cpp:34
SYNC_BYTE
#define SYNC_BYTE
Definition: tspacket.h:15
TSHeader::ContinuityCounter
unsigned int ContinuityCounter(void) const
Definition: tspacket.h:87
DescriptorID::teletext
@ teletext
Definition: mpegdescriptors.h:95
MPEGStreamData::ReturnCachedPATTables
virtual void ReturnCachedPATTables(pat_vec_t &pats) const
Definition: mpegstreamdata.cpp:1456
TSHeader::SetContinuityCounter
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:148
MPEGStreamData::IsListeningPID
virtual bool IsListeningPID(uint pid) const
Definition: mpegstreamdata.cpp:1077
PSIPTable
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:386
MPEGStreamData::HasCachedAllPMTs
bool HasCachedAllPMTs(void) const
Definition: mpegstreamdata.cpp:1284
MPEGStreamData::m_siStandard
QString m_siStandard
Definition: mpegstreamdata.h:305
MPEGStreamData::CreatePMTSingleProgram
bool CreatePMTSingleProgram(const ProgramMapTable &pmt)
Definition: mpegstreamdata.cpp:455
MPEGDescriptor::IsValid
bool IsValid(void) const
Definition: mpegdescriptors.h:322
ATSCStreamData::ReturnCachedTVCTTables
void ReturnCachedTVCTTables(tvct_vec_t &tvcts) const
Definition: atscstreamdata.cpp:915
MPEGStreamData::ReturnCachedTable
virtual void ReturnCachedTable(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1439
ProgramMapTable::IsStreamEncrypted
bool IsStreamEncrypted(uint pid) const
Returns true iff PMT contains CA descriptor.
Definition: mpegtables.cpp:595
MPEGStreamData::HasCachedAllCAT
bool HasCachedAllCAT(uint tsid) const
Definition: mpegstreamdata.cpp:1218
MPEGStreamData::m_listenerLock
QMutex m_listenerLock
Definition: mpegstreamdata.h:333
MPEGStreamData::PATSingleProgram
const ProgramAssociationTable * PATSingleProgram(void) const
Definition: mpegstreamdata.h:260
CryptInfo
Definition: mpegstreamdata.h:62
MPEGStreamData::m_tsAvListeners
ts_av_listener_vec_t m_tsAvListeners
Definition: mpegstreamdata.h:337
MPEGStreamData::AddPSStreamListener
void AddPSStreamListener(PSStreamListener *val)
Definition: mpegstreamdata.cpp:1693
ProgramAssociationTable::TransportStreamID
uint TransportStreamID(void) const
Definition: mpegtables.h:608
MPEGStreamData::IsEncryptionTestPID
bool IsEncryptionTestPID(uint pid) const
Definition: mpegstreamdata.cpp:1778
ProgramMapTable::toString
QString toString(void) const override
Definition: mpegtables.cpp:879
MPEGStreamData::m_pidsNotListening
pid_map_t m_pidsNotListening
Definition: mpegstreamdata.h:320
MPEGStreamData::m_desiredProgram
int m_desiredProgram
Definition: mpegstreamdata.h:358
hardwareprofile.config.p
p
Definition: config.py:33
MPEGStreamData::m_siTimeOffsetCnt
uint m_siTimeOffsetCnt
Definition: mpegstreamdata.h:310
MPEGStreamData::HasCachedAllPMT
bool HasCachedAllPMT(uint pnum) const
Definition: mpegstreamdata.cpp:1254
MPEGStreamListener
Definition: streamlisteners.h:81
MPEGStreamData::SetRecordingType
void SetRecordingType(const QString &recording_type)
Definition: mpegstreamdata.cpp:102
MPEGStreamData::m_stripPmtDescriptors
bool m_stripPmtDescriptors
Definition: mpegstreamdata.h:360
StreamID::IsAudio
static bool IsAudio(uint type)
Returns true iff audio is MPEG1/2, AAC, AC3 or DTS audio stream.
Definition: mpegtables.h:179
MPEGStreamData::m_cachedCats
cat_cache_t m_cachedCats
Definition: mpegstreamdata.h:352
TSPacketListenerAV
Definition: streamlisteners.h:71
MPEGStreamData::GetCachedPAT
pat_const_ptr_t GetCachedPAT(uint tsid, uint section_num) const
Definition: mpegstreamdata.cpp:1313
TSPacket
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:166
ATSCStreamData
Encapsulates data about ATSC stream and emits events for most tables.
Definition: atscstreamdata.h:28
DONE_WITH_PSIP_PACKET
#define DONE_WITH_PSIP_PACKET()
Definition: mpegstreamdata.cpp:852
MPEGStreamData::ProcessData
virtual int ProcessData(const unsigned char *buffer, int len)
Definition: mpegstreamdata.cpp:945
ProgramMapTable::StreamType
uint StreamType(uint i) const
Definition: mpegtables.h:712
MPEGStreamData::HandleTables
virtual bool HandleTables(uint pid, const PSIPTable &psip)
Process PSIP packets.
Definition: mpegstreamdata.cpp:666
MPEGStreamData::GetCachedCATs
cat_vec_t GetCachedCATs(void) const
Definition: mpegstreamdata.cpp:1383
pmt_const_ptr_t
ProgramMapTable const * pmt_const_ptr_t
Definition: mpegstreamdata.h:42
MPEGStreamData::m_pidPmtSingleProgram
uint m_pidPmtSingleProgram
Definition: mpegstreamdata.h:363
ConditionalAccessDescriptor
Definition: mpegdescriptors.h:389
MPEGStreamData::m_pidsAudio
pid_map_t m_pidsAudio
Definition: mpegstreamdata.h:322
TableID::ST
@ ST
Definition: mpegtables.h:274
MPEGStreamData::CreatePATSingleProgram
bool CreatePATSingleProgram(const ProgramAssociationTable &pat)
Definition: mpegstreamdata.cpp:346
MPEGStreamData::SetEITRate
void SetEITRate(float rate) override
Definition: mpegstreamdata.cpp:116
MPEGDescriptor::ParseOnlyInclude
static desc_list_t ParseOnlyInclude(const unsigned char *data, uint len, int excluded_descid)
Definition: mpegdescriptors.cpp:57
CryptInfo::m_encryptedMin
uint m_encryptedMin
Definition: mpegstreamdata.h:72
MPEGStreamData::RemoveWritingListener
void RemoveWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1629
MPEGStreamData::m_pidVideoSingleProgram
uint m_pidVideoSingleProgram
Definition: mpegstreamdata.h:362
CryptStatus
CryptStatus
Definition: mpegstreamdata.h:55
MPEGStreamData::GetCachedPMTs
pmt_vec_t GetCachedPMTs(void) const
Definition: mpegstreamdata.cpp:1411
ProgramAssociationTable::toString
QString toString(void) const override
Definition: mpegtables.cpp:814
DescriptorID::caption_service
@ caption_service
Definition: mpegdescriptors.h:163
ATSCStreamData::ReturnCachedCVCTTables
void ReturnCachedCVCTTables(cvct_vec_t &cvcts) const
Definition: atscstreamdata.cpp:922
MPEGStreamData::ProcessPAT
void ProcessPAT(const ProgramAssociationTable *pat)
Definition: mpegstreamdata.cpp:733
mpegtables.h
MPEGStreamData::GetCachedPMTMap
pmt_map_t GetCachedPMTMap(void) const
Definition: mpegstreamdata.cpp:1425
MPEGStreamData::m_pmtSingleProgram
ProgramMapTable * m_pmtSingleProgram
Definition: mpegstreamdata.h:367
MPEGStreamData::m_mpegListeners
mpeg_listener_vec_t m_mpegListeners
Definition: mpegstreamdata.h:334
MPEGStreamData::m_catStatus
TableStatusMap m_catStatus
Definition: mpegstreamdata.h:342
MPEGStreamData::SetAudioStreamsRequired
void SetAudioStreamsRequired(uint num)
Definition: mpegstreamdata.h:249
MPEGStreamData::CachePAT
void CachePAT(const ProgramAssociationTable *pat)
Definition: mpegstreamdata.cpp:1551
MPEGStreamData::ResetDecryptionMonitoringState
void ResetDecryptionMonitoringState(void)
Definition: mpegstreamdata.cpp:1814
PESPacket::IsGood
bool IsGood() const
Definition: pespacket.h:83
MPEGStreamData::m_pmtStatus
TableStatusMap m_pmtStatus
Definition: mpegstreamdata.h:343
MPEGStreamData::DeletePartialPSIP
void DeletePartialPSIP(uint pid)
Definition: mpegstreamdata.cpp:172
MPEGStreamData::m_recordingType
QString m_recordingType
Definition: mpegstreamdata.h:359
PESPacket::TSSizeInBuffer
uint TSSizeInBuffer() const
Definition: pespacket.h:156
uint
unsigned int uint
Definition: compat.h:140
EITHelper
Definition: eithelper.h:92
kEncDecrypted
@ kEncDecrypted
Definition: mpegstreamdata.h:58
ProgramAssociationTable
The Program Association Table lists all the programs in a stream, and is always found on PID 0.
Definition: mpegtables.h:589
PSIPTable::LastSection
uint LastSection(void) const
Definition: mpegtables.h:525
PSIPTable::HasCRC
bool HasCRC(void) const override
1 bit Cyclic Redundancy Check present
Definition: mpegtables.cpp:94
ProgramMapTable::IsAudio
bool IsAudio(uint i, const QString &sistandard) const
Returns true iff the stream at index i is an audio stream.
Definition: mpegtables.cpp:535
MPEGStreamData::m_encryptionPnumToStatus
QMap< uint, CryptStatus > m_encryptionPnumToStatus
Definition: mpegstreamdata.h:330
TSPacket::kPayloadSize
static constexpr unsigned int kPayloadSize
Definition: tspacket.h:221
ATSCStreamData::GetCachedTVCTs
tvct_vec_t GetCachedTVCTs(bool current=true) const
Definition: atscstreamdata.cpp:810
pid_map_t
QMap< uint, PIDPriority > pid_map_t
Definition: mpegstreamdata.h:83
TableID
Contains listing of Table ID's for various tables (PAT=0,PMT=2,etc).
Definition: mpegtables.h:248
mpegstreamdata.h
MPEGStreamData::SavePartialPSIP
void SavePartialPSIP(uint pid, PSIPTable *packet)
Definition: mpegstreamdata.cpp:1144
kPIDPriorityHigh
@ kPIDPriorityHigh
Definition: mpegstreamdata.h:81
MPEGStreamData::HasAllPATSections
bool HasAllPATSections(uint tsid) const
Definition: mpegstreamdata.cpp:1158
MPEGStreamData::IncrementRefCnt
void IncrementRefCnt(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1501
MPEGStreamData::GetCachedPMT
pmt_const_ptr_t GetCachedPMT(uint program_num, uint section_num) const
Definition: mpegstreamdata.cpp:1397
MPEGStreamData::AddMPEGListener
void AddMPEGListener(MPEGStreamListener *val)
Definition: mpegstreamdata.cpp:1593
PSIPTable::VerifyPSIP
bool VerifyPSIP(bool verify_crc) const
Definition: mpegtables.cpp:236
DescriptorID::subtitling
@ subtitling
Definition: mpegdescriptors.h:98
MythTimer::elapsed
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
MPEGStreamData::RemovePSStreamListener
void RemovePSStreamListener(PSStreamListener *val)
Definition: mpegstreamdata.cpp:1704
MPEGStreamData::AddAVListener
void AddAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1643
MPEGStreamData::ReturnCachedPMTTables
virtual void ReturnCachedPMTTables(pmt_vec_t &pmts) const
Definition: mpegstreamdata.cpp:1486
ProgramMapTable::ProgramInfoLength
uint ProgramInfoLength(void) const
Definition: mpegtables.h:706
VERBOSE_LEVEL_CHECK
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
MPEGStreamData::AddWritingPID
virtual void AddWritingPID(uint pid, PIDPriority priority=kPIDPriorityHigh)
Definition: mpegstreamdata.h:125
CryptInfo::m_status
CryptStatus m_status
Definition: mpegstreamdata.h:69
MPEGStreamData::HasCachedAnyPMT
bool HasCachedAnyPMT(uint pnum) const
Definition: mpegstreamdata.cpp:1273
MPEGStreamData::TimeOffset
double TimeOffset(void) const
Current Offset from computer time to DVB time in seconds.
Definition: mpegstreamdata.cpp:819
extract_atsc_desc
static desc_list_t extract_atsc_desc(const tvct_vec_t &tvct, const cvct_vec_t &cvct, uint pnum)
Definition: mpegstreamdata.cpp:411
PESPacket::AddTSPacket
bool AddTSPacket(const TSPacket *tspacket, bool &broken)
Definition: pespacket.cpp:21
MPEGStreamData::AddWritingListener
void AddWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1618
cat_map_t
QMap< uint, cat_vec_t > cat_map_t
Definition: mpegstreamdata.h:38
TableID::STT
@ STT
Definition: mpegtables.h:344
MPEGStreamData::GetCachedCAT
cat_const_ptr_t GetCachedCAT(uint tsid, uint section_num) const
Definition: mpegstreamdata.cpp:1355
PSIPTable::TableID
uint TableID(void) const
Definition: mpegtables.h:489
PSIPTable::TableIDExtension
uint TableIDExtension(void) const
Definition: mpegtables.h:506
TableID::PAT
@ PAT
Definition: mpegtables.h:253
pmt_map_t
QMap< uint, pmt_vec_t > pmt_map_t
Definition: channelscan_sm.h:64
MPEGStreamData::m_pmtSingleProgramNumVideo
uint m_pmtSingleProgramNumVideo
Definition: mpegstreamdata.h:364
MPEGStreamData::m_mpegSpListeners
mpeg_sp_listener_vec_t m_mpegSpListeners
Definition: mpegstreamdata.h:335
MPEGStreamData::m_invalidPatSeen
bool m_invalidPatSeen
Definition: mpegstreamdata.h:371
TSHeader::HasPayload
bool HasPayload(void) const
Definition: tspacket.h:94
MPEGStreamData::SetPATSingleProgram
void SetPATSingleProgram(ProgramAssociationTable *pat)
Definition: mpegstreamdata.h:378
ConditionalAccessTable
The CAT is used to transmit additional ConditionalAccessDescriptor instances, in addition to the ones...
Definition: mpegtables.h:829
uint_vec_t
vector< uint > uint_vec_t
Definition: mpegstreamdata.h:24
MPEGStreamData::HasAllCATSections
bool HasAllCATSections(uint tsid) const
Definition: mpegstreamdata.cpp:1163
cvct_vec_t
vector< const CableVirtualChannelTable * > cvct_vec_t
Definition: atscstreamdata.h:16
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
LOC
#define LOC
Definition: mpegstreamdata.cpp:22
MPEGStreamData::m_cachedSlatedForDeletion
psip_refcnt_map_t m_cachedSlatedForDeletion
Definition: mpegstreamdata.h:355
MPEGStreamData::AddAudioPID
virtual void AddAudioPID(uint pid, PIDPriority priority=kPIDPriorityHigh)
Definition: mpegstreamdata.h:128
MPEGStreamData::HasCachedAnyPMTs
bool HasCachedAnyPMTs(void) const
Definition: mpegstreamdata.cpp:1307
MPEGStreamData::ProcessTSPacket
virtual bool ProcessTSPacket(const TSPacket &tspacket)
Definition: mpegstreamdata.cpp:995
MPEGStreamData::m_psListeners
ps_listener_vec_t m_psListeners
Definition: mpegstreamdata.h:338
TableID::CAT
@ CAT
Definition: mpegtables.h:254
atsctables.h
MPEGStreamData::HasCachedAllPAT
bool HasCachedAllPAT(uint tsid) const
Definition: mpegstreamdata.cpp:1182
MPEGStreamData::m_cacheTables
bool m_cacheTables
Definition: mpegstreamdata.h:349
tvct_vec_t
vector< const TerrestrialVirtualChannelTable * > tvct_vec_t
Definition: atscstreamdata.h:15
MPEGStreamData::m_tsWritingListeners
ts_listener_vec_t m_tsWritingListeners
Definition: mpegstreamdata.h:336
MPEGStreamData::AddListeningPID
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
Definition: mpegstreamdata.h:120
SpliceInformationTable::setSCTEPID
void setSCTEPID(int ts_pid)
Definition: mpegtables.h:1018
ProgramAssociationTable::FindPID
uint FindPID(uint progNum) const
Definition: mpegtables.h:629
MPEGStreamData::HandleTSTables
virtual void HandleTSTables(const TSPacket *tspacket)
Assembles PSIP packets and processes them.
Definition: mpegstreamdata.cpp:858
MPEGStreamData::m_patStatus
TableStatusMap m_patStatus
Definition: mpegstreamdata.h:341
TableStatusMap::IsSectionSeen
bool IsSectionSeen(uint32_t key, int32_t version, uint32_t section) const
Definition: tablestatus.cpp:73
MPEGStreamData::m_cachedPats
pat_cache_t m_cachedPats
Definition: mpegstreamdata.h:351
MPEGStreamData::m_pmtSingleProgramNumAudio
uint m_pmtSingleProgramNumAudio
Definition: mpegstreamdata.h:365
MPEGStreamData::m_eitRate
float m_eitRate
Definition: mpegstreamdata.h:316
TSHeader::GetPCR
TimePoint GetPCR(void) const
Definition: tspacket.h:126
ProgramMapTable::StreamInfoLength
uint StreamInfoLength(uint i) const
Definition: mpegtables.h:718
CryptInfo::m_encryptedPackets
uint m_encryptedPackets
Definition: mpegstreamdata.h:70
StreamID::Normalize
static uint Normalize(uint stream_id, const desc_list_t &desc, const QString &sistandard)
Definition: mpegtables.cpp:46
MPEGDescriptor::Find
static const unsigned char * Find(const desc_list_t &parsed, uint desc_tag)
Definition: mpegdescriptors.cpp:78
MPEGStreamData::m_encryptionPnumToPids
QMap< uint, uint_vec_t > m_encryptionPnumToPids
Definition: mpegstreamdata.h:328
ProgramMapTable::IsProgramEncrypted
bool IsProgramEncrypted(void) const
Returns true iff PMT's ProgramInfo contains CA descriptor.
Definition: mpegtables.cpp:567
MPEGStreamData::m_encryptionPidToPnums
QMap< uint, uint_vec_t > m_encryptionPidToPnums
Definition: mpegstreamdata.h:329
MPEGStreamData::RemoveAVListener
void RemoveAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1654
MPEGStreamData::IsWritingPID
virtual bool IsWritingPID(uint pid) const
Definition: mpegstreamdata.cpp:1091
ProgramMapTable::StreamPID
uint StreamPID(uint i) const
Definition: mpegtables.h:715
PIDPriority
PIDPriority
Definition: mpegstreamdata.h:76
MPEGStreamData::HasCachedAnyCAT
bool HasCachedAnyCAT(void) const
Definition: mpegstreamdata.cpp:1248
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:81
MPEGStreamData::TestDecryption
void TestDecryption(const ProgramMapTable *pmt)
Definition: mpegstreamdata.cpp:1788
TSHeader::data
const unsigned char * data(void) const
Definition: tspacket.h:152
MPEGStreamData::GetPartialPSIP
PSIPTable * GetPartialPSIP(uint pid)
Definition: mpegstreamdata.h:282
MPEGStreamData::RemoveMPEGSPListener
void RemoveMPEGSPListener(MPEGSingleProgramStreamListener *val)
Definition: mpegstreamdata.cpp:1679
MPEGStreamData::RemoveListeningPID
virtual void RemoveListeningPID(uint pid)
Definition: mpegstreamdata.h:132
MPEGStreamData::HasProgram
bool HasProgram(uint progNum) const
Definition: mpegstreamdata.cpp:1173
PSIPTable::Version
uint Version(void) const
Definition: mpegtables.h:513
ProgramMapTable::Create
static ProgramMapTable * Create(uint programNumber, uint basepid, uint pcrpid, uint version, vector< uint > pids, vector< uint > types)
Definition: mpegtables.cpp:406
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:356
TSHeader::TransportError
bool TransportError(void) const
Definition: tspacket.h:64
ConditionalAccessDescriptor::PID
uint PID(void) const
Definition: mpegdescriptors.h:396
MPEGStreamData::m_cachedPmts
pmt_cache_t m_cachedPmts
Definition: mpegstreamdata.h:353
MPEGStreamData::HasAllPMTSections
bool HasAllPMTSections(uint prog_num) const
Definition: mpegstreamdata.cpp:1168
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:220
MPEGStreamData::RemoveEncryptionTestPIDs
void RemoveEncryptionTestPIDs(uint pnum)
Definition: mpegstreamdata.cpp:1736