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