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