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)").
364  arg(m_desiredProgram).arg(m_pidPmtSingleProgram, 0, 16));
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.")
377  .arg(m_desiredProgram));
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  std::vector<uint> videoPIDs;
508  std::vector<uint> audioPIDs;
509  std::vector<uint> dataPIDs;
510 
511  for (uint i = 0; i < pmt.StreamCount(); i++)
512  {
513  uint pid = pmt.StreamPID(i);
514 
516  pmt.StreamInfo(i), pmt.StreamInfoLength(i),
518 
520  pmt.StreamType(i), desc, m_siStandard);
521 
522  bool is_video = StreamID::IsVideo(type);
523  bool is_audio = StreamID::IsAudio(type);
524 
525  if (is_audio)
526  {
527  audioPIDs.push_back(pid);
528  }
529  else if (m_recordingType == "audio" )
530  {
531  // If not an audio PID but we only want audio,
532  // ignore this PID.
533  continue;
534  }
535 
536 #ifdef DEBUG_MPEG_RADIO
537  if (is_video)
538  continue;
539 #endif // DEBUG_MPEG_RADIO
540 
541  if (is_video)
542  {
543  videoPIDs.push_back(pid);
544  }
545 
547  desc.clear();
548 
549  // Filter out streams not used for basic television
550  if (m_recordingType == "tv" && !is_audio && !is_video &&
553  pid != pmt.PCRPID()) // We must not strip the PCR!
554  {
555  continue;
556  }
557 
558  if (!is_audio && !is_video) //NOTE: Anything which isn't audio or video is data
559  dataPIDs.push_back(pid);
560 
561  pdesc.push_back(desc);
562  pids.push_back(pid);
563  types.push_back(type);
564  }
565 
566  if (videoPIDs.size() < m_pmtSingleProgramNumVideo)
567  {
568  LOG(VB_RECORD, LOG_ERR, LOC +
569  QString("Only %1 video streams seen in PMT, but %2 are required.")
570  .arg(videoPIDs.size()).arg(m_pmtSingleProgramNumVideo));
571  return false;
572  }
573 
574  if (audioPIDs.size() < m_pmtSingleProgramNumAudio)
575  {
576  LOG(VB_RECORD, LOG_ERR, LOC +
577  QString("Only %1 audio streams seen in PMT, but %2 are required.")
578  .arg(audioPIDs.size()).arg(m_pmtSingleProgramNumAudio));
579  return false;
580  }
581 
583  pmt.ProgramInfo(), pmt.ProgramInfoLength(),
585  for (auto & i : cdesc)
586  {
588  if (cad.IsValid())
589  {
590  AddListeningPID(cad.PID());
592  }
593  }
594 
595  m_pidsAudio.clear();
596  for (uint pid : audioPIDs)
597  AddAudioPID(pid);
598 
599  m_pidsWriting.clear();
600  m_pidVideoSingleProgram = !videoPIDs.empty() ? videoPIDs[0] : 0xffffffff;
601  for (size_t i = 1; i < videoPIDs.size(); i++)
602  AddWritingPID(videoPIDs[i]);
603 
604  for (uint pid : dataPIDs)
605  AddWritingPID(pid);
606 
607  // Timebase
608  int pcrpidIndex = pmt.FindPID(pmt.PCRPID());
609  if (pcrpidIndex < 0)
610  {
611  // the timecode reference stream is not in the PMT,
612  // add stream to misc record streams
613  AddWritingPID(pmt.PCRPID());
614  }
615 
616  // Create the PMT
618  programNumber, m_pidPmtSingleProgram, pmt.PCRPID(),
619  pmt.Version(), gdesc, pids, types, pdesc);
620 
621  // Return any TVCT & CVCT tables, once we've copied any descriptors.
622  if (sd)
623  {
624  sd->ReturnCachedTVCTTables(tvct);
625  sd->ReturnCachedCVCTTables(cvct);
626  }
627 
628  // Set Continuity Header
629  uint cc_cnt = pmt.tsheader()->ContinuityCounter();
630  pmt2->tsheader()->SetContinuityCounter(cc_cnt);
631  SetPMTSingleProgram(pmt2);
632 
633  LOG(VB_RECORD, LOG_DEBUG, LOC + "PMT for output stream");
634  LOG(VB_RECORD, LOG_DEBUG, LOC + pmt2->toString());
635 
636  return true;
637 }
638 
642 bool MPEGStreamData::IsRedundant(uint pid, const PSIPTable &psip) const
643 {
644  (void) pid;
645  const int table_id = psip.TableID();
646  const int version = psip.Version();
647 
648  if (TableID::PAT == table_id)
649  {
650  return m_patStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
651  }
652 
653  if (TableID::CAT == table_id)
654  {
655  return m_catStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
656  }
657 
658  if (TableID::PMT == table_id)
659  {
660  return m_pmtStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
661  }
662 
663  return false;
664 }
665 
670 {
671  if (MPEGStreamData::IsRedundant(pid, psip))
672  return true;
673 
674  const int version = psip.Version();
675  // If we get this far decode table
676  switch (psip.TableID())
677  {
678  case TableID::PAT:
679  {
680  uint tsid = psip.TableIDExtension();
681  m_patStatus.SetSectionSeen(tsid, version, psip.Section(), psip.LastSection());
682 
683  ProgramAssociationTable pat(psip);
684 
685  if (m_cacheTables)
686  CachePAT(&pat);
687 
688  ProcessPAT(&pat);
689 
690  return true;
691  }
692  case TableID::CAT:
693  {
694  uint tsid = psip.TableIDExtension();
695  m_catStatus.SetSectionSeen(tsid, version, psip.Section(), psip.LastSection());
696 
698 
699  if (m_cacheTables)
700  CacheCAT(&cat);
701 
702  ProcessCAT(&cat);
703 
704  return true;
705  }
706  case TableID::PMT:
707  {
708  uint prog_num = psip.TableIDExtension();
709  m_pmtStatus.SetSectionSeen(prog_num, version, psip.Section(), psip.LastSection());
710 
711  ProgramMapTable pmt(psip);
712 
713  if (m_cacheTables)
714  CachePMT(&pmt);
715 
716  ProcessPMT(&pmt);
717 
718  return true;
719  }
720  case TableID::SITscte:
721  {
722  SpliceInformationTable sit(psip);
723  sit.setSCTEPID(pid);
724 
725  m_listenerLock.lock();
726  for (auto & listener : m_mpegListeners)
727  listener->HandleSplice(&sit);
728  m_listenerLock.unlock();
729 
730  return true;
731  }
732  }
733  return false;
734 }
735 
737 {
738  bool foundProgram = pat->FindPID(m_desiredProgram) != 0U;
739 
740  m_listenerLock.lock();
741  for (auto & listener : m_mpegListeners)
742  listener->HandlePAT(pat);
743  m_listenerLock.unlock();
744 
745  if (m_desiredProgram < 0)
746  return;
747 
748  bool send_single_program = false;
749  if (!m_invalidPatSeen && !foundProgram)
750  {
751  m_invalidPatSeen = true;
752  m_invalidPatWarning = false;
754  LOG(VB_RECORD, LOG_WARNING, LOC +
755  "ProcessPAT: PAT is missing program, setting timeout");
756  }
757  else if (m_invalidPatSeen && !foundProgram &&
759  {
760  m_invalidPatWarning = true; // only emit one warning...
761  // After 400ms emit error if we haven't found correct PAT.
762  LOG(VB_GENERAL, LOG_ERR, LOC + "ProcessPAT: Program not found in PAT. "
763  "Rescan your transports.");
764 
765  send_single_program = CreatePATSingleProgram(*pat);
766  }
767  else if (foundProgram)
768  {
769  if (m_invalidPatSeen)
770  LOG(VB_RECORD, LOG_INFO, LOC +
771  "ProcessPAT: Good PAT seen after a bad PAT");
772 
773  m_invalidPatSeen = false;
774 
775  send_single_program = CreatePATSingleProgram(*pat);
776  }
777 
778  if (send_single_program)
779  {
780  QMutexLocker locker(&m_listenerLock);
782  for (auto & listener : m_mpegSpListeners)
783  listener->HandleSingleProgramPAT(pat_sp, false);
784  }
785 }
786 
788 {
789  m_listenerLock.lock();
790  for (auto & listener : m_mpegListeners)
791  listener->HandleCAT(cat);
792  m_listenerLock.unlock();
793 
795  cat->Descriptors(), cat->DescriptorsLength(),
797  for (auto & i : cdesc)
798  {
800  if (cad.IsValid())
801  {
802  AddListeningPID(cad.PID());
804  }
805  }
806 }
807 
809 {
810  m_listenerLock.lock();
811  for (auto & listener : m_mpegListeners)
812  listener->HandlePMT(pmt->ProgramNumber(), pmt);
813  m_listenerLock.unlock();
814 
815  bool desired = pmt->ProgramNumber() == (uint) m_desiredProgram;
816  if (desired && CreatePMTSingleProgram(*pmt))
817  {
818  QMutexLocker locker(&m_listenerLock);
819  ProgramMapTable *pmt_sp = PMTSingleProgram();
820  for (auto & listener : m_mpegSpListeners)
821  listener->HandleSingleProgramPMT(pmt_sp, false);
822  }
823 }
824 
825 double MPEGStreamData::TimeOffset(void) const
826 {
827  QMutexLocker locker(&m_siTimeLock);
828  if (!m_siTimeOffsetCnt)
829  return 0.0;
830 
831  double avg_offset = 0.0;
832  double mult = 1.0 / m_siTimeOffsetCnt;
833  for (uint i = 0; i < m_siTimeOffsetCnt; i++)
834  avg_offset += m_siTimeOffsets[i] * mult;
835 
836  return avg_offset;
837 }
838 
839 void MPEGStreamData::UpdateTimeOffset(uint64_t _si_utc_time)
840 {
841  struct timeval tm {};
842  if (gettimeofday(&tm, nullptr) != 0)
843  return;
844 
845  double utc_time = tm.tv_sec + (tm.tv_usec * 0.000001);
846  double si_time = _si_utc_time;
847 
848  QMutexLocker locker(&m_siTimeLock);
849  m_siTimeOffsets[m_siTimeOffsetIndx] = si_time - utc_time;
850 
853 
855 
856 }
857 
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 compiant");
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  if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_DEBUG))
1017  {
1018  if (m_pmtSingleProgram && tspacket.PID() ==
1020  {
1021  if (tspacket.HasPCR())
1022  {
1023  LOG(VB_RECORD, LOG_DEBUG, LOC +
1024  QString("PID %1 (0x%2) has PCR %3μs")
1025  .arg(m_pmtSingleProgram->PCRPID())
1026  .arg(m_pmtSingleProgram->PCRPID(), 0, 16)
1027  .arg(duration_cast<std::chrono::microseconds>
1028  (tspacket.GetPCR().time_since_epoch()).count()));
1029  }
1030  }
1031  }
1032 
1033  if (IsVideoPID(tspacket.PID()))
1034  {
1035  for (auto & listener : m_tsAvListeners)
1036  listener->ProcessVideoTSPacket(tspacket);
1037 
1038  return true;
1039  }
1040 
1041  if (IsAudioPID(tspacket.PID()))
1042  {
1043  for (auto & listener : m_tsAvListeners)
1044  listener->ProcessAudioTSPacket(tspacket);
1045 
1046  return true;
1047  }
1048 
1049  if (IsWritingPID(tspacket.PID()))
1050  {
1051  for (auto & listener : m_tsWritingListeners)
1052  listener->ProcessTSPacket(tspacket);
1053  }
1054 
1055  if (tspacket.HasPayload() &&
1056  IsListeningPID(tspacket.PID()) &&
1057  !IsConditionalAccessPID(tspacket.PID()))
1058  {
1059  HandleTSTables(&tspacket); // Table handling starts here....
1060  }
1061 
1062  return true;
1063 }
1064 
1065 int MPEGStreamData::ResyncStream(const unsigned char *buffer, int curr_pos,
1066  int len)
1067 {
1068  // Search for two sync bytes 188 bytes apart,
1069  int pos = curr_pos;
1070  int nextpos = pos + TSPacket::kSize;
1071  if (nextpos >= len)
1072  return -1; // not enough bytes; caller should try again
1073 
1074  while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE)
1075  {
1076  pos++;
1077  nextpos++;
1078  if (nextpos == len)
1079  return -2; // not found
1080  }
1081 
1082  return pos;
1083 }
1084 
1086 {
1087  pid_map_t::const_iterator it = m_pidsConditionalAccess.find(pid);
1088  return it != m_pidsConditionalAccess.end();
1089 }
1090 
1092 {
1094  return false;
1095  pid_map_t::const_iterator it = m_pidsListening.find(pid);
1096  return it != m_pidsListening.end();
1097 }
1098 
1100 {
1101  pid_map_t::const_iterator it = m_pidsNotListening.find(pid);
1102  return it != m_pidsNotListening.end();
1103 }
1104 
1106 {
1107  pid_map_t::const_iterator it = m_pidsWriting.find(pid);
1108  return it != m_pidsWriting.end();
1109 }
1110 
1112 {
1113  pid_map_t::const_iterator it = m_pidsAudio.find(pid);
1114  return it != m_pidsAudio.end();
1115 }
1116 
1118 {
1119  uint sz = pids.size();
1120 
1121  if (m_pidVideoSingleProgram < 0x1fff)
1123 
1124  for (auto it = m_pidsListening.cbegin(); it != m_pidsListening.cend(); ++it)
1125  pids[it.key()] = std::max(pids[it.key()], *it);
1126 
1127  for (auto it = m_pidsAudio.cbegin(); it != m_pidsAudio.cend(); ++it)
1128  pids[it.key()] = std::max(pids[it.key()], *it);
1129 
1130  for (auto it = m_pidsWriting.cbegin(); it != m_pidsWriting.cend(); ++it)
1131  pids[it.key()] = std::max(pids[it.key()], *it);
1132 
1133  return pids.size() - sz;
1134 }
1135 
1137 {
1138  if (m_pidVideoSingleProgram == pid)
1139  return kPIDPriorityHigh;
1140 
1141  pid_map_t::const_iterator it;
1142  it = m_pidsListening.find(pid);
1143  if (it != m_pidsListening.end())
1144  return *it;
1145  it = m_pidsNotListening.find(pid);
1146  if (it != m_pidsNotListening.end())
1147  return *it;
1148  it = m_pidsWriting.find(pid);
1149  if (it != m_pidsWriting.end())
1150  return *it;
1151  it = m_pidsAudio.find(pid);
1152  if (it != m_pidsAudio.end())
1153  return *it;
1154 
1155  return kPIDPriorityNone;
1156 }
1157 
1159 {
1160  pid_psip_map_t::iterator it = m_partialPsipPacketCache.find(pid);
1161  if (it == m_partialPsipPacketCache.end())
1162  m_partialPsipPacketCache[pid] = packet;
1163  else
1164  {
1165  PSIPTable *old = *it;
1166  m_partialPsipPacketCache.remove(pid);
1167  m_partialPsipPacketCache.insert(pid, packet);
1168  delete old;
1169  }
1170 }
1171 
1173 {
1174  return m_patStatus.HasAllSections(tsid);
1175 }
1176 
1178 {
1179  return m_catStatus.HasAllSections(tsid);
1180 }
1181 
1183 {
1184  return m_pmtStatus.HasAllSections(prog_num);
1185 }
1186 
1188 {
1189  pmt_const_ptr_t pmt = GetCachedPMT(progNum, 0);
1190  bool hasit = pmt;
1191  ReturnCachedTable(pmt);
1192 
1193  return hasit;
1194 }
1195 
1197 {
1198  QMutexLocker locker(&m_cacheLock);
1199 
1200  pat_cache_t::const_iterator it = m_cachedPats.constFind(tsid << 8);
1201  if (it == m_cachedPats.constEnd())
1202  return false;
1203 
1204  uint last_section = (*it)->LastSection();
1205  if (!last_section)
1206  return true;
1207 
1208  for (uint i = 1; i <= last_section; i++)
1209  if (m_cachedPats.constFind((tsid << 8) | i) == m_cachedPats.constEnd())
1210  return false;
1211 
1212  return true;
1213 }
1214 
1216 {
1217  QMutexLocker locker(&m_cacheLock);
1218 
1219  for (uint i = 0; i <= 255; i++)
1220  if (m_cachedPats.find((tsid << 8) | i) != m_cachedPats.end())
1221  return true;
1222 
1223  return false;
1224 }
1225 
1227 {
1228  QMutexLocker locker(&m_cacheLock);
1229  return !m_cachedPats.empty();
1230 }
1231 
1233 {
1234  QMutexLocker locker(&m_cacheLock);
1235 
1236  cat_cache_t::const_iterator it = m_cachedCats.constFind(tsid << 8);
1237  if (it == m_cachedCats.constEnd())
1238  return false;
1239 
1240  uint last_section = (*it)->LastSection();
1241  if (!last_section)
1242  return true;
1243 
1244  for (uint i = 1; i <= last_section; i++)
1245  if (m_cachedCats.constFind((tsid << 8) | i) == m_cachedCats.constEnd())
1246  return false;
1247 
1248  return true;
1249 }
1250 
1252 {
1253  QMutexLocker locker(&m_cacheLock);
1254 
1255  for (uint i = 0; i <= 255; i++)
1256  if (m_cachedCats.find((tsid << 8) | i) != m_cachedCats.end())
1257  return true;
1258 
1259  return false;
1260 }
1261 
1263 {
1264  QMutexLocker locker(&m_cacheLock);
1265  return !m_cachedCats.empty();
1266 }
1267 
1269 {
1270  QMutexLocker locker(&m_cacheLock);
1271 
1272  pmt_cache_t::const_iterator it = m_cachedPmts.constFind(pnum << 8);
1273  if (it == m_cachedPmts.constEnd())
1274  return false;
1275 
1276  uint last_section = (*it)->LastSection();
1277  if (!last_section)
1278  return true;
1279 
1280  for (uint i = 1; i <= last_section; i++)
1281  if (m_cachedPmts.constFind((pnum << 8) | i) == m_cachedPmts.constEnd())
1282  return false;
1283 
1284  return true;
1285 }
1286 
1288 {
1289  QMutexLocker locker(&m_cacheLock);
1290 
1291  for (uint i = 0; i <= 255; i++)
1292  if (m_cachedPmts.find((pnum << 8) | i) != m_cachedPmts.end())
1293  return true;
1294 
1295  return false;
1296 }
1297 
1299 {
1300  QMutexLocker locker(&m_cacheLock);
1301 
1302  if (m_cachedPats.empty())
1303  return false;
1304 
1305  for (auto *pat : qAsConst(m_cachedPats))
1306  {
1307  if (!HasCachedAllPAT(pat->TransportStreamID()))
1308  return false;
1309 
1310  for (uint i = 0; i < pat->ProgramCount(); i++)
1311  {
1312  uint prognum = pat->ProgramNumber(i);
1313  if (prognum && !HasCachedAllPMT(prognum))
1314  return false;
1315  }
1316  }
1317 
1318  return true;
1319 }
1320 
1322 {
1323  QMutexLocker locker(&m_cacheLock);
1324  return !m_cachedPmts.empty();
1325 }
1326 
1328 {
1329  QMutexLocker locker(&m_cacheLock);
1330  ProgramAssociationTable *pat = nullptr;
1331 
1332  uint key = (tsid << 8) | section_num;
1333  pat_cache_t::const_iterator it = m_cachedPats.constFind(key);
1334  if (it != m_cachedPats.constEnd())
1335  IncrementRefCnt(pat = *it);
1336 
1337  return pat;
1338 }
1339 
1341 {
1342  QMutexLocker locker(&m_cacheLock);
1343  pat_vec_t pats;
1344 
1345  for (uint i=0; i < 256; i++)
1346  {
1347  pat_const_ptr_t pat = GetCachedPAT(tsid, i);
1348  if (pat)
1349  pats.push_back(pat);
1350  }
1351 
1352  return pats;
1353 }
1354 
1356 {
1357  QMutexLocker locker(&m_cacheLock);
1358  pat_vec_t pats;
1359 
1360  for (auto *pat : qAsConst(m_cachedPats))
1361  {
1362  IncrementRefCnt(pat);
1363  pats.push_back(pat);
1364  }
1365 
1366  return pats;
1367 }
1368 
1370 {
1371  QMutexLocker locker(&m_cacheLock);
1372  ConditionalAccessTable *cat = nullptr;
1373 
1374  uint key = (tsid << 8) | section_num;
1375  cat_cache_t::const_iterator it = m_cachedCats.constFind(key);
1376  if (it != m_cachedCats.constEnd())
1377  IncrementRefCnt(cat = *it);
1378 
1379  return cat;
1380 }
1381 
1383 {
1384  QMutexLocker locker(&m_cacheLock);
1385  cat_vec_t cats;
1386 
1387  for (uint i=0; i < 256; i++)
1388  {
1389  cat_const_ptr_t cat = GetCachedCAT(tsid, i);
1390  if (cat)
1391  cats.push_back(cat);
1392  }
1393 
1394  return cats;
1395 }
1396 
1398 {
1399  QMutexLocker locker(&m_cacheLock);
1400  cat_vec_t cats;
1401 
1402  for (auto *cat : qAsConst(m_cachedCats))
1403  {
1405  cats.push_back(cat);
1406  }
1407 
1408  return cats;
1409 }
1410 
1412  uint program_num, uint section_num) const
1413 {
1414  QMutexLocker locker(&m_cacheLock);
1415  ProgramMapTable *pmt = nullptr;
1416 
1417  uint key = (program_num << 8) | section_num;
1418  pmt_cache_t::const_iterator it = m_cachedPmts.constFind(key);
1419  if (it != m_cachedPmts.constEnd())
1420  IncrementRefCnt(pmt = *it);
1421 
1422  return pmt;
1423 }
1424 
1426 {
1427  QMutexLocker locker(&m_cacheLock);
1428  std::vector<const ProgramMapTable*> pmts;
1429 
1430  for (auto *pmt : qAsConst(m_cachedPmts))
1431  {
1432  IncrementRefCnt(pmt);
1433  pmts.push_back(pmt);
1434  }
1435 
1436  return pmts;
1437 }
1438 
1440 {
1441  QMutexLocker locker(&m_cacheLock);
1442  pmt_map_t pmts;
1443 
1444  for (auto *pmt : qAsConst(m_cachedPmts))
1445  {
1446  IncrementRefCnt(pmt);
1447  pmts[pmt->ProgramNumber()].push_back(pmt);
1448  }
1449 
1450  return pmts;
1451 }
1452 
1454 {
1455  QMutexLocker locker(&m_cacheLock);
1456 
1457  int val = m_cachedRefCnt[psip] - 1;
1458  m_cachedRefCnt[psip] = val;
1459 
1460  // if ref <= 0 and table was slated for deletion, delete it.
1461  if (val <= 0)
1462  {
1463  psip_refcnt_map_t::iterator it;
1464  it = m_cachedSlatedForDeletion.find(psip);
1465  if (it != m_cachedSlatedForDeletion.end())
1466  DeleteCachedTable(psip);
1467  }
1468 }
1469 
1471 {
1472  for (auto & pat : pats)
1473  ReturnCachedTable(pat);
1474  pats.clear();
1475 }
1476 
1478 {
1479  // NOLINTNEXTLINE(modernize-loop-convert)
1480  for (pat_map_t::iterator it = pats.begin(); it != pats.end(); ++it)
1481  ReturnCachedPATTables(*it);
1482  pats.clear();
1483 }
1484 
1486 {
1487  for (auto & cat : cats)
1489  cats.clear();
1490 }
1491 
1493 {
1494  // NOLINTNEXTLINE(modernize-loop-convert)
1495  for (cat_map_t::iterator it = cats.begin(); it != cats.end(); ++it)
1496  ReturnCachedCATTables(*it);
1497  cats.clear();
1498 }
1499 
1501 {
1502  for (auto & pmt : pmts)
1503  ReturnCachedTable(pmt);
1504  pmts.clear();
1505 }
1506 
1508 {
1509  // NOLINTNEXTLINE(modernize-loop-convert)
1510  for (pmt_map_t::iterator it = pmts.begin(); it != pmts.end(); ++it)
1511  ReturnCachedPMTTables(*it);
1512  pmts.clear();
1513 }
1514 
1516 {
1517  QMutexLocker locker(&m_cacheLock);
1518  m_cachedRefCnt[psip] = m_cachedRefCnt[psip] + 1;
1519 }
1520 
1522 {
1523  if (!psip)
1524  return false;
1525 
1526  uint tid = psip->TableIDExtension();
1527 
1528  QMutexLocker locker(&m_cacheLock);
1529  if (m_cachedRefCnt[psip] > 0)
1530  {
1531  m_cachedSlatedForDeletion[psip] = 1;
1532  return false;
1533  }
1534  if (TableID::PAT == psip->TableID() &&
1535  (m_cachedPats[(tid << 8) | psip->Section()] == psip))
1536  {
1537  m_cachedPats[(tid << 8) | psip->Section()] = nullptr;
1538  delete psip;
1539  }
1540  else if (TableID::CAT == psip->TableID() &&
1541  (m_cachedCats[(tid << 8) | psip->Section()] == psip))
1542  {
1543  m_cachedCats[(tid << 8) | psip->Section()] = nullptr;
1544  delete psip;
1545  }
1546  else if ((TableID::PMT == psip->TableID()) &&
1547  (m_cachedPmts[(tid << 8) | psip->Section()] == psip))
1548  {
1549  m_cachedPmts[(tid << 8) | psip->Section()] = nullptr;
1550  delete psip;
1551  }
1552  else
1553  {
1554  m_cachedSlatedForDeletion[psip] = 2;
1555  return false;
1556  }
1557  psip_refcnt_map_t::iterator it;
1558  it = m_cachedSlatedForDeletion.find(psip);
1559  if (it != m_cachedSlatedForDeletion.end())
1560  m_cachedSlatedForDeletion.erase(it);
1561 
1562  return true;
1563 }
1564 
1566 {
1567  auto *pat = new ProgramAssociationTable(*_pat);
1568  uint key = (_pat->TransportStreamID() << 8) | _pat->Section();
1569 
1570  QMutexLocker locker(&m_cacheLock);
1571 
1572  pat_cache_t::iterator it = m_cachedPats.find(key);
1573  if (it != m_cachedPats.end())
1574  DeleteCachedTable(*it);
1575 
1576  m_cachedPats[key] = pat;
1577 }
1578 
1580 {
1581  auto *cat = new ConditionalAccessTable(*_cat);
1582  uint key = (_cat->TableIDExtension() << 8) | _cat->Section();
1583 
1584  QMutexLocker locker(&m_cacheLock);
1585 
1586  cat_cache_t::iterator it = m_cachedCats.find(key);
1587  if (it != m_cachedCats.end())
1588  DeleteCachedTable(*it);
1589 
1590  m_cachedCats[key] = cat;
1591 }
1592 
1594 {
1595  auto *pmt = new ProgramMapTable(*_pmt);
1596  uint key = (_pmt->ProgramNumber() << 8) | _pmt->Section();
1597 
1598  QMutexLocker locker(&m_cacheLock);
1599 
1600  pmt_cache_t::iterator it = m_cachedPmts.find(key);
1601  if (it != m_cachedPmts.end())
1602  DeleteCachedTable(*it);
1603 
1604  m_cachedPmts[key] = pmt;
1605 }
1606 
1608 {
1609  QMutexLocker locker(&m_listenerLock);
1610 
1611  for (auto & listener : m_mpegListeners)
1612  if (((void*)val) == ((void*)listener))
1613  return;
1614 
1615  m_mpegListeners.push_back(val);
1616 }
1617 
1619 {
1620  QMutexLocker locker(&m_listenerLock);
1621 
1622  for (auto it = m_mpegListeners.begin(); it != m_mpegListeners.end(); ++it)
1623  {
1624  if (((void*)val) == ((void*)*it))
1625  {
1626  m_mpegListeners.erase(it);
1627  return;
1628  }
1629  }
1630 }
1631 
1633 {
1634  QMutexLocker locker(&m_listenerLock);
1635 
1636  for (auto & listener : m_tsWritingListeners)
1637  if (((void*)val) == ((void*)listener))
1638  return;
1639 
1640  m_tsWritingListeners.push_back(val);
1641 }
1642 
1644 {
1645  QMutexLocker locker(&m_listenerLock);
1646 
1647  for (auto it = m_tsWritingListeners.begin(); it != m_tsWritingListeners.end(); ++it)
1648  {
1649  if (((void*)val) == ((void*)*it))
1650  {
1651  m_tsWritingListeners.erase(it);
1652  return;
1653  }
1654  }
1655 }
1656 
1658 {
1659  QMutexLocker locker(&m_listenerLock);
1660 
1661  for (auto & listener : m_tsAvListeners)
1662  {
1663  if (((void*)val) == ((void*)listener))
1664  {
1665  LOG(VB_RECORD, LOG_ERR, LOC + QString("AddAVListener 0x%1 already present")
1666  .arg((uint64_t)val, 0, 16));
1667  return;
1668  }
1669  }
1670 
1671  m_tsAvListeners.push_back(val);
1672 #if 0
1673  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("AddAVListener 0x%1 added")
1674  .arg((uint64_t)val, 0, 16));
1675 #endif
1676 }
1677 
1679 {
1680  QMutexLocker locker(&m_listenerLock);
1681 
1682  for (auto it = m_tsAvListeners.begin(); it != m_tsAvListeners.end(); ++it)
1683  {
1684  if (((void*)val) == ((void*)*it))
1685  {
1686  m_tsAvListeners.erase(it);
1687 #if 0
1688  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("RemoveAVListener 0x%1 found and removed")
1689  .arg((uint64_t)val, 0, 16));
1690 #endif
1691  return;
1692  }
1693  }
1694 
1695  LOG(VB_RECORD, LOG_ERR, LOC + QString("RemoveAVListener 0x%1 NOT found")
1696  .arg((uint64_t)val, 0, 16));
1697 }
1698 
1700 {
1701  QMutexLocker locker(&m_listenerLock);
1702 
1703  for (auto & listener : m_mpegSpListeners)
1704  if (((void*)val) == ((void*)listener))
1705  return;
1706 
1707  m_mpegSpListeners.push_back(val);
1708 }
1709 
1711 {
1712  QMutexLocker locker(&m_listenerLock);
1713 
1714  for (auto it = m_mpegSpListeners.begin(); it != m_mpegSpListeners.end(); ++it)
1715  {
1716  if (((void*)val) == ((void*)*it))
1717  {
1718  m_mpegSpListeners.erase(it);
1719  return;
1720  }
1721  }
1722 }
1723 
1725 {
1726  QMutexLocker locker(&m_listenerLock);
1727 
1728  for (auto & listener : m_psListeners)
1729  if (((void*)val) == ((void*)listener))
1730  return;
1731 
1732  m_psListeners.push_back(val);
1733 }
1734 
1736 {
1737  QMutexLocker locker(&m_listenerLock);
1738 
1739  for (auto it = m_psListeners.begin(); it != m_psListeners.end(); ++it)
1740  {
1741  if (((void*)val) == ((void*)*it))
1742  {
1743  m_psListeners.erase(it);
1744  return;
1745  }
1746  }
1747 }
1748 
1749 void MPEGStreamData::AddEncryptionTestPID(uint pnum, uint pid, bool isvideo)
1750 {
1751  QMutexLocker locker(&m_encryptionLock);
1752 
1753 #if 0
1754  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("AddEncryptionTestPID(%1, 0x%2)")
1755  .arg(pnum) .arg(pid, 0, 16));
1756 #endif
1757 
1758  AddListeningPID(pid);
1759 
1760  m_encryptionPidToInfo[pid] = CryptInfo((isvideo) ? 10000 : 500, 8);
1761 
1762  m_encryptionPidToPnums[pid].push_back(pnum);
1763  m_encryptionPnumToPids[pnum].push_back(pid);
1765 }
1766 
1768 {
1769  QMutexLocker locker(&m_encryptionLock);
1770 
1771 #if 0
1772  LOG(VB_RECORD, LOG_DEBUG, LOC +
1773  QString("Tearing down up decryption monitoring for program %1")
1774  .arg(pnum));
1775 #endif
1776 
1777  QMap<uint, uint_vec_t>::iterator list;
1778  uint_vec_t::iterator it;
1779 
1780  uint_vec_t pids = m_encryptionPnumToPids[pnum];
1781  for (uint pid : pids)
1782  {
1783 #if 0
1784  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1785  QString("Removing 0x%1 PID Enc monitoring").arg(pid,0,16));
1786 #endif
1787 
1788  RemoveListeningPID(pid);
1789 
1790  list = m_encryptionPidToPnums.find(pid);
1791  if (list != m_encryptionPidToPnums.end())
1792  {
1793  it = find((*list).begin(), (*list).end(), pnum);
1794 
1795  if (it != (*list).end())
1796  (*list).erase(it);
1797 
1798  if ((*list).empty())
1799  {
1800  m_encryptionPidToPnums.remove(pid);
1801  m_encryptionPidToInfo.remove(pid);
1802  }
1803  }
1804  }
1805 
1806  m_encryptionPnumToPids.remove(pnum);
1807 }
1808 
1810 {
1811  QMutexLocker locker(&m_encryptionLock);
1812 
1813  QMap<uint, CryptInfo>::const_iterator it =
1814  m_encryptionPidToInfo.find(pid);
1815 
1816  return it != m_encryptionPidToInfo.end();
1817 }
1818 
1820 {
1821  QMutexLocker locker(&m_encryptionLock);
1822 
1823 #if 0
1824  LOG(VB_RECORD, LOG_DEBUG, LOC +
1825  QString("Setting up decryption monitoring for program %1")
1826  .arg(pmt->ProgramNumber()));
1827 #endif
1828 
1829  bool encrypted = pmt->IsProgramEncrypted();
1830  for (uint i = 0; i < pmt->StreamCount(); i++)
1831  {
1832  if (!encrypted && !pmt->IsStreamEncrypted(i))
1833  continue;
1834 
1835  const uint streamType = pmt->StreamType(i);
1836  bool is_vid = StreamID::IsVideo(streamType);
1837  bool is_aud = StreamID::IsAudio(streamType);
1838 
1839  if (is_vid || is_aud)
1840  {
1842  pmt->ProgramNumber(), pmt->StreamPID(i), is_vid);
1843  }
1844  }
1845 }
1846 
1848 {
1849  QMutexLocker locker(&m_encryptionLock);
1850 
1851  m_encryptionPidToInfo.clear();
1852  m_encryptionPidToPnums.clear();
1853  m_encryptionPnumToPids.clear();
1854 }
1855 
1857 {
1858  QMutexLocker locker(&m_encryptionLock);
1859  return m_encryptionPnumToStatus[pnum] == kEncDecrypted;
1860 }
1861 
1863 {
1864  QMutexLocker locker(&m_encryptionLock);
1865  return m_encryptionPnumToStatus[pnum] == kEncEncrypted;
1866 }
1867 
1868 static QString toString(CryptStatus status)
1869 {
1870  if (kEncDecrypted == status)
1871  return "Decrypted";
1872  if (kEncEncrypted == status)
1873  return "Encrypted";
1874  return "Unknown";
1875 }
1876 
1881 {
1882  QMutexLocker encryptionLock(&m_encryptionLock);
1883 
1884  std::map<uint,bool> pnumEncrypted;
1885  const uint pid = tspacket.PID();
1886  CryptInfo &info = m_encryptionPidToInfo[pid];
1887 
1888  CryptStatus status = kEncUnknown;
1889 
1890  if (tspacket.Scrambled())
1891  {
1892  info.m_decryptedPackets = 0;
1893 
1894  // If a fair amount of encrypted packets is passed assume that
1895  // the stream is not decryptable
1896  if (++info.m_encryptedPackets >= info.m_encryptedMin)
1897  status = kEncEncrypted;
1898  }
1899  else
1900  {
1901  info.m_encryptedPackets = 0;
1902  if (++info.m_decryptedPackets > info.m_decryptedMin)
1903  status = kEncDecrypted;
1904  }
1905 
1906  if (status == info.m_status)
1907  return; // pid encryption status unchanged
1908 
1909  info.m_status = status;
1910 
1911  LOG(status != kEncDecrypted ? VB_GENERAL : VB_RECORD, LOG_DEBUG, LOC +
1912  QString("PID 0x%1 status: %2") .arg(pid,0,16).arg(toString(status)));
1913 
1914  uint_vec_t pnum_del_list;
1915  const uint_vec_t &pnums = m_encryptionPidToPnums[pid];
1916  for (uint pnum : pnums)
1917  {
1918  status = m_encryptionPnumToStatus[pnum];
1919 
1920  const uint_vec_t &pids = m_encryptionPnumToPids[pnum];
1921  if (!pids.empty())
1922  {
1923  std::array<uint,3> enc_cnt { 0, 0, 0 };
1924  for (uint pid2 : pids)
1925  {
1926  CryptStatus stat = m_encryptionPidToInfo[pid2].m_status;
1927  enc_cnt[stat]++;
1928 
1929 #if 0
1930  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1931  QString("\tpnum %1 PID 0x%2 status: %3")
1932  .arg(pnum).arg(pid2,0,16) .arg(toString(stat)));
1933 #endif
1934  }
1935  status = kEncUnknown;
1936 
1937  if (enc_cnt[kEncEncrypted])
1938  status = kEncEncrypted;
1939  else if (enc_cnt[kEncDecrypted] >= std::min((size_t) 2, pids.size()))
1940  status = kEncDecrypted;
1941  }
1942 
1943  if (status == m_encryptionPnumToStatus[pnum])
1944  continue; // program encryption status unchanged
1945 
1946  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Program %1 status: %2")
1947  .arg(pnum).arg(toString(status)));
1948 
1949  m_encryptionPnumToStatus[pnum] = status;
1950 
1951  bool encrypted = kEncUnknown == status || kEncEncrypted == status;
1952  pnumEncrypted[pnum] = encrypted;
1953 
1954  if (kEncDecrypted == status)
1955  pnum_del_list.push_back(pnum);
1956  }
1957 
1958  // Call HandleEncryptionStatus outside the m_encryptionLock
1959  encryptionLock.unlock();
1960  m_listenerLock.lock();
1961  for (auto & pe : pnumEncrypted)
1962  {
1963  for (auto & listener : m_mpegListeners)
1964  {
1965  listener->HandleEncryptionStatus(pe.first, pe.second);
1966  }
1967  }
1968  m_listenerLock.unlock();
1969 
1970  for (size_t i = 0; i < pnum_del_list.size(); i++)
1971  RemoveEncryptionTestPIDs(pnums[i]);
1972 }
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:109
PSStreamListener
Definition: streamlisteners.h:103
TSHeader::PayloadStart
bool PayloadStart(void) const
Definition: tspacket.h:72
kEncEncrypted
@ kEncEncrypted
Definition: mpegstreamdata.h:59
MPEGStreamData::IsProgramDecrypted
bool IsProgramDecrypted(uint pnum) const
Definition: mpegstreamdata.cpp:1856
MPEGStreamData::m_pidsListening
pid_map_t m_pidsListening
Definition: mpegstreamdata.h:323
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:1485
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:50
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:1880
TSPacket::StartOfFieldPointer
unsigned int StartOfFieldPointer(void) const
Definition: tspacket.h:218
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:66
TSHeader::HasPCR
bool HasPCR(void) const
Definition: tspacket.h:104
CryptInfo::m_decryptedMin
uint m_decryptedMin
Definition: mpegstreamdata.h:73
MPEGStreamData::ProcessPMT
void ProcessPMT(const ProgramMapTable *pmt)
Definition: mpegstreamdata.cpp:808
MPEGStreamData::AddMPEGSPListener
void AddMPEGSPListener(MPEGSingleProgramStreamListener *val)
Definition: mpegstreamdata.cpp:1699
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:1521
PSIPTable::IsCurrent
bool IsCurrent(void) const
Definition: mpegtables.h:545
MPEGStreamData::CachePMT
void CachePMT(const ProgramMapTable *pmt)
Definition: mpegstreamdata.cpp:1593
toString
static QString toString(CryptStatus status)
Definition: mpegstreamdata.cpp:1868
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:205
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:1355
PESPacket::tsheader
const TSHeader * tsheader() const
Definition: pespacket.h:92
TSHeader::PID
unsigned int PID(void) const
Definition: tspacket.h:76
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:642
ProgramMapTable::FindPID
int FindPID(uint pid) const
Locates stream index of pid.
Definition: mpegtables.h:797
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:213
MPEGStreamData::RemoveMPEGListener
void RemoveMPEGListener(MPEGStreamListener *val)
Definition: mpegstreamdata.cpp:1618
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:39
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:1226
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:164
TSHeader::Scrambled
bool Scrambled(void) const
Definition: tspacket.h:95
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:1749
MPEGStreamData::ProcessCAT
void ProcessCAT(const ConditionalAccessTable *cat)
Definition: mpegstreamdata.cpp:787
TSPacketListener
Definition: streamlisteners.h:62
MPEGStreamData::IsNotListeningPID
virtual bool IsNotListeningPID(uint pid) const
Definition: mpegstreamdata.cpp:1099
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:1111
MPEGStreamData::m_eitHelper
EITHelper * m_eitHelper
Definition: mpegstreamdata.h:319
MPEGStreamData::IsProgramEncrypted
bool IsProgramEncrypted(uint pnum) const
Definition: mpegstreamdata.cpp:1862
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:1117
MPEGStreamData::ResyncStream
static int ResyncStream(const unsigned char *buffer, int curr_pos, int len)
Definition: mpegstreamdata.cpp:1065
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:1136
MPEGStreamData::CacheCAT
void CacheCAT(const ConditionalAccessTable *_cat)
Definition: mpegstreamdata.cpp:1579
MPEGStreamData::UpdateTimeOffset
void UpdateTimeOffset(uint64_t si_utc_time)
Definition: mpegstreamdata.cpp:839
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
SYNC_BYTE
#define SYNC_BYTE
Definition: tspacket.h:18
TSHeader::ContinuityCounter
unsigned int ContinuityCounter(void) const
Definition: tspacket.h:92
MPEGStreamData::ReturnCachedPATTables
virtual void ReturnCachedPATTables(pat_vec_t &pats) const
Definition: mpegstreamdata.cpp:1470
TSHeader::SetContinuityCounter
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:153
MPEGStreamData::IsListeningPID
virtual bool IsListeningPID(uint pid) const
Definition: mpegstreamdata.cpp:1091
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:1298
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:460
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:1453
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:1232
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:1724
ProgramAssociationTable::TransportStreamID
uint TransportStreamID(void) const
Definition: mpegtables.h:634
MPEGStreamData::IsEncryptionTestPID
bool IsEncryptionTestPID(uint pid) const
Definition: mpegstreamdata.cpp:1809
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:1268
MPEGStreamListener
Definition: streamlisteners.h:81
MPEGStreamData::SetRecordingType
void SetRecordingType(const QString &recording_type)
Definition: mpegstreamdata.cpp:101
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:1327
TSPacket
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:171
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:669
MPEGStreamData::GetCachedCATs
cat_vec_t GetCachedCATs(void) const
Definition: mpegstreamdata.cpp:1397
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: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:72
MPEGStreamData::AddConditionalAccessPID
virtual void AddConditionalAccessPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
Definition: mpegstreamdata.h:131
MPEGStreamData::RemoveWritingListener
void RemoveWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1643
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:1425
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:736
mpegtables.h
MPEGStreamData::GetCachedPMTMap
pmt_map_t GetCachedPMTMap(void) const
Definition: mpegstreamdata.cpp:1439
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:1565
MPEGStreamData::ResetDecryptionMonitoringState
void ResetDecryptionMonitoringState(void)
Definition: mpegstreamdata.cpp:1847
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:172
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:226
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
mpegstreamdata.h
MPEGStreamData::SavePartialPSIP
void SavePartialPSIP(uint pid, PSIPTable *packet)
Definition: mpegstreamdata.cpp:1158
kPIDPriorityHigh
@ kPIDPriorityHigh
Definition: mpegstreamdata.h:81
MPEGStreamData::HasAllPATSections
bool HasAllPATSections(uint tsid) const
Definition: mpegstreamdata.cpp:1172
MPEGStreamData::IncrementRefCnt
void IncrementRefCnt(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1515
MPEGStreamData::GetCachedPMT
pmt_const_ptr_t GetCachedPMT(uint program_num, uint section_num) const
Definition: mpegstreamdata.cpp:1411
MPEGStreamData::AddMPEGListener
void AddMPEGListener(MPEGStreamListener *val)
Definition: mpegstreamdata.cpp:1607
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:1735
MPEGStreamData::AddAVListener
void AddAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1657
MPEGStreamData::ReturnCachedPMTTables
virtual void ReturnCachedPMTTables(pmt_vec_t &pmts) const
Definition: mpegstreamdata.cpp:1500
ProgramMapTable::ProgramInfoLength
uint ProgramInfoLength(void) const
Definition: mpegtables.h:732
VERBOSE_LEVEL_CHECK
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
MPEGStreamData::AddWritingPID
virtual void AddWritingPID(uint pid, PIDPriority priority=kPIDPriorityHigh)
Definition: mpegstreamdata.h:125
MPEGStreamData::IsConditionalAccessPID
virtual bool IsConditionalAccessPID(uint pid) const
Definition: mpegstreamdata.cpp:1085
CryptInfo::m_status
CryptStatus m_status
Definition: mpegstreamdata.h:69
MPEGStreamData::HasCachedAnyPMT
bool HasCachedAnyPMT(uint pnum) const
Definition: mpegstreamdata.cpp:1287
MPEGStreamData::TimeOffset
double TimeOffset(void) const
Current Offset from computer time to DVB time in seconds.
Definition: mpegstreamdata.cpp:825
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:1632
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:1369
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:99
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:1177
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
LOC
#define LOC
Definition: mpegstreamdata.cpp:21
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:19
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:1321
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:1196
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
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:131
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:1678
MPEGStreamData::IsWritingPID
virtual bool IsWritingPID(uint pid) const
Definition: mpegstreamdata.cpp:1105
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:1262
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:77
MPEGStreamData::TestDecryption
void TestDecryption(const ProgramMapTable *pmt)
Definition: mpegstreamdata.cpp:1819
TSHeader::data
const unsigned char * data(void) const
Definition: tspacket.h:157
MPEGStreamData::GetPartialPSIP
PSIPTable * GetPartialPSIP(uint pid)
Definition: mpegstreamdata.h:286
MPEGStreamData::RemoveMPEGSPListener
void RemoveMPEGSPListener(MPEGSingleProgramStreamListener *val)
Definition: mpegstreamdata.cpp:1710
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:1187
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:357
TSHeader::TransportError
bool TransportError(void) const
Definition: tspacket.h:69
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:1182
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:225
MPEGStreamData::RemoveEncryptionTestPIDs
void RemoveEncryptionTestPIDs(uint pnum)
Definition: mpegstreamdata.cpp:1767