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