MythTV  master
dvbstreamdata.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // Copyright (c) 2003-2004, Daniel Thor Kristjansson
3 #include <algorithm>
4 using namespace std;
5 
6 #include <QSharedPointer>
7 #include "dvbstreamdata.h"
8 #include "dvbtables.h"
9 #include "premieretables.h"
10 #include "eithelper.h"
11 
12 #define PREMIERE_ONID 133
13 #define FREESAT_EIT_PID 3842
14 #define MCA_ONID 6144
15 #define MCA_EIT_TSID 136
16 #define MCA_EIT_PID 1018
17 
18 #define LOC QString("DVBStream[%1]: ").arg(m_cardId)
19 
20 // service_id is synonymous with the MPEG program number in the PMT.
21 DVBStreamData::DVBStreamData(uint desired_netid, uint desired_tsid,
22  int desired_program, int cardnum, bool cacheTables)
23  : MPEGStreamData(desired_program, cardnum, cacheTables),
24  m_desiredNetId(desired_netid), m_desiredTsId(desired_tsid)
25 {
26  m_nitStatus.SetVersion(-1,0);
31 }
32 
34 {
36 
37  QMutexLocker locker(&m_listenerLock);
38  m_dvbMainListeners.clear();
39  m_dvbOtherListeners.clear();
40  m_dvbEitListeners.clear();
41  m_dvbHasEit.clear();
42 }
43 
44 void DVBStreamData::SetDesiredService(uint netid, uint tsid, int serviceid)
45 {
46  bool reset = true;
47 
48  if (HasCachedAllSDT(tsid, true))
49  {
50  sdt_const_ptr_t first_sdt = GetCachedSDT(tsid, 0, true);
51  uint networkID = first_sdt->OriginalNetworkID();
52  if (networkID == netid)
53  {
54  reset = false;
55  m_desiredNetId = netid;
56  m_desiredTsId = tsid;
57  uint last_section = first_sdt->LastSection();
58  ProcessSDT(m_desiredTsId, first_sdt);
59  ReturnCachedTable(first_sdt);
60  for (uint i = 1; i <= last_section; ++i)
61  {
64  ReturnCachedTable(sdt);
65  }
66  SetDesiredProgram(serviceid);
67  }
68  }
69 
70  if (reset)
71  Reset(netid, tsid, serviceid);
72 }
73 
74 
79 bool DVBStreamData::IsRedundant(uint pid, const PSIPTable &psip) const
80 {
81  if (MPEGStreamData::IsRedundant(pid, psip))
82  return true;
83 
84  const int table_id = psip.TableID();
85  const int version = psip.Version();
86 
87  if (TableID::NIT == table_id)
88  {
89  return m_nitStatus.IsSectionSeen(version, psip.Section());
90  }
91 
92  if (TableID::SDT == table_id)
93  {
95  }
96 
97  if (TableID::TDT == table_id)
98  return false;
99 
100  if (TableID::BAT == table_id)
101  {
102  return m_batStatus.IsSectionSeen(psip.TableIDExtension(), version, psip.Section());
103  }
104 
105  bool is_eit = false;
106  if (DVB_EIT_PID == pid || FREESAT_EIT_PID == pid)
107  {
108  // Standard Now/Next Event Information Tables for this transport
109  is_eit |= TableID::PF_EIT == table_id;
110  // Standard Future Event Information Tables for this transport
111  is_eit |= (TableID::SC_EITbeg <= table_id &&
112  TableID::SC_EITend >= table_id);
113  }
114  if (is_eit)
115  {
116  uint service_id = psip.TableIDExtension();
117  uint key = (table_id<<16) | service_id;
118  return m_eitStatus.IsSectionSeen(key, version, psip.Section());
119  }
120 
122  // Other transport tables
123 
124  if (TableID::NITo == table_id)
125  {
126  return m_nitoStatus.IsSectionSeen(version, psip.Section());
127  }
128 
129  if (TableID::SDTo == table_id)
130  {
132  }
133 
134  if (DVB_EIT_PID == pid || FREESAT_EIT_PID == pid || MCA_EIT_PID == pid)
135  {
136  // Standard Now/Next Event Information Tables for other transport
137  is_eit |= TableID::PF_EITo == table_id;
138  // Standard Future Event Information Tables for other transports
139  is_eit |= (TableID::SC_EITbego <= table_id &&
140  TableID::SC_EITendo >= table_id);
141  }
142  if (DVB_DNLONG_EIT_PID == pid || DVB_BVLONG_EIT_PID == pid)
143  {
144  // Dish Network and Bev Long Term Future Event Information
145  // for all transports
146  is_eit |= (TableID::DN_EITbego <= table_id &&
147  TableID::DN_EITendo >= table_id);
148  }
149  if (is_eit)
150  {
151  uint service_id = psip.TableIDExtension();
152  uint key = (table_id<<16) | service_id;
153  return m_eitStatus.IsSectionSeen(key, version, psip.Section());
154  }
155 
156  if (((PREMIERE_EIT_DIREKT_PID == pid) || (PREMIERE_EIT_SPORT_PID == pid)) &&
157  TableID::PREMIERE_CIT == table_id)
158  {
159  uint content_id = PremiereContentInformationTable(psip).ContentID();
160  return m_citStatus.IsSectionSeen(content_id, version, psip.Section());
161  }
162 
163  return false;
164 }
165 
166 void DVBStreamData::Reset(uint desired_netid, uint desired_tsid,
167  int desired_serviceid)
168 {
169  MPEGStreamData::Reset(desired_serviceid);
170 
171  m_desiredNetId = desired_netid;
172  m_desiredTsId = desired_tsid;
173 
174  m_nitStatus.SetVersion(-1,0);
175  m_sdtStatus.clear();
176  m_eitStatus.clear();
177  m_citStatus.clear();
178 
179  m_nitoStatus.SetVersion(-1,0);
180  m_sdtoStatus.clear();
181  m_batStatus.clear();
182 
183  {
184  m_cacheLock.lock();
185 
186  foreach (auto & nit, m_cachedNit)
187  DeleteCachedTable(nit);
188  m_cachedNit.clear();
189 
190  foreach (auto & cached, m_cachedSdts)
191  DeleteCachedTable(cached);
192  m_cachedSdts.clear();
193 
194  foreach (auto & cached, m_cachedBats)
195  DeleteCachedTable(cached);
196  m_cachedBats.clear();
197 
198  m_cacheLock.unlock();
199  }
203 }
204 
209 {
210  if (MPEGStreamData::HandleTables(pid, psip))
211  return true;
212 
213  // If the user specified a network ID and that network ID is a NITo then change that NITo into
214  // the NIT and change the NIT into a NITo. See ticket #7486.
215  if (m_dvbRealNetworkId > 0)
216  {
217  if ((psip.TableID() == TableID::NIT && psip.TableIDExtension() != (uint)m_dvbRealNetworkId) ||
218  (psip.TableID() == TableID::NITo && psip.TableIDExtension() == (uint)m_dvbRealNetworkId) )
219  {
220  auto *nit = new NetworkInformationTable(psip);
221  if (!nit->Mutate())
222  {
223  delete nit;
224  return true;
225  }
226  bool retval = HandleTables(pid, *nit);
227  delete nit;
228  return retval;
229  }
230  }
231 
232  if (IsRedundant(pid, psip))
233  return true;
234 
235  switch (psip.TableID())
236  {
237  case TableID::NIT:
238  {
239  m_nitStatus.SetSectionSeen(psip.Version(), psip.Section(),
240  psip.LastSection());
241 
242  if (m_cacheTables)
243  {
244  auto *nit = new NetworkInformationTable(psip);
245  CacheNIT(nit);
246  QMutexLocker locker(&m_listenerLock);
247  for (auto & listener : m_dvbMainListeners)
248  listener->HandleNIT(nit);
249  }
250  else
251  {
252  NetworkInformationTable nit(psip);
253  QMutexLocker locker(&m_listenerLock);
254  for (auto & listener : m_dvbMainListeners)
255  listener->HandleNIT(&nit);
256  }
257 
258  return true;
259  }
260  case TableID::SDT:
261  {
262  uint tsid = psip.TableIDExtension();
263  m_sdtStatus.SetSectionSeen(tsid, psip.Version(), psip.Section(),
264  psip.LastSection());
265 
266  if (m_cacheTables)
267  {
268  auto *sdt = new ServiceDescriptionTable(psip);
269  CacheSDT(sdt);
270  ProcessSDT(tsid, sdt);
271  }
272  else
273  {
274  ServiceDescriptionTable sdt(psip);
275  ProcessSDT(tsid, &sdt);
276  }
277 
278  return true;
279  }
280  case TableID::TDT:
281  {
282  TimeDateTable tdt(psip);
283 
284  UpdateTimeOffset(tdt.UTCUnix());
285 
286  QMutexLocker locker(&m_listenerLock);
287  for (auto & listener : m_dvbMainListeners)
288  listener->HandleTDT(&tdt);
289 
290  return true;
291  }
292  case TableID::NITo:
293  {
295  psip.LastSection());
296  NetworkInformationTable nit(psip);
297 
298  QMutexLocker locker(&m_listenerLock);
299  for (auto & listener : m_dvbOtherListeners)
300  listener->HandleNITo(&nit);
301 
302  return true;
303  }
304  case TableID::SDTo:
305  {
306  uint tsid = psip.TableIDExtension();
307  m_sdtoStatus.SetSectionSeen(tsid, psip.Version(), psip.Section(),
308  psip.LastSection());
309  ServiceDescriptionTable sdt(psip);
310 
311  // some providers send the SDT for the current multiplex as SDTo
312  // this routine changes the TableID to SDT and recalculates the CRC
313  if (m_desiredNetId == sdt.OriginalNetworkID() &&
314  m_desiredTsId == tsid)
315  {
316  auto *sdta = new ServiceDescriptionTable(psip);
317  if (!sdta->Mutate())
318  {
319  delete sdta;
320  return true;
321  }
322  if (m_cacheTables)
323  {
324  CacheSDT(sdta);
325  ProcessSDT(tsid, sdta);
326  }
327  else
328  {
329  ProcessSDT(tsid, sdta);
330  delete sdta;
331  }
332  return true;
333  }
334 
335  QMutexLocker locker(&m_listenerLock);
336  for (auto & listener : m_dvbOtherListeners)
337  listener->HandleSDTo(tsid, &sdt);
338 
339  return true;
340  }
341  case TableID::BAT:
342  {
343  uint bouquet_id = psip.TableIDExtension();
344  m_batStatus.SetSectionSeen(bouquet_id, psip.Version(), psip.Section(),
345  psip.LastSection());
346 
347  if (m_cacheTables)
348  {
349  auto *bat = new BouquetAssociationTable(psip);
350  CacheBAT(bat);
351  QMutexLocker locker(&m_listenerLock);
352  for (auto & listener : m_dvbOtherListeners)
353  listener->HandleBAT(bat);
354  }
355  else
356  {
357  BouquetAssociationTable bat(psip);
358  QMutexLocker locker(&m_listenerLock);
359  for (auto & listener : m_dvbOtherListeners)
360  listener->HandleBAT(&bat);
361  }
362 
363  return true;
364  }
365  }
366 
367  if ((DVB_EIT_PID == pid || DVB_DNLONG_EIT_PID == pid || FREESAT_EIT_PID == pid ||
369  (MCA_EIT_PID == pid)) || DVB_BVLONG_EIT_PID == pid) &&
370 
372  {
373  QMutexLocker locker(&m_listenerLock);
374  if (m_dvbEitListeners.empty() && !m_eitHelper)
375  return true;
376 
377  uint service_id = psip.TableIDExtension();
378  uint key = (psip.TableID()<<16) | service_id;
379  m_eitStatus.SetSectionSeen(key, psip.Version(), psip.Section(),
380  psip.LastSection());
381 
382  DVBEventInformationTable eit(psip);
383  for (auto & listener : m_dvbEitListeners)
384  listener->HandleEIT(&eit);
385 
386  if (m_eitHelper)
387  m_eitHelper->AddEIT(&eit);
388 
389  return true;
390  }
391 
392  if (m_desiredNetId == PREMIERE_ONID &&
393  (PREMIERE_EIT_DIREKT_PID == pid || PREMIERE_EIT_SPORT_PID == pid) &&
395  {
396  QMutexLocker locker(&m_listenerLock);
397  if (m_dvbEitListeners.empty() && !m_eitHelper)
398  return true;
399 
401  m_citStatus.SetSectionSeen(cit.ContentID(), psip.Version(), psip.Section(), psip.LastSection());
402 
403  for (auto & listener : m_dvbEitListeners)
404  listener->HandleEIT(&cit);
405 
406  if (m_eitHelper)
407  m_eitHelper->AddEIT(&cit);
408 
409  return true;
410  }
411 
412  return false;
413 }
414 
416 {
417  QMutexLocker locker(&m_listenerLock);
418 
419  for (uint i = 0; i < sdt->ServiceCount(); i++)
420  {
421  /*
422  * FIXME always signal EIT presence. We filter later. To many
423  * networks set these flags wrong.
424  * This allows the user to simply set useonairguide on a
425  * channel manually.
426  */
427 #if 0
428  if (sdt->HasEITSchedule(i) || sdt->HasEITPresentFollowing(i))
429 #endif
430  m_dvbHasEit[sdt->ServiceID(i)] = true;
431  }
432 
433  for (auto & listener : m_dvbMainListeners)
434  listener->HandleSDT(tsid, sdt);
435 }
436 
437 bool DVBStreamData::HasEITPIDChanges(const uint_vec_t &in_use_pids) const
438 {
439  QMutexLocker locker(&m_listenerLock);
440  bool want_eit = (m_eitRate >= 0.5F) && HasAnyEIT();
441  bool has_eit = !in_use_pids.empty();
442  return want_eit != has_eit;
443 }
444 
446  uint_vec_t &add_pids,
447  uint_vec_t &del_pids) const
448 {
449  QMutexLocker locker(&m_listenerLock);
450 
451  if ((m_eitRate >= 0.5F) && HasAnyEIT())
452  {
453  if (find(cur_pids.begin(), cur_pids.end(),
454  (uint) DVB_EIT_PID) == cur_pids.end())
455  {
456  add_pids.push_back(DVB_EIT_PID);
457  }
458 
459  if (m_dvbEitDishnetLong &&
460  find(cur_pids.begin(), cur_pids.end(),
461  (uint) DVB_DNLONG_EIT_PID) == cur_pids.end())
462  {
463  add_pids.push_back(DVB_DNLONG_EIT_PID);
464  }
465 
466  if (m_dvbEitDishnetLong &&
467  find(cur_pids.begin(), cur_pids.end(),
468  (uint) DVB_BVLONG_EIT_PID) == cur_pids.end())
469  {
470  add_pids.push_back(DVB_BVLONG_EIT_PID);
471  }
472 
473 #if 0
474  // OpenTV EIT pids
476  {
477  uint pid;
478  for (pid = OTV_EIT_TIT_PID_START; pid <= OTV_EIT_TIT_PID_END; pid++)
479  {
480  if (find(cur_pids.begin(), cur_pids.end(),
481  pid) == cur_pids.end())
482  add_pids.push_back(pid);
483  }
484  for (pid = OTV_EIT_SUP_PID_START; pid <= OTV_EIT_SUP_PID_END; pid++)
485  {
486  if (find(cur_pids.begin(), cur_pids.end(),
487  pid) == cur_pids.end())
488  add_pids.push_back(pid);
489  }
490  }
491 #endif
492 
493  if (m_desiredNetId == PREMIERE_ONID &&
494  find(cur_pids.begin(), cur_pids.end(),
495  (uint) PREMIERE_EIT_DIREKT_PID) == cur_pids.end())
496  {
497  add_pids.push_back(PREMIERE_EIT_DIREKT_PID);
498  }
499 
500  if (m_desiredNetId == PREMIERE_ONID &&
501  find(cur_pids.begin(), cur_pids.end(),
502  (uint) PREMIERE_EIT_SPORT_PID) == cur_pids.end())
503  {
504  add_pids.push_back(PREMIERE_EIT_SPORT_PID);
505  }
506 
507  if (find(cur_pids.begin(), cur_pids.end(),
508  (uint) FREESAT_EIT_PID) == cur_pids.end())
509  {
510  add_pids.push_back(FREESAT_EIT_PID);
511  }
512 
514  find(cur_pids.begin(), cur_pids.end(),
515  (uint) MCA_EIT_PID) == cur_pids.end())
516  {
517  add_pids.push_back(MCA_EIT_PID);
518  }
519 
520  }
521  else
522  {
523  if (find(cur_pids.begin(), cur_pids.end(),
524  (uint) DVB_EIT_PID) != cur_pids.end())
525  {
526  del_pids.push_back(DVB_EIT_PID);
527  }
528 
529  if (m_dvbEitDishnetLong &&
530  find(cur_pids.begin(), cur_pids.end(),
531  (uint) DVB_DNLONG_EIT_PID) != cur_pids.end())
532  {
533  del_pids.push_back(DVB_DNLONG_EIT_PID);
534  }
535 
536  if (m_dvbEitDishnetLong &&
537  find(cur_pids.begin(), cur_pids.end(),
538  (uint) DVB_BVLONG_EIT_PID) != cur_pids.end())
539  {
540  del_pids.push_back(DVB_BVLONG_EIT_PID);
541  }
542 
543 #if 0
544  // OpenTV EIT pids
546  {
547  uint pid;
548  for( pid = OTV_EIT_TIT_PID_START; pid <= OTV_EIT_TIT_PID_END; pid++)
549  {
550  if (find(cur_pids.begin(), cur_pids.end(),
551  pid) != cur_pids.end())
552  del_pids.push_back(pid);
553  }
554  for(pid=OTV_EIT_SUP_PID_START; pid <= OTV_EIT_SUP_PID_END; pid++)
555  {
556  if (find(cur_pids.begin(), cur_pids.end(),
557  pid) != cur_pids.end())
558  del_pids.push_back(pid);
559  }
560  }
561 #endif
562 
563  if (m_desiredNetId == PREMIERE_ONID &&
564  find(cur_pids.begin(), cur_pids.end(),
565  (uint) PREMIERE_EIT_DIREKT_PID) != cur_pids.end())
566  {
567  del_pids.push_back(PREMIERE_EIT_DIREKT_PID);
568  }
569 
570  if (m_desiredNetId == PREMIERE_ONID &&
571  find(cur_pids.begin(), cur_pids.end(),
572  (uint) PREMIERE_EIT_SPORT_PID) != cur_pids.end())
573  {
574  del_pids.push_back(PREMIERE_EIT_SPORT_PID);
575  }
576 
577  if (find(cur_pids.begin(), cur_pids.end(),
578  (uint) FREESAT_EIT_PID) != cur_pids.end())
579  {
580  del_pids.push_back(FREESAT_EIT_PID);
581  }
582 
584  find(cur_pids.begin(), cur_pids.end(),
585  (uint) MCA_EIT_PID) != cur_pids.end())
586  {
587  del_pids.push_back(MCA_EIT_PID);
588  }
589  }
590 
591  return !add_pids.empty() || !del_pids.empty();
592 }
593 
595 {
596  return m_nitStatus.HasAllSections();
597 }
598 
600 {
601  return m_nitoStatus.HasAllSections();
602 }
603 
605 {
606  return m_sdtStatus.HasAllSections(tsid);
607 }
608 
610 {
611  return m_sdtoStatus.HasAllSections(tsid);
612 }
613 
615 {
616  return m_batStatus.HasAllSections(bid);
617 }
618 
620 {
621  QMutexLocker locker(&m_cacheLock);
622 
623  if (!current)
624  LOG(VB_GENERAL, LOG_WARNING, LOC +
625  "Currently we ignore \'current\' param");
626 
627  return (bool)(m_cachedNit.size());
628 }
629 
631 {
632  QMutexLocker locker(&m_cacheLock);
633 
634  if (!current)
635  LOG(VB_GENERAL, LOG_WARNING, LOC +
636  "Currently we ignore \'current\' param");
637 
638  if (m_cachedNit.empty())
639  return false;
640 
641  uint last_section = (*m_cachedNit.begin())->LastSection();
642  if (!last_section)
643  return true;
644 
645  for (uint i = 0; i <= last_section; i++)
646  if (m_cachedNit.find(i) == m_cachedNit.end())
647  return false;
648 
649  return true;
650 }
651 
653 {
654  QMutexLocker locker(&m_cacheLock);
655 
656  if (!current)
657  LOG(VB_GENERAL, LOG_WARNING, LOC +
658  "Currently we ignore \'current\' param");
659 
660  for (uint i = 0; i <= 255; i++)
661  if (m_cachedBats.find((batid << 8) | i) != m_cachedBats.end())
662  return true;
663 
664  return false;
665 }
666 
668 {
669  QMutexLocker locker(&m_cacheLock);
670 
671  if (!current)
672  LOG(VB_GENERAL, LOG_WARNING, LOC +
673  "Currently we ignore \'current\' param");
674 
675  bat_cache_t::const_iterator it = m_cachedBats.find(batid << 8);
676  if (it == m_cachedBats.end())
677  return false;
678 
679  uint last_section = (*it)->LastSection();
680  if (!last_section)
681  return true;
682 
683  for (uint i = 1; i <= last_section; i++)
684  if (m_cachedBats.find((batid << 8) | i) == m_cachedBats.end())
685  return false;
686 
687  return true;
688 }
689 
690 bool DVBStreamData::HasCachedAnyBATs(bool /*current*/) const
691 {
692  QMutexLocker locker(&m_cacheLock);
693  return !m_cachedBats.empty();
694 }
695 
697 {
698  QMutexLocker locker(&m_cacheLock);
699 
700  if (m_cachedBats.empty())
701  return false;
702 
703  for (auto it = m_cachedBats.cbegin(); it != m_cachedBats.cend(); ++it)
704  {
705  if (!HasCachedAllBAT(it.key() >> 8, current))
706  return false;
707  }
708 
709  return true;
710 }
711 
713 {
714  QMutexLocker locker(&m_cacheLock);
715 
716  if (!current)
717  LOG(VB_GENERAL, LOG_WARNING, LOC +
718  "Currently we ignore \'current\' param");
719 
720  sdt_cache_t::const_iterator it = m_cachedSdts.find(tsid << 8);
721  if (it == m_cachedSdts.end())
722  return false;
723 
724  uint last_section = (*it)->LastSection();
725  if (!last_section)
726  return true;
727 
728  for (uint i = 1; i <= last_section; i++)
729  if (m_cachedSdts.find((tsid << 8) | i) == m_cachedSdts.end())
730  return false;
731 
732  return true;
733 }
734 
736 {
737  QMutexLocker locker(&m_cacheLock);
738 
739  if (!current)
740  LOG(VB_GENERAL, LOG_WARNING, LOC +
741  "Currently we ignore \'current\' param");
742 
743  for (uint i = 0; i <= 255; i++)
744  if (m_cachedSdts.find((tsid << 8) | i) != m_cachedSdts.end())
745  return true;
746 
747  return false;
748 }
749 
751 {
752  QMutexLocker locker(&m_cacheLock);
753 
754  if (m_cachedNit.empty())
755  return false;
756 
757  foreach (auto nit, m_cachedNit)
758  {
759  for (uint i = 0; i < nit->TransportStreamCount(); i++)
760  {
761  if (HasCachedAllSDT(nit->TSID(i), current))
762  return true;
763  }
764  }
765 
766  return false;
767 }
768 
769 bool DVBStreamData::HasCachedAnySDTs(bool /*current*/) const
770 {
771  QMutexLocker locker(&m_cacheLock);
772  return !m_cachedSdts.empty();
773 }
774 
776 {
777  QMutexLocker locker(&m_cacheLock);
778 
779  if (m_cachedNit.empty())
780  return false;
781 
782  foreach (auto nit, m_cachedNit)
783  {
784  if ((int)nit->TransportStreamCount() > m_cachedSdts.size())
785  return false;
786 
787  for (uint i = 0; i < nit->TransportStreamCount(); i++)
788  if (!HasCachedAllSDT(nit->TSID(i), current))
789  return false;
790  }
791 
792  return true;
793 }
794 
796  uint section_num, bool current) const
797 {
798  QMutexLocker locker(&m_cacheLock);
799 
800  if (!current)
801  LOG(VB_GENERAL, LOG_WARNING, LOC +
802  "Currently we ignore \'current\' param");
803 
804  nit_ptr_t nit = nullptr;
805 
806  nit_cache_t::const_iterator it = m_cachedNit.find(section_num);
807  if (it != m_cachedNit.end())
808  IncrementRefCnt(nit = *it);
809 
810  return nit;
811 }
812 
814 {
815  QMutexLocker locker(&m_cacheLock);
816 
817  nit_vec_t nits;
818 
819  for (uint i = 0; i < 256; i++)
820  {
822  if (nit)
823  nits.push_back(nit);
824  }
825 
826  return nits;
827 }
828 
830  uint batid, uint section_num, bool current) const
831 {
832  QMutexLocker locker(&m_cacheLock);
833 
834  if (!current)
835  LOG(VB_GENERAL, LOG_WARNING, LOC +
836  "Currently we ignore \'current\' param");
837 
838  bat_ptr_t bat = nullptr;
839 
840  uint key = (batid << 8) | section_num;
841  bat_cache_t::const_iterator it = m_cachedBats.find(key);
842  if (it != m_cachedBats.end())
843  IncrementRefCnt(bat = *it);
844 
845  return bat;
846 }
847 
849 {
850  QMutexLocker locker(&m_cacheLock);
851 
852  if (!current)
853  LOG(VB_GENERAL, LOG_WARNING, LOC +
854  "Currently we ignore \'current\' param");
855 
856  bat_vec_t bats;
857 
858  foreach (auto bat, m_cachedBats)
859  {
860  IncrementRefCnt(bat);
861  bats.push_back(bat);
862  }
863 
864  return bats;
865 }
866 
868  uint tsid, uint section_num, bool current) const
869 {
870  QMutexLocker locker(&m_cacheLock);
871 
872  if (!current)
873  LOG(VB_GENERAL, LOG_WARNING, LOC +
874  "Currently we ignore \'current\' param");
875 
876  sdt_ptr_t sdt = nullptr;
877 
878  uint key = (tsid << 8) | section_num;
879  sdt_cache_t::const_iterator it = m_cachedSdts.find(key);
880  if (it != m_cachedSdts.end())
881  IncrementRefCnt(sdt = *it);
882 
883  return sdt;
884 }
885 
887 {
888  QMutexLocker locker(&m_cacheLock);
889 
890  if (!current)
891  LOG(VB_GENERAL, LOG_WARNING, LOC +
892  "Currently we ignore \'current\' param");
893 
894  sdt_vec_t sdts;
895  sdt_const_ptr_t sdt = GetCachedSDT(tsid, 0);
896 
897  if (sdt)
898  {
899  uint lastSection = sdt->LastSection();
900 
901  sdts.push_back(sdt);
902 
903  for (uint section = 1; section <= lastSection; section++)
904  {
905  sdt = GetCachedSDT(tsid, section);
906 
907  if (sdt)
908  sdts.push_back(sdt);
909  }
910  }
911 
912  return sdts;
913 }
914 
916 {
917  QMutexLocker locker(&m_cacheLock);
918 
919  if (!current)
920  LOG(VB_GENERAL, LOG_WARNING, LOC +
921  "Currently we ignore \'current\' param");
922 
923  sdt_vec_t sdts;
924 
925  foreach (auto sdt, m_cachedSdts)
926  {
927  IncrementRefCnt(sdt);
928  sdts.push_back(sdt);
929  }
930 
931  return sdts;
932 }
933 
935 {
936  for (auto & sdt : sdts)
937  ReturnCachedTable(sdt);
938  sdts.clear();
939 }
940 
942 {
943  if (!psip)
944  return false;
945 
946  uint tid = psip->TableIDExtension(); // For SDTs
947  uint bid = psip->TableIDExtension(); // For BATs
948 
949  QMutexLocker locker(&m_cacheLock);
950  if (m_cachedRefCnt[psip] > 0)
951  {
952  m_cachedSlatedForDeletion[psip] = 1;
953  return false;
954  }
955  if ((TableID::NIT == psip->TableID()) &&
956  m_cachedNit[psip->Section()])
957  {
958  m_cachedNit[psip->Section()] = nullptr;
959  delete psip;
960  }
961  else if ((TableID::SDT == psip->TableID()) &&
962  m_cachedSdts[tid << 8 | psip->Section()])
963  {
964  m_cachedSdts[tid << 8 | psip->Section()] = nullptr;
965  delete psip;
966  }
967  else if ((TableID::BAT == psip->TableID()) &&
968  m_cachedBats[bid << 8 | psip->Section()])
969  {
970  m_cachedBats[bid << 8 | psip->Section()] = nullptr;
971  delete psip;
972  }
973  else
974  {
976  }
977  psip_refcnt_map_t::iterator it;
978  it = m_cachedSlatedForDeletion.find(psip);
979  if (it != m_cachedSlatedForDeletion.end())
980  m_cachedSlatedForDeletion.erase(it);
981 
982  return true;
983 }
984 
986 {
987  QMutexLocker locker(&m_cacheLock);
988 
989  nit_cache_t::iterator it = m_cachedNit.find(nit->Section());
990  if (it != m_cachedNit.end())
991  DeleteCachedTable(*it);
992 
993  m_cachedNit[nit->Section()] = nit;
994 }
995 
997 {
998  uint key = (bat->BouquetID() << 8) | bat->Section();
999 
1000  QMutexLocker locker(&m_cacheLock);
1001 
1002  bat_cache_t::iterator it = m_cachedBats.find(key);
1003  if (it != m_cachedBats.end())
1004  DeleteCachedTable(*it);
1005 
1006  m_cachedBats[key] = bat;
1007 }
1008 
1010 {
1011  uint key = (sdt->TSID() << 8) | sdt->Section();
1012 
1013  QMutexLocker locker(&m_cacheLock);
1014 
1015  sdt_cache_t::iterator it = m_cachedSdts.find(key);
1016  if (it != m_cachedSdts.end())
1017  DeleteCachedTable(*it);
1018 
1019  m_cachedSdts[key] = sdt;
1020 }
1021 
1023 {
1024  QMutexLocker locker(&m_listenerLock);
1025 
1026  for (auto & listener : m_dvbMainListeners)
1027  if (((void*)val) == ((void*)listener))
1028  return;
1029 
1030  m_dvbMainListeners.push_back(val);
1031 }
1032 
1034 {
1035  QMutexLocker locker(&m_listenerLock);
1036 
1037  for (auto it = m_dvbMainListeners.begin(); it != m_dvbMainListeners.end(); ++it)
1038  {
1039  if (((void*)val) == ((void*)*it))
1040  {
1041  m_dvbMainListeners.erase(it);
1042  return;
1043  }
1044  }
1045 }
1046 
1048 {
1049  QMutexLocker locker(&m_listenerLock);
1050 
1051  for (auto & listener : m_dvbOtherListeners)
1052  if (((void*)val) == ((void*)listener))
1053  return;
1054 
1055  m_dvbOtherListeners.push_back(val);
1056 }
1057 
1059 {
1060  QMutexLocker locker(&m_listenerLock);
1061 
1062  for (auto it = m_dvbOtherListeners.begin(); it != m_dvbOtherListeners.end(); ++it)
1063  {
1064  if (((void*)val) == ((void*)*it))
1065  {
1066  m_dvbOtherListeners.erase(it);
1067  return;
1068  }
1069  }
1070 }
1071 
1073 {
1074  QMutexLocker locker(&m_listenerLock);
1075 
1076  for (auto & listener : m_dvbEitListeners)
1077  if (((void*)val) == ((void*)listener))
1078  return;
1079 
1080  m_dvbEitListeners.push_back(val);
1081 }
1082 
1084 {
1085  QMutexLocker locker(&m_listenerLock);
1086 
1087  for (auto it = m_dvbEitListeners.begin(); it != m_dvbEitListeners.end(); ++it)
1088  {
1089  if (((void*)val) == ((void*)*it))
1090  {
1091  m_dvbEitListeners.erase(it);
1092  return;
1093  }
1094  }
1095 }
bool IsSectionSeen(uint32_t key, int32_t version, uint32_t section) const
Definition: tablestatus.cpp:73
uint BouquetID() const
Definition: dvbtables.h:195
bool HasCachedAnyNIT(bool current=true) const
uint Version(void) const
Definition: mpegtables.h:513
virtual void Reset(void)
void RemoveDVBMainListener(DVBMainStreamListener *val)
bool HasAnyEIT(void) const
bool HasAllSections() const
Definition: tablestatus.cpp:49
bool HasEITPresentFollowing(uint i) const
Definition: dvbtables.h:146
dvb_eit_listener_vec_t m_dvbEitListeners
nit_cache_t m_cachedNit
psip_refcnt_map_t m_cachedSlatedForDeletion
bool HasAllSDTSections(uint tsid) const
virtual void ReturnCachedTable(const PSIPTable *psip) const
void SetSectionSeen(int32_t version, uint32_t section, uint32_t last_section, uint32_t segment_last_section=0xffff)
Definition: tablestatus.cpp:30
sdt_vec_t GetCachedSDTSections(uint tsid, bool current=true) const
This table tells the decoder on which PIDs to find A/V data.
Definition: dvbtables.h:101
uint TableIDExtension(void) const
Definition: mpegtables.h:506
#define LOC
bool HasCachedAnyBAT(uint batid, bool current=true) const
BouquetAssociationTable const * bat_const_ptr_t
Definition: dvbstreamdata.h:22
time_t UTCUnix(void) const
Definition: dvbtables.h:393
uint ServiceID(uint i) const
service_id 16 0.0+p
Definition: dvbtables.h:141
#define MCA_EIT_TSID
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)
uint LastSection(void) const
Definition: mpegtables.h:525
#define MCA_ONID
This table gives the current DVB stream time.
Definition: dvbtables.h:373
bool m_dvbEitDishnetLong
Decode DishNet's long-term DVB EIT.
void RemoveDVBEITListener(DVBEITStreamListener *val)
virtual bool HandleTables(uint pid, const PSIPTable &psip)
Process PSIP packets.
#define MCA_EIT_PID
uint TSID() const
transport_stream_id 16 3.0 0x0000
Definition: dvbtables.h:129
bat_const_ptr_t GetCachedBAT(uint batid, uint section_num, bool current=true) const
TableStatus m_nitStatus
DVBStreamData(uint desired_netid, uint desired_tsid, int desired_program, int cardnum, bool cacheTables=false)
vector< uint > uint_vec_t
TableStatusMap m_batStatus
bool HasAllSDToSections(uint tsid) const
void AddDVBEITListener(DVBEITStreamListener *val)
#define PREMIERE_ONID
void AddEIT(uint atsc_major, uint atsc_minor, const EventInformationTable *eit)
Definition: eithelper.cpp:141
virtual bool DeleteCachedTable(const PSIPTable *psip) const
bool HandleTables(uint pid, const PSIPTable &psip) override
Process PSIP packets.
bool HasCachedAllNIT(bool current=true) const
uint Section(void) const
Definition: mpegtables.h:522
TableStatusMap m_sdtStatus
dvb_has_eit_t m_dvbHasEit
Tell us if the DVB service has EIT.
static bool IsEIT(uint table_id)
Definition: dvbtables.cpp:265
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
bool HasAllNIToSections(void) const
bool IsSectionSeen(int32_t version, uint32_t section) const
Definition: tablestatus.cpp:41
uint OriginalNetworkID() const
original_network_id 16 8.0
Definition: dvbtables.h:132
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:386
bool HasEITPIDChanges(const uint_vec_t &in_use_pids) const override
uint m_desiredNetId
DVB table monitoring.
virtual bool IsRedundant(uint pid, const PSIPTable &psip) const
Returns true if table already seen.
sdt_cache_t m_cachedSdts
bool HasCachedAnySDT(uint tsid, bool current=true) const
bool HasAllNITSections(void) const
NetworkInformationTable const * nit_const_ptr_t
Definition: dvbstreamdata.h:11
bool HasCachedSDT(bool current=true) const
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
void SetDesiredProgram(int p)
void CacheBAT(BouquetAssociationTable *bat)
void CacheSDT(ServiceDescriptionTable *sdt)
uint ServiceCount() const
Number of services.
Definition: dvbtables.h:136
dvb_main_listener_vec_t m_dvbMainListeners
bat_vec_t GetCachedBATs(bool current=true) const
bool HasAllSections(uint32_t key) const
Definition: tablestatus.cpp:81
sdt_const_ptr_t GetCachedSDT(uint tsid, uint section_num, bool current=true) const
bool HasCachedAllSDTs(bool current=true) const
unsigned int uint
Definition: compat.h:140
bool IsRedundant(uint pid, const PSIPTable &psip) const override
Returns true if table already seen.
sdt_vec_t GetCachedSDTs(bool current=true) const
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:144
bool GetEITPIDChanges(const uint_vec_t &cur_pids, uint_vec_t &add_pids, uint_vec_t &del_pids) const override
void AddDVBOtherListener(DVBOtherStreamListener *val)
ServiceDescriptionTable const * sdt_const_ptr_t
Definition: dvbstreamdata.h:16
bool HasCachedAllBAT(uint batid, bool current=true) const
bool HasCachedAllBATs(bool current=true) const
void UpdateTimeOffset(uint64_t si_utc_time)
void IncrementRefCnt(const PSIPTable *psip) const
TableStatusMap m_citStatus
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
psip_refcnt_map_t m_cachedRefCnt
vector< const NetworkInformationTable * > nit_vec_t
Definition: dvbstreamdata.h:12
uint TableID(void) const
Definition: mpegtables.h:489
TableStatusMap m_eitStatus
bool HasCachedAnyBATs(bool current=true) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool HasCachedAllSDT(uint tsid, bool current=true) const
nit_const_ptr_t GetCachedNIT(uint section_num, bool current=true) const
static bool IsEIT(uint table_id)
void Reset(void) override
Definition: dvbstreamdata.h:40
dvb_other_listener_vec_t m_dvbOtherListeners
#define FREESAT_EIT_PID
vector< const ServiceDescriptionTable * > sdt_vec_t
Definition: dvbstreamdata.h:17
TableStatus m_nitoStatus
void CacheNIT(NetworkInformationTable *nit)
bool HasAllBATSections(uint bid) const
bat_cache_t m_cachedBats
bool DeleteCachedTable(const PSIPTable *psip) const override
Tells what channels can be found on each transponder for one bouquet (a bunch of channels from one pr...
Definition: dvbtables.h:179
TableStatusMap m_sdtoStatus
bool HasCachedAnySDTs(bool current=true) const
void RemoveDVBOtherListener(DVBOtherStreamListener *val)
void AddDVBMainListener(DVBMainStreamListener *val)
void SetDesiredService(uint netid, uint tsid, int serviceid)
EITHelper * m_eitHelper
void ReturnCachedSDTTables(sdt_vec_t &sdts) const
This table tells the decoder on which PIDs to find other tables.
Definition: dvbtables.h:21
void SetVersion(int32_t version, uint32_t last_section)
Definition: tablestatus.cpp:21
void ProcessSDT(uint tsid, const ServiceDescriptionTable *sdt)
Encapsulates data about MPEG stream and emits events for each table.
~DVBStreamData() override
vector< const BouquetAssociationTable * > bat_vec_t
Definition: dvbstreamdata.h:23