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