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#ifdef __cpp_lib_ranges_contains
454 if (!std::ranges::contains(cur_pids, PID::DVB_EIT_PID))
455#else
456 if (std::ranges::find(cur_pids,
457 (uint) PID::DVB_EIT_PID) == cur_pids.end())
458#endif
459 {
460 add_pids.push_back(PID::DVB_EIT_PID);
461 }
462
464#ifdef __cpp_lib_ranges_contains
465 !std::ranges::contains(cur_pids, PID::DVB_DNLONG_EIT_PID))
466#else
467 std::ranges::find(cur_pids,
468 (uint) PID::DVB_DNLONG_EIT_PID) == cur_pids.end())
469#endif
470 {
471 add_pids.push_back(PID::DVB_DNLONG_EIT_PID);
472 }
473
475#ifdef __cpp_lib_ranges_contains
476 !std::ranges::contains(cur_pids, PID::DVB_BVLONG_EIT_PID))
477#else
478 std::ranges::find(cur_pids,
479 (uint) PID::DVB_BVLONG_EIT_PID) == cur_pids.end())
480#endif
481 {
482 add_pids.push_back(PID::DVB_BVLONG_EIT_PID);
483 }
484
485#if 0
486 // OpenTV EIT pids
488 {
490 {
491#ifdef __cpp_lib_ranges_contains
492 if (!std::ranges::contains(cur_pids, pid))
493#else
494 if (std::ranges::find(cur_pids,
495 pid) == cur_pids.end())
496#endif
497 add_pids.push_back(pid);
498 }
500 {
501#ifdef __cpp_lib_ranges_contains
502 if (!std::ranges::contains(cur_pids, pid))
503#else
504 if (std::ranges::find(cur_pids,
505 pid) == cur_pids.end())
506#endif
507 add_pids.push_back(pid);
508 }
509 }
510#endif
511
513#ifdef __cpp_lib_ranges_contains
514 !std::ranges::contains(cur_pids, PID::PREMIERE_EIT_DIREKT_PID))
515#else
516 std::ranges::find(cur_pids,
517 (uint) PID::PREMIERE_EIT_DIREKT_PID) == cur_pids.end())
518#endif
519 {
520 add_pids.push_back(PID::PREMIERE_EIT_DIREKT_PID);
521 }
522
524#ifdef __cpp_lib_ranges_contains
525 !std::ranges::contains(cur_pids, PID::PREMIERE_EIT_SPORT_PID))
526#else
527 std::ranges::find(cur_pids,
528 (uint) PID::PREMIERE_EIT_SPORT_PID) == cur_pids.end())
529#endif
530 {
531 add_pids.push_back(PID::PREMIERE_EIT_SPORT_PID);
532 }
533
535#ifdef __cpp_lib_ranges_contains
536 !std::ranges::contains(cur_pids, PID::FREESAT_EIT_PID))
537#else
538 std::ranges::find(cur_pids,
539 (uint) PID::FREESAT_EIT_PID) == cur_pids.end())
540#endif
541 {
542 add_pids.push_back(PID::FREESAT_EIT_PID);
543 }
544
546#ifdef __cpp_lib_ranges_contains
547 !std::ranges::contains(cur_pids, PID::MCA_EIT_PID))
548#else
549 std::ranges::find(cur_pids,
550 (uint) PID::MCA_EIT_PID) == cur_pids.end())
551#endif
552 {
553 add_pids.push_back(PID::MCA_EIT_PID);
554 }
555
556 }
557 else
558 {
559#ifdef __cpp_lib_ranges_contains
560 if (std::ranges::contains(cur_pids, PID::DVB_EIT_PID))
561#else
562 if (std::ranges::find(cur_pids,
563 (uint) PID::DVB_EIT_PID) != cur_pids.end())
564#endif
565 {
566 del_pids.push_back(PID::DVB_EIT_PID);
567 }
568
570#ifdef __cpp_lib_ranges_contains
571 std::ranges::contains(cur_pids, PID::DVB_DNLONG_EIT_PID))
572#else
573 std::ranges::find(cur_pids,
574 (uint) PID::DVB_DNLONG_EIT_PID) != cur_pids.end())
575#endif
576 {
577 del_pids.push_back(PID::DVB_DNLONG_EIT_PID);
578 }
579
581#ifdef __cpp_lib_ranges_contains
582 std::ranges::contains(cur_pids, PID::DVB_BVLONG_EIT_PID))
583#else
584 std::ranges::find(cur_pids,
585 (uint) PID::DVB_BVLONG_EIT_PID) != cur_pids.end())
586#endif
587 {
588 del_pids.push_back(PID::DVB_BVLONG_EIT_PID);
589 }
590
591#if 0
592 // OpenTV EIT pids
594 {
596 {
597#ifdef __cpp_lib_ranges_contains
598 if (std::ranges::contains(cur_pids, pid))
599#else
600 if (std::ranges::find(cur_pids,
601 pid) != cur_pids.end())
602#endif
603 del_pids.push_back(pid);
604 }
606 {
607#ifdef __cpp_lib_ranges_contains
608 if (std::ranges::contains(cur_pids, pid))
609#else
610 if (std::ranges::find(cur_pids,
611 pid) != cur_pids.end())
612#endif
613 del_pids.push_back(pid);
614 }
615 }
616#endif
617
619#ifdef __cpp_lib_ranges_contains
620 std::ranges::contains(cur_pids, PID::PREMIERE_EIT_DIREKT_PID))
621#else
622 std::ranges::find(cur_pids,
623 (uint) PID::PREMIERE_EIT_DIREKT_PID) != cur_pids.end())
624#endif
625 {
626 del_pids.push_back(PID::PREMIERE_EIT_DIREKT_PID);
627 }
628
630#ifdef __cpp_lib_ranges_contains
631 std::ranges::contains(cur_pids, PID::PREMIERE_EIT_SPORT_PID))
632#else
633 std::ranges::find(cur_pids,
634 (uint) PID::PREMIERE_EIT_SPORT_PID) != cur_pids.end())
635#endif
636 {
637 del_pids.push_back(PID::PREMIERE_EIT_SPORT_PID);
638 }
639
641#ifdef __cpp_lib_ranges_contains
642 std::ranges::contains(cur_pids, PID::FREESAT_EIT_PID))
643#else
644 std::ranges::find(cur_pids,
645 (uint) PID::FREESAT_EIT_PID) != cur_pids.end())
646#endif
647 {
648 del_pids.push_back(PID::FREESAT_EIT_PID);
649 }
650
652#ifdef __cpp_lib_ranges_contains
653 std::ranges::contains(cur_pids, PID::MCA_EIT_PID))
654#else
655 std::ranges::find(cur_pids,
656 (uint) PID::MCA_EIT_PID) != cur_pids.end())
657#endif
658 {
659 del_pids.push_back(PID::MCA_EIT_PID);
660 }
661 }
662
663 return !add_pids.empty() || !del_pids.empty();
664}
665
667{
669}
670
672{
674}
675
677{
678 return m_sdtStatus.HasAllSections(tsid);
679}
680
682{
683 return m_sdtoStatus.HasAllSections(tsid);
684}
685
687{
688 return m_batStatus.HasAllSections(bid);
689}
690
692{
693 QMutexLocker locker(&m_cacheLock);
694
695 if (!current)
696 LOG(VB_GENERAL, LOG_WARNING, LOC +
697 "Currently we ignore \'current\' param");
698
699 return !m_cachedNit.empty();
700}
701
703{
704 QMutexLocker locker(&m_cacheLock);
705
706 if (!current)
707 LOG(VB_GENERAL, LOG_WARNING, LOC +
708 "Currently we ignore \'current\' param");
709
710 if (m_cachedNit.empty())
711 return false;
712
713 uint last_section = (*m_cachedNit.begin())->LastSection();
714 if (!last_section)
715 return true;
716
717 for (uint i = 0; i <= last_section; i++)
718 if (!m_cachedNit.contains(i))
719 return false;
720
721 return true;
722}
723
725{
726 QMutexLocker locker(&m_cacheLock);
727
728 if (!current)
729 LOG(VB_GENERAL, LOG_WARNING, LOC +
730 "Currently we ignore \'current\' param");
731
732 for (uint i = 0; i <= 255; i++)
733 if (m_cachedBats.contains((batid << 8) | i))
734 return true;
735
736 return false;
737}
738
740{
741 QMutexLocker locker(&m_cacheLock);
742
743 if (!current)
744 LOG(VB_GENERAL, LOG_WARNING, LOC +
745 "Currently we ignore \'current\' param");
746
747 bat_cache_t::const_iterator it = m_cachedBats.constFind(batid << 8);
748 if (it == m_cachedBats.constEnd())
749 return false;
750
751 uint last_section = (*it)->LastSection();
752 if (!last_section)
753 return true;
754
755 for (uint i = 1; i <= last_section; i++)
756 if (m_cachedBats.constFind((batid << 8) | i) == m_cachedBats.constEnd())
757 return false;
758
759 return true;
760}
761
762bool DVBStreamData::HasCachedAnyBATs(bool /*current*/) const
763{
764 QMutexLocker locker(&m_cacheLock);
765 return !m_cachedBats.empty();
766}
767
769{
770 QMutexLocker locker(&m_cacheLock);
771
772 if (m_cachedBats.empty())
773 return false;
774
775 for (auto it = m_cachedBats.cbegin(); it != m_cachedBats.cend(); ++it)
776 {
777 if (!HasCachedAllBAT(it.key() >> 8, current))
778 return false;
779 }
780
781 return true;
782}
783
785{
786 QMutexLocker locker(&m_cacheLock);
787
788 if (!current)
789 LOG(VB_GENERAL, LOG_WARNING, LOC +
790 "Currently we ignore \'current\' param");
791
792 sdt_cache_t::const_iterator it = m_cachedSdts.constFind(tsid << 8);
793 if (it == m_cachedSdts.constEnd())
794 return false;
795
796 uint last_section = (*it)->LastSection();
797 if (!last_section)
798 return true;
799
800 for (uint i = 1; i <= last_section; i++)
801 if (m_cachedSdts.constFind((tsid << 8) | i) == m_cachedSdts.constEnd())
802 return false;
803
804 return true;
805}
806
808{
809 QMutexLocker locker(&m_cacheLock);
810
811 if (!current)
812 LOG(VB_GENERAL, LOG_WARNING, LOC +
813 "Currently we ignore \'current\' param");
814
815 for (uint i = 0; i <= 255; i++)
816 if (m_cachedSdts.contains((tsid << 8) | i))
817 return true;
818
819 return false;
820}
821
823{
824 QMutexLocker locker(&m_cacheLock);
825
826 if (m_cachedNit.empty())
827 return false;
828
829 for (auto *nit : std::as_const(m_cachedNit))
830 {
831 for (uint i = 0; i < nit->TransportStreamCount(); i++)
832 {
833 if (HasCachedAllSDT(nit->TSID(i), current))
834 return true;
835 }
836 }
837
838 return false;
839}
840
841bool DVBStreamData::HasCachedAnySDTs(bool /*current*/) const
842{
843 QMutexLocker locker(&m_cacheLock);
844 return !m_cachedSdts.empty();
845}
846
848{
849 QMutexLocker locker(&m_cacheLock);
850
851 if (m_cachedNit.empty())
852 return false;
853
854 for (auto *nit : std::as_const(m_cachedNit))
855 {
856 if ((int)nit->TransportStreamCount() > m_cachedSdts.size())
857 return false;
858
859 for (uint i = 0; i < nit->TransportStreamCount(); i++)
860 if (!HasCachedAllSDT(nit->TSID(i), current))
861 return false;
862 }
863
864 return true;
865}
866
868 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 nit_ptr_t nit = nullptr;
877
878 nit_cache_t::const_iterator it = m_cachedNit.constFind(section_num);
879 if (it != m_cachedNit.constEnd())
880 IncrementRefCnt(nit = *it);
881
882 return nit;
883}
884
886{
887 QMutexLocker locker(&m_cacheLock);
888
889 nit_vec_t nits;
890
891 for (uint i = 0; i < 256; i++)
892 {
894 if (nit)
895 nits.push_back(nit);
896 }
897
898 return nits;
899}
900
902 uint batid, uint section_num, bool current) const
903{
904 QMutexLocker locker(&m_cacheLock);
905
906 if (!current)
907 LOG(VB_GENERAL, LOG_WARNING, LOC +
908 "Currently we ignore \'current\' param");
909
910 bat_ptr_t bat = nullptr;
911
912 uint key = (batid << 8) | section_num;
913 bat_cache_t::const_iterator it = m_cachedBats.constFind(key);
914 if (it != m_cachedBats.constEnd())
915 IncrementRefCnt(bat = *it);
916
917 return bat;
918}
919
921{
922 QMutexLocker locker(&m_cacheLock);
923
924 if (!current)
925 LOG(VB_GENERAL, LOG_WARNING, LOC +
926 "Currently we ignore \'current\' param");
927
928 bat_vec_t bats;
929
930 for (auto *bat : std::as_const(m_cachedBats))
931 {
932 IncrementRefCnt(bat);
933 bats.push_back(bat);
934 }
935
936 return bats;
937}
938
940 uint tsid, uint section_num, bool current) const
941{
942 QMutexLocker locker(&m_cacheLock);
943
944 if (!current)
945 LOG(VB_GENERAL, LOG_WARNING, LOC +
946 "Currently we ignore \'current\' param");
947
948 sdt_ptr_t sdt = nullptr;
949
950 uint key = (tsid << 8) | section_num;
951 sdt_cache_t::const_iterator it = m_cachedSdts.constFind(key);
952 if (it != m_cachedSdts.constEnd())
953 IncrementRefCnt(sdt = *it);
954
955 return sdt;
956}
957
959{
960 QMutexLocker locker(&m_cacheLock);
961
962 if (!current)
963 LOG(VB_GENERAL, LOG_WARNING, LOC +
964 "Currently we ignore \'current\' param");
965
966 sdt_vec_t sdts;
967 sdt_const_ptr_t sdt = GetCachedSDT(tsid, 0);
968
969 if (sdt)
970 {
971 uint lastSection = sdt->LastSection();
972
973 sdts.push_back(sdt);
974
975 for (uint section = 1; section <= lastSection; section++)
976 {
977 sdt = GetCachedSDT(tsid, section);
978
979 if (sdt)
980 sdts.push_back(sdt);
981 }
982 }
983
984 return sdts;
985}
986
988{
989 QMutexLocker locker(&m_cacheLock);
990
991 if (!current)
992 LOG(VB_GENERAL, LOG_WARNING, LOC +
993 "Currently we ignore \'current\' param");
994
995 sdt_vec_t sdts;
996
997 for (auto *sdt : std::as_const(m_cachedSdts))
998 {
999 IncrementRefCnt(sdt);
1000 sdts.push_back(sdt);
1001 }
1002
1003 return sdts;
1004}
1005
1007{
1008 for (auto & sdt : sdts)
1009 ReturnCachedTable(sdt);
1010 sdts.clear();
1011}
1012
1014{
1015 if (!psip)
1016 return false;
1017
1018 uint tid = psip->TableIDExtension(); // For SDTs
1019 uint bid = psip->TableIDExtension(); // For BATs
1020
1021 QMutexLocker locker(&m_cacheLock);
1022 if (m_cachedRefCnt[psip] > 0)
1023 {
1024 m_cachedSlatedForDeletion[psip] = 1;
1025 return false;
1026 }
1027 if ((TableID::NIT == psip->TableID()) &&
1028 m_cachedNit[psip->Section()])
1029 {
1030 m_cachedNit[psip->Section()] = nullptr;
1031 delete psip;
1032 }
1033 else if ((TableID::SDT == psip->TableID()) &&
1034 m_cachedSdts[tid << 8 | psip->Section()])
1035 {
1036 m_cachedSdts[tid << 8 | psip->Section()] = nullptr;
1037 delete psip;
1038 }
1039 else if ((TableID::BAT == psip->TableID()) &&
1040 m_cachedBats[bid << 8 | psip->Section()])
1041 {
1042 m_cachedBats[bid << 8 | psip->Section()] = nullptr;
1043 delete psip;
1044 }
1045 else
1046 {
1048 }
1049 psip_refcnt_map_t::iterator it;
1050 it = m_cachedSlatedForDeletion.find(psip);
1051 if (it != m_cachedSlatedForDeletion.end())
1052 m_cachedSlatedForDeletion.erase(it);
1053
1054 return true;
1055}
1056
1058{
1059 QMutexLocker locker(&m_cacheLock);
1060
1061 nit_cache_t::iterator it = m_cachedNit.find(nit->Section());
1062 if (it != m_cachedNit.end())
1063 DeleteCachedTable(*it);
1064
1065 m_cachedNit[nit->Section()] = nit;
1066}
1067
1069{
1070 uint key = (bat->BouquetID() << 8) | bat->Section();
1071
1072 QMutexLocker locker(&m_cacheLock);
1073
1074 bat_cache_t::iterator it = m_cachedBats.find(key);
1075 if (it != m_cachedBats.end())
1076 DeleteCachedTable(*it);
1077
1078 m_cachedBats[key] = bat;
1079}
1080
1082{
1083 uint key = (sdt->TSID() << 8) | sdt->Section();
1084
1085 QMutexLocker locker(&m_cacheLock);
1086
1087 sdt_cache_t::iterator it = m_cachedSdts.find(key);
1088 if (it != m_cachedSdts.end())
1089 DeleteCachedTable(*it);
1090
1091 m_cachedSdts[key] = sdt;
1092}
1093
1095{
1096 QMutexLocker locker(&m_listenerLock);
1097
1098#ifdef __cpp_lib_ranges_contains
1099 if (std::ranges::contains(m_dvbMainListeners, val))
1100#else
1101 if (std::ranges::any_of(m_dvbMainListeners,
1102 [val](auto & listener){ return val == listener; } ))
1103#endif
1104 return;
1105
1106 m_dvbMainListeners.push_back(val);
1107}
1108
1110{
1111 QMutexLocker locker(&m_listenerLock);
1112
1113 auto it = std::ranges::find(m_dvbMainListeners, val);
1114 if (it != m_dvbMainListeners.end())
1115 m_dvbMainListeners.erase(it);
1116}
1117
1119{
1120 QMutexLocker locker(&m_listenerLock);
1121
1122#ifdef __cpp_lib_ranges_contains
1123 if (std::ranges::contains(m_dvbOtherListeners, val))
1124#else
1125 if (std::ranges::any_of(m_dvbOtherListeners,
1126 [val](auto & listener){ return val == listener; } ))
1127#endif
1128 return;
1129
1130 m_dvbOtherListeners.push_back(val);
1131}
1132
1134{
1135 QMutexLocker locker(&m_listenerLock);
1136
1137 auto it = std::ranges::find(m_dvbOtherListeners, val);
1138 if (it != m_dvbOtherListeners.end())
1139 m_dvbOtherListeners.erase(it);
1140}
1141
1143{
1144 QMutexLocker locker(&m_listenerLock);
1145
1146#ifdef __cpp_lib_ranges_contains
1147 if (std::ranges::contains(m_dvbEitListeners, val))
1148#else
1149 if (std::ranges::any_of(m_dvbEitListeners,
1150 [val](auto & listener){ return val == listener; } ))
1151#endif
1152 return;
1153
1154 m_dvbEitListeners.push_back(val);
1155}
1156
1158{
1159 QMutexLocker locker(&m_listenerLock);
1160
1161 auto it = std::ranges::find(m_dvbEitListeners, val);
1162 if (it != m_dvbEitListeners.end())
1163 m_dvbEitListeners.erase(it);
1164}
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
unsigned int uint
Definition: compat.h:60
#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)
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