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
5#include <QSharedPointer>
6#include "dvbstreamdata.h"
7
9
10#include "dvbtables.h"
11#include "mpegdescriptors.h"
12#include "mpegtables.h"
13#include "premieretables.h"
14#include "eithelper.h"
15
16static constexpr uint8_t MCA_EIT_TSID { 136 };
17
18#define LOC QString("DVBStream[%1]: ").arg(m_cardId)
19
20// service_id is synonymous with the MPEG program number in the PMT.
21DVBStreamData::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{
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}
44void 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 {
65 }
66 SetDesiredProgram(serviceid);
67 }
68 }
69
70 if (reset)
71 Reset(netid, tsid, serviceid);
72}
73
74
79bool 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 {
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 {
103 }
104
105 bool is_eit = false;
106 if (PID::DVB_EIT_PID == 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 {
127 }
128
129 if (TableID::SDTo == table_id)
130 {
132 }
133
134 if (PID::DVB_EIT_PID == pid || PID::FREESAT_EIT_PID == 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 }
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
157 TableID::PREMIERE_CIT == table_id)
158 {
160 return m_citStatus.IsSectionSeen(content_id, version, psip.Section());
161 }
162
163 return false;
164}
165
166void 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
175 m_sdtStatus.clear();
176 m_eitStatus.clear();
177 m_citStatus.clear();
178
180 m_sdtoStatus.clear();
181 m_batStatus.clear();
182
183 {
184 m_cacheLock.lock();
185
186 for (const auto & nit : std::as_const(m_cachedNit))
188 m_cachedNit.clear();
189
190 for (const auto & cached : std::as_const(m_cachedSdts))
191 DeleteCachedTable(cached);
192 m_cachedSdts.clear();
193
194 for (const auto & cached : std::as_const(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) ||
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 {
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
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 ((PID::DVB_EIT_PID == pid || PID::DVB_DNLONG_EIT_PID == pid || PID::FREESAT_EIT_PID == pid ||
369 (PID::MCA_EIT_PID == 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
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
437bool 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) PID::DVB_EIT_PID) == cur_pids.end())
455 {
456 add_pids.push_back(PID::DVB_EIT_PID);
457 }
458
460 find(cur_pids.begin(), cur_pids.end(),
461 (uint) PID::DVB_DNLONG_EIT_PID) == cur_pids.end())
462 {
463 add_pids.push_back(PID::DVB_DNLONG_EIT_PID);
464 }
465
467 find(cur_pids.begin(), cur_pids.end(),
468 (uint) PID::DVB_BVLONG_EIT_PID) == cur_pids.end())
469 {
470 add_pids.push_back(PID::DVB_BVLONG_EIT_PID);
471 }
472
473#if 0
474 // OpenTV EIT pids
476 {
478 {
479 if (find(cur_pids.begin(), cur_pids.end(),
480 pid) == cur_pids.end())
481 add_pids.push_back(pid);
482 }
484 {
485 if (find(cur_pids.begin(), cur_pids.end(),
486 pid) == cur_pids.end())
487 add_pids.push_back(pid);
488 }
489 }
490#endif
491
493 find(cur_pids.begin(), cur_pids.end(),
494 (uint) PID::PREMIERE_EIT_DIREKT_PID) == cur_pids.end())
495 {
496 add_pids.push_back(PID::PREMIERE_EIT_DIREKT_PID);
497 }
498
500 find(cur_pids.begin(), cur_pids.end(),
501 (uint) PID::PREMIERE_EIT_SPORT_PID) == cur_pids.end())
502 {
503 add_pids.push_back(PID::PREMIERE_EIT_SPORT_PID);
504 }
505
507 find(cur_pids.begin(), cur_pids.end(),
508 (uint) PID::FREESAT_EIT_PID) == cur_pids.end())
509 {
510 add_pids.push_back(PID::FREESAT_EIT_PID);
511 }
512
514 find(cur_pids.begin(), cur_pids.end(),
515 (uint) PID::MCA_EIT_PID) == cur_pids.end())
516 {
517 add_pids.push_back(PID::MCA_EIT_PID);
518 }
519
520 }
521 else
522 {
523 if (find(cur_pids.begin(), cur_pids.end(),
524 (uint) PID::DVB_EIT_PID) != cur_pids.end())
525 {
526 del_pids.push_back(PID::DVB_EIT_PID);
527 }
528
530 find(cur_pids.begin(), cur_pids.end(),
531 (uint) PID::DVB_DNLONG_EIT_PID) != cur_pids.end())
532 {
533 del_pids.push_back(PID::DVB_DNLONG_EIT_PID);
534 }
535
537 find(cur_pids.begin(), cur_pids.end(),
538 (uint) PID::DVB_BVLONG_EIT_PID) != cur_pids.end())
539 {
540 del_pids.push_back(PID::DVB_BVLONG_EIT_PID);
541 }
542
543#if 0
544 // OpenTV EIT pids
546 {
548 {
549 if (find(cur_pids.begin(), cur_pids.end(),
550 pid) != cur_pids.end())
551 del_pids.push_back(pid);
552 }
554 {
555 if (find(cur_pids.begin(), cur_pids.end(),
556 pid) != cur_pids.end())
557 del_pids.push_back(pid);
558 }
559 }
560#endif
561
563 find(cur_pids.begin(), cur_pids.end(),
564 (uint) PID::PREMIERE_EIT_DIREKT_PID) != cur_pids.end())
565 {
566 del_pids.push_back(PID::PREMIERE_EIT_DIREKT_PID);
567 }
568
570 find(cur_pids.begin(), cur_pids.end(),
571 (uint) PID::PREMIERE_EIT_SPORT_PID) != cur_pids.end())
572 {
573 del_pids.push_back(PID::PREMIERE_EIT_SPORT_PID);
574 }
575
577 find(cur_pids.begin(), cur_pids.end(),
578 (uint) PID::FREESAT_EIT_PID) != cur_pids.end())
579 {
580 del_pids.push_back(PID::FREESAT_EIT_PID);
581 }
582
584 find(cur_pids.begin(), cur_pids.end(),
585 (uint) PID::MCA_EIT_PID) != cur_pids.end())
586 {
587 del_pids.push_back(PID::MCA_EIT_PID);
588 }
589 }
590
591 return !add_pids.empty() || !del_pids.empty();
592}
593
595{
597}
598
600{
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 !m_cachedNit.empty();
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.contains(i))
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.contains((batid << 8) | i))
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.constFind(batid << 8);
676 if (it == m_cachedBats.constEnd())
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.constFind((batid << 8) | i) == m_cachedBats.constEnd())
685 return false;
686
687 return true;
688}
689
690bool 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.constFind(tsid << 8);
721 if (it == m_cachedSdts.constEnd())
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.constFind((tsid << 8) | i) == m_cachedSdts.constEnd())
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.contains((tsid << 8) | i))
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 for (auto *nit : std::as_const(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
769bool 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 for (auto *nit : std::as_const(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.constFind(section_num);
807 if (it != m_cachedNit.constEnd())
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.constFind(key);
842 if (it != m_cachedBats.constEnd())
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 for (auto *bat : std::as_const(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.constFind(key);
880 if (it != m_cachedSdts.constEnd())
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 for (auto *sdt : std::as_const(m_cachedSdts))
926 {
927 IncrementRefCnt(sdt);
928 sdts.push_back(sdt);
929 }
930
931 return sdts;
932}
933
935{
936 for (auto & sdt : sdts)
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 {
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())
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())
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 if (std::any_of(m_dvbMainListeners.cbegin(), m_dvbMainListeners.cend(),
1027 [val](auto & listener){ return val == 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 if (std::any_of(m_dvbOtherListeners.cbegin(), m_dvbOtherListeners.cend(),
1052 [val](auto & listener){ return val == 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 if (std::any_of(m_dvbEitListeners.cbegin(), m_dvbEitListeners.cend(),
1077 [val](auto & listener){ return val == 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}
Tells what channels can be found on each transponder for one bouquet (a bunch of channels from one pr...
Definition: dvbtables.h:193
uint BouquetID() const
Definition: dvbtables.h:208
static bool IsEIT(uint table_id)
Definition: dvbtables.cpp:282
uint m_desiredNetId
DVB table monitoring.
void AddDVBOtherListener(DVBOtherStreamListener *val)
bool GetEITPIDChanges(const uint_vec_t &cur_pids, uint_vec_t &add_pids, uint_vec_t &del_pids) const override
void Reset(void) override
Definition: dvbstreamdata.h:41
bool HasAllSDToSections(uint tsid) const
void RemoveDVBMainListener(DVBMainStreamListener *val)
TableStatusMap m_eitStatus
bool HasAllSDTSections(uint tsid) const
TableStatus m_nitStatus
TableStatusMap m_sdtStatus
bool IsRedundant(uint pid, const PSIPTable &psip) const override
Returns true if table already seen.
sdt_vec_t GetCachedSDTSections(uint tsid, bool current=true) const
bool HasAnyEIT(void) const
bool HasCachedAnySDTs(bool current=true) const
bool HasAllBATSections(uint bid) const
void CacheNIT(NetworkInformationTable *nit)
bool DeleteCachedTable(const PSIPTable *psip) const override
void AddDVBEITListener(DVBEITStreamListener *val)
sdt_vec_t GetCachedSDTs(bool current=true) const
bool HasCachedAnyBATs(bool current=true) const
bool m_dvbEitDishnetLong
Decode DishNet's long-term DVB EIT.
dvb_other_listener_vec_t m_dvbOtherListeners
dvb_has_eit_t m_dvbHasEit
Tell us if the DVB service has EIT.
bool HasAllNIToSections(void) const
TableStatusMap m_sdtoStatus
sdt_cache_t m_cachedSdts
nit_cache_t m_cachedNit
void RemoveDVBOtherListener(DVBOtherStreamListener *val)
bool HasCachedAllBATs(bool current=true) const
TableStatus m_nitoStatus
bool HasCachedAnySDT(uint tsid, bool current=true) const
void SetDesiredService(uint netid, uint tsid, int serviceid)
bool HasCachedAnyNIT(bool current=true) const
bat_cache_t m_cachedBats
bool HandleTables(uint pid, const PSIPTable &psip) override
Process PSIP packets.
bool HasCachedAllBAT(uint batid, bool current=true) const
bool HasAllNITSections(void) const
void AddDVBMainListener(DVBMainStreamListener *val)
bat_vec_t GetCachedBATs(bool current=true) const
sdt_const_ptr_t GetCachedSDT(uint tsid, uint section_num, bool current=true) const
bool HasCachedAllSDT(uint tsid, bool current=true) const
bool HasCachedAllSDTs(bool current=true) const
bool HasCachedAnyBAT(uint batid, bool current=true) const
void CacheBAT(BouquetAssociationTable *bat)
bat_const_ptr_t GetCachedBAT(uint batid, uint section_num, bool current=true) const
void RemoveDVBEITListener(DVBEITStreamListener *val)
TableStatusMap m_citStatus
bool HasCachedSDT(bool current=true) const
TableStatusMap m_batStatus
DVBStreamData(uint desired_netid, uint desired_tsid, int desired_program, int cardnum, bool cacheTables=false)
void ReturnCachedSDTTables(sdt_vec_t &sdts) const
dvb_eit_listener_vec_t m_dvbEitListeners
nit_const_ptr_t GetCachedNIT(uint section_num, bool current=true) const
~DVBStreamData() override
bool HasEITPIDChanges(const uint_vec_t &in_use_pids) const override
dvb_main_listener_vec_t m_dvbMainListeners
void CacheSDT(ServiceDescriptionTable *sdt)
bool HasCachedAllNIT(bool current=true) const
void ProcessSDT(uint tsid, const ServiceDescriptionTable *sdt)
void AddEIT(uint, uint, const EventInformationTable *)
Definition: eithelper.h:122
Encapsulates data about MPEG stream and emits events for each table.
void SetDesiredProgram(int p)
QRecursiveMutex m_listenerLock
psip_refcnt_map_t m_cachedSlatedForDeletion
void UpdateTimeOffset(uint64_t si_utc_time)
EITHelper * m_eitHelper
QRecursiveMutex m_cacheLock
virtual bool DeleteCachedTable(const PSIPTable *psip) const
psip_refcnt_map_t m_cachedRefCnt
virtual bool IsRedundant(uint pid, const PSIPTable &psip) const
Returns true if table already seen.
virtual void ReturnCachedTable(const PSIPTable *psip) const
virtual void Reset(void)
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
virtual bool HandleTables(uint pid, const PSIPTable &psip)
Process PSIP packets.
void IncrementRefCnt(const PSIPTable *psip) const
This table tells the decoder on which PIDs to find other tables.
Definition: dvbtables.h:34
@ OTV_EIT_SUP_PID_END
Definition: mpegtables.h:252
@ DVB_DNLONG_EIT_PID
Definition: mpegtables.h:222
@ OTV_EIT_SUP_PID_START
Definition: mpegtables.h:251
@ DVB_EIT_PID
Definition: mpegtables.h:217
@ PREMIERE_EIT_DIREKT_PID
Definition: mpegtables.h:231
@ MCA_EIT_PID
Definition: mpegtables.h:228
@ DVB_TDT_PID
Definition: mpegtables.h:219
@ OTV_EIT_TIT_PID_END
Definition: mpegtables.h:250
@ DVB_BVLONG_EIT_PID
Definition: mpegtables.h:225
@ OTV_EIT_TIT_PID_START
Definition: mpegtables.h:249
@ DVB_SDT_PID
Definition: mpegtables.h:216
@ PREMIERE_EIT_SPORT_PID
Definition: mpegtables.h:232
@ DVB_NIT_PID
Definition: mpegtables.h:215
@ FREESAT_EIT_PID
Definition: mpegtables.h:241
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:410
uint LastSection(void) const
Definition: mpegtables.h:534
uint Version(void) const
Definition: mpegtables.h:522
uint TableID(void) const
Definition: mpegtables.h:496
uint Section(void) const
Definition: mpegtables.h:531
uint TableIDExtension(void) const
Definition: mpegtables.h:515
static bool IsEIT(uint table_id)
This table tells the decoder on which PIDs to find A/V data.
Definition: dvbtables.h:114
uint TSID() const
transport_stream_id 16 3.0 0x0000
Definition: dvbtables.h:141
bool HasEITPresentFollowing(uint i) const
Definition: dvbtables.h:158
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:156
uint ServiceID(uint i) const
service_id 16 0.0+p
Definition: dvbtables.h:153
uint ServiceCount() const
Number of services.
Definition: dvbtables.h:148
uint OriginalNetworkID() const
original_network_id 16 8.0
Definition: dvbtables.h:144
@ DN_EITbego
Definition: mpegtables.h:314
@ SC_EITbeg
Definition: mpegtables.h:280
@ SC_EITend
Definition: mpegtables.h:281
@ DN_EITendo
Definition: mpegtables.h:315
@ SC_EITendo
Definition: mpegtables.h:283
@ PREMIERE_CIT
Definition: mpegtables.h:389
@ SC_EITbego
Definition: mpegtables.h:282
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 IsSectionSeen(uint32_t key, int32_t version, uint32_t section) const
Definition: tablestatus.cpp:73
bool HasAllSections(uint32_t key) const
Definition: tablestatus.cpp:81
void SetVersion(int32_t version, uint32_t last_section)
Definition: tablestatus.cpp:21
void SetSectionSeen(int32_t version, uint32_t section, uint32_t last_section, uint32_t segment_last_section=0xffff)
Definition: tablestatus.cpp:30
bool IsSectionSeen(int32_t version, uint32_t section) const
Definition: tablestatus.cpp:41
bool HasAllSections() const
Definition: tablestatus.cpp:49
This table gives the current DVB stream time.
Definition: dvbtables.h:387
time_t UTCUnix(void) const
Definition: dvbtables.h:406
#define LOC
static constexpr uint8_t MCA_EIT_TSID
ServiceDescriptionTable const * sdt_const_ptr_t
Definition: dvbstreamdata.h:17
std::vector< const ServiceDescriptionTable * > sdt_vec_t
Definition: dvbstreamdata.h:18
std::vector< const NetworkInformationTable * > nit_vec_t
Definition: dvbstreamdata.h:13
std::vector< const BouquetAssociationTable * > bat_vec_t
Definition: dvbstreamdata.h:24
NetworkInformationTable const * nit_const_ptr_t
Definition: dvbstreamdata.h:12
BouquetAssociationTable const * bat_const_ptr_t
Definition: dvbstreamdata.h:23
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)
unsigned int uint
Definition: freesurround.h:24
std::vector< uint > uint_vec_t
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
string version
Definition: giantbomb.py:185