Ticket #12932: dvbstreamdata.cpp

File dvbstreamdata.cpp, 33.3 KB (added by Roger James <roger@…>, 7 years ago)
Line 
1// -*- Mode: c++ -*-
2// Copyright (c) 2003-2004, Daniel Thor Kristjansson
3#include <algorithm>
4using 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.
21DVBStreamData::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      _nit_version(-2), _nito_version(-2)
27{
28    SetVersionNIT(-1,0);
29    SetVersionNITo(-1,0);
30    AddListeningPID(DVB_NIT_PID);
31    AddListeningPID(DVB_SDT_PID);
32    AddListeningPID(DVB_RST_PID);
33    AddListeningPID(DVB_TDT_PID);
34}
35
36DVBStreamData::~DVBStreamData()
37{
38    Reset(_desired_netid, _desired_tsid, _desired_program);
39
40    QMutexLocker locker(&_listener_lock);
41    _dvb_main_listeners.clear();
42    _dvb_other_listeners.clear();
43    _dvb_eit_listeners.clear();
44    _dvb_has_eit.clear();
45}
46
47void DVBStreamData::SetDesiredService(uint netid, uint tsid, int serviceid)
48{
49    bool reset = true;
50
51    if (HasCachedAllSDT(tsid, true))
52    {
53        sdt_const_ptr_t first_sdt = GetCachedSDT(tsid, 0, true);
54        uint networkID = first_sdt->OriginalNetworkID();
55        if (networkID == netid)
56        {
57            reset = false;
58            _desired_netid = netid;
59            _desired_tsid = tsid;
60            uint last_section = first_sdt->LastSection();
61            ProcessSDT(_desired_tsid, first_sdt);
62            ReturnCachedTable(first_sdt);
63            for (uint i = 1; i <= last_section; ++i)
64            {
65                sdt_const_ptr_t sdt = GetCachedSDT(_desired_tsid, i, true);
66                ProcessSDT(_desired_tsid, sdt);
67                ReturnCachedTable(sdt);
68            }
69            SetDesiredProgram(serviceid);
70        }
71    }
72
73    if (reset)
74        Reset(netid, tsid, serviceid);
75}
76
77
78/** \fn DVBStreamData::IsRedundant(uint,const PSIPTable&) const
79 *  \brief Returns true if table already seen.
80 *  \todo This is just a stub.
81 */
82bool DVBStreamData::IsRedundant(uint pid, const PSIPTable &psip) const
83{
84    if (MPEGStreamData::IsRedundant(pid, psip))
85        return true;
86
87    const int table_id = psip.TableID();
88    const int version  = psip.Version();
89
90    if (TableID::NIT == table_id)
91    {
92        if (VersionNIT() != version)
93            return false;
94        return NITSectionSeen(psip.Section());
95    }
96
97    if (TableID::SDT == table_id)
98    {
99        if (VersionSDT(psip.TableIDExtension()) != version)
100            return false;
101        return SDTSectionSeen(psip.TableIDExtension(), psip.Section());
102    }
103
104    if (TableID::TDT == table_id)
105        return false;
106
107    if (TableID::BAT == table_id)
108    {
109        if (VersionBAT(psip.TableIDExtension()) != version)
110            return false;
111        return BATSectionSeen(psip.TableIDExtension(), psip.Section());
112    }
113
114    bool is_eit = false;
115    if (DVB_EIT_PID == pid || FREESAT_EIT_PID == pid)
116    {
117        // Standard Now/Next Event Information Tables for this transport
118        is_eit |= TableID::PF_EIT  == table_id;
119        // Standard Future Event Information Tables for this transport
120        is_eit |= (TableID::SC_EITbeg  <= table_id &&
121                   TableID::SC_EITend  >= table_id);
122    }
123    if (is_eit)
124    {
125        DVBEventInformationTable eit(psip);
126        if (VersionEIT(eit.OriginalNetworkID(), eit.TSID(),
127                       eit.ServiceID(), eit.TableID()) != version)
128            return false;
129        return EITSectionSeen(eit.OriginalNetworkID(), eit.TSID(),
130                              eit.ServiceID(), eit.TableID(),
131                              eit.Section());
132    }
133
134    ////////////////////////////////////////////////////////////////////////
135    // Other transport tables
136
137    if (TableID::NITo == table_id)
138    {
139        if (VersionNITo() != version)
140            return false;
141        return NIToSectionSeen(psip.Section());
142    }
143
144    if (TableID::SDTo == table_id)
145    {
146        if (VersionSDTo(psip.TableIDExtension()) != version)
147            return false;
148        return SDToSectionSeen(psip.TableIDExtension(), psip.Section());
149    }
150
151    if (DVB_EIT_PID == pid || FREESAT_EIT_PID == pid || MCA_EIT_PID == pid)
152    {
153        // Standard Now/Next Event Information Tables for other transport
154        is_eit |= TableID::PF_EITo == table_id;
155        // Standard Future Event Information Tables for other transports
156        is_eit |= (TableID::SC_EITbego <= table_id &&
157                   TableID::SC_EITendo >= table_id);
158    }
159    if (DVB_DNLONG_EIT_PID == pid || DVB_BVLONG_EIT_PID == pid)
160    {
161        // Dish Network and Bev Long Term Future Event Information
162        // for all transports
163        is_eit |= (TableID::DN_EITbego <= table_id &&
164                   TableID::DN_EITendo >= table_id);
165    }
166    if (is_eit)
167    {
168        DVBEventInformationTable eit(psip);
169        if (VersionEIT(eit.OriginalNetworkID(), eit.TSID(),
170                       eit.ServiceID(), eit.TableID()) != version)
171            return false;
172        return EITSectionSeen(eit.OriginalNetworkID(), eit.TSID(),
173                              eit.ServiceID(), eit.TableID(),
174                              eit.Section());
175    }
176
177    if (((PREMIERE_EIT_DIREKT_PID == pid) || (PREMIERE_EIT_SPORT_PID == pid)) &&
178        TableID::PREMIERE_CIT == table_id)
179    {
180        uint content_id = PremiereContentInformationTable(psip).ContentID();
181        if (VersionCIT(content_id) != version)
182            return false;
183        return CITSectionSeen(content_id, psip.Section());
184    }
185
186    return false;
187}
188
189void DVBStreamData::Reset(uint desired_netid, uint desired_tsid,
190                          int desired_serviceid)
191{
192    MPEGStreamData::Reset(desired_serviceid);
193
194    _desired_netid = desired_netid;
195    _desired_tsid  = desired_tsid;
196
197    SetVersionNIT(-1,0);
198    _sdt_versions.clear();
199    _sdt_section_seen.clear();
200    _eit_version.clear();
201    _eit_section_seen.clear();
202    _cit_version.clear();
203    _cit_section_seen.clear();
204
205    SetVersionNITo(-1,0);
206    _sdto_versions.clear();
207    _sdto_section_seen.clear();
208    _bat_versions.clear();
209    _bat_section_seen.clear();
210
211    {
212        _cache_lock.lock();
213
214        nit_cache_t::iterator nit = _cached_nit.begin();
215        for (; nit != _cached_nit.end(); ++nit)
216            DeleteCachedTable(*nit);
217        _cached_nit.clear();
218
219        sdt_cache_t::iterator sit = _cached_sdts.begin();
220        for (; sit != _cached_sdts.end(); ++sit)
221            DeleteCachedTable(*sit);
222        _cached_sdts.clear();
223
224        _cache_lock.unlock();
225    }
226    AddListeningPID(DVB_NIT_PID);
227    AddListeningPID(DVB_SDT_PID);
228    AddListeningPID(DVB_RST_PID);
229    AddListeningPID(DVB_TDT_PID);
230}
231
232/** \fn DVBStreamData::HandleTables(uint pid, const PSIPTable&)
233 *  \brief Assembles PSIP packets and processes them.
234 *  \todo This is just a stub.
235 */
236bool DVBStreamData::HandleTables(uint pid, const PSIPTable &psip)
237{
238    if (MPEGStreamData::HandleTables(pid, psip))
239        return true;
240
241    if (IsRedundant(pid, psip))
242        return true;
243
244    switch (psip.TableID())
245    {
246        case TableID::NIT:
247        {
248            if (_dvb_real_network_id >= 0 && psip.TableIDExtension() != (uint)_dvb_real_network_id)
249            {
250                NetworkInformationTable *nit = new NetworkInformationTable(psip);
251                if (!nit->Mutate())
252                {
253                    delete nit;
254                    return true;
255                }
256                bool retval = HandleTables(pid, *nit);
257                delete nit;
258                return retval;
259            }
260
261            SetVersionNIT(psip.Version(), psip.LastSection());
262            SetNITSectionSeen(psip.Section());
263
264            if (_cache_tables)
265            {
266                NetworkInformationTable *nit =
267                    new NetworkInformationTable(psip);
268                CacheNIT(nit);
269                QMutexLocker locker(&_listener_lock);
270                for (uint i = 0; i < _dvb_main_listeners.size(); i++)
271                    _dvb_main_listeners[i]->HandleNIT(nit);
272            }
273            else
274            {
275                NetworkInformationTable nit(psip);
276                QMutexLocker locker(&_listener_lock);
277                for (uint i = 0; i < _dvb_main_listeners.size(); i++)
278                    _dvb_main_listeners[i]->HandleNIT(&nit);
279            }
280
281            return true;
282        }
283        case TableID::SDT:
284        {
285            uint tsid = psip.TableIDExtension();
286            SetVersionSDT(tsid, psip.Version(), psip.LastSection());
287            SetSDTSectionSeen(tsid, psip.Section());
288
289            if (_cache_tables)
290            {
291                ServiceDescriptionTable *sdt =
292                    new ServiceDescriptionTable(psip);
293                CacheSDT(sdt);
294                ProcessSDT(tsid, sdt);
295            }
296            else
297            {
298                ServiceDescriptionTable sdt(psip);
299                ProcessSDT(tsid, &sdt);
300            }
301
302            return true;
303        }
304        case TableID::TDT:
305        {
306            TimeDateTable tdt(psip);
307
308            UpdateTimeOffset(tdt.UTCUnix());
309
310            QMutexLocker locker(&_listener_lock);
311            for (uint i = 0; i < _dvb_main_listeners.size(); i++)
312                _dvb_main_listeners[i]->HandleTDT(&tdt);
313
314            return true;
315        }
316        case TableID::NITo:
317        {
318            if (_dvb_real_network_id >= 0 && psip.TableIDExtension() == (uint)_dvb_real_network_id)
319            {
320                NetworkInformationTable *nit = new NetworkInformationTable(psip);
321                if (!nit->Mutate())
322                {
323                    delete nit;
324                    return true;
325                }
326                bool retval = HandleTables(pid, *nit);
327                delete nit;
328                return retval;
329            }
330
331            SetVersionNITo(psip.Version(), psip.LastSection());
332            SetNIToSectionSeen(psip.Section());
333            NetworkInformationTable nit(psip);
334
335            QMutexLocker locker(&_listener_lock);
336            for (uint i = 0; i < _dvb_other_listeners.size(); i++)
337                _dvb_other_listeners[i]->HandleNITo(&nit);
338
339            return true;
340        }
341        case TableID::SDTo:
342        {
343            uint tsid = psip.TableIDExtension();
344            SetVersionSDTo(tsid, psip.Version(), psip.LastSection());
345            SetSDToSectionSeen(tsid, psip.Section());
346            ServiceDescriptionTable sdt(psip);
347
348            // some providers send the SDT for the current multiplex as SDTo
349            // this routine changes the TableID to SDT and recalculates the CRC
350            if (_desired_netid == sdt.OriginalNetworkID() &&
351                _desired_tsid  == tsid)
352            {
353                ServiceDescriptionTable *sdta =
354                    new ServiceDescriptionTable(psip);
355                if (!sdta->Mutate())
356                {
357                    delete sdta;
358                    return true;
359                }
360                if (_cache_tables)
361                {
362                    CacheSDT(sdta);
363                    ProcessSDT(tsid, sdta);
364                }
365                else
366                {
367                    ProcessSDT(tsid, sdta);
368                    delete sdta;
369                }
370                return true;
371            }
372
373            QMutexLocker locker(&_listener_lock);
374            for (uint i = 0; i < _dvb_other_listeners.size(); i++)
375                _dvb_other_listeners[i]->HandleSDTo(tsid, &sdt);
376
377            return true;
378        }
379        case TableID::BAT:
380        {
381            uint bid = psip.TableIDExtension();
382            SetVersionBAT(bid, psip.Version(), psip.LastSection());
383            SetBATSectionSeen(bid, psip.Section());
384            BouquetAssociationTable bat(psip);
385
386            QMutexLocker locker(&_listener_lock);
387            for (uint i = 0; i < _dvb_other_listeners.size(); i++)
388                _dvb_other_listeners[i]->HandleBAT(&bat);
389
390            return true;
391        }
392    }
393
394    if ((DVB_EIT_PID == pid || DVB_DNLONG_EIT_PID == pid || FREESAT_EIT_PID == pid ||
395        ((MCA_ONID == _desired_netid) && (MCA_EIT_TSID == _desired_tsid) &&
396        (MCA_EIT_PID == pid)) || DVB_BVLONG_EIT_PID == pid) &&
397
398        DVBEventInformationTable::IsEIT(psip.TableID()))
399    {
400        QMutexLocker locker(&_listener_lock);
401        if (!_dvb_eit_listeners.size() && !_eit_helper)
402            return true;
403
404        DVBEventInformationTable eit(psip);
405
406        SetVersionEIT(eit.OriginalNetworkID(), eit.TSID(),
407                      eit.ServiceID(), eit.TableID(),
408                      eit.Version(), eit.LastSection());
409        SetEITSectionSeen(eit.OriginalNetworkID(), eit.TSID(),
410                          eit.ServiceID(), eit.TableID(),
411                          eit.Section(), eit.SegmentLastSectionNumber());
412
413        // In the future I could pass this to the handlers
414        if(HasAllEITSections(eit.OriginalNetworkID(), eit.TSID(),
415                      eit.ServiceID(), eit.TableID()))
416        {
417            LOG(VB_GENERAL, LOG_INFO, LOC + QString(
418                    "Table %1 complete subtable id 0x%2/0x%3/0x%4 version %5")
419                .arg(eit.TableID())
420                .arg(eit.OriginalNetworkID() == 0x233a ?
421                        GenerateUniqueUKOriginalNetworkID(eit.TSID()) :
422                        eit.OriginalNetworkID(),0,16)
423                .arg(eit.TSID(),0,16)
424                .arg(eit.ServiceID(),0,16)
425                .arg(eit.Version()));
426        }
427
428        for (uint i = 0; i < _dvb_eit_listeners.size(); i++)
429            _dvb_eit_listeners[i]->HandleEIT(&eit);
430
431        if (_eit_helper)
432            _eit_helper->AddEIT(&eit);
433
434        return true;
435    }
436
437    if (_desired_netid == PREMIERE_ONID &&
438        (PREMIERE_EIT_DIREKT_PID == pid || PREMIERE_EIT_SPORT_PID == pid) &&
439        PremiereContentInformationTable::IsEIT(psip.TableID()))
440    {
441        QMutexLocker locker(&_listener_lock);
442        if (!_dvb_eit_listeners.size() && !_eit_helper)
443            return true;
444
445        PremiereContentInformationTable cit(psip);
446        SetVersionCIT(cit.ContentID(), cit.Version());
447        SetCITSectionSeen(cit.ContentID(), cit.Section());
448
449        for (uint i = 0; i < _dvb_eit_listeners.size(); i++)
450            _dvb_eit_listeners[i]->HandleEIT(&cit);
451
452        if (_eit_helper)
453            _eit_helper->AddEIT(&cit);
454
455        return true;
456    }
457
458    return false;
459}
460
461void DVBStreamData::ProcessSDT(uint tsid, const ServiceDescriptionTable *sdt)
462{
463    QMutexLocker locker(&_listener_lock);
464
465    for (uint i = 0; i < sdt->ServiceCount(); i++)
466    {
467        /*
468         * FIXME always signal EIT presence. We filter later. To many
469         * networks set these flags wrong.
470         * This allows the user to simply set useonairguide on a
471         * channel manually.
472         */
473#if 0
474        if (sdt->HasEITSchedule(i) || sdt->HasEITPresentFollowing(i))
475#endif
476            _dvb_has_eit[sdt->ServiceID(i)] = true;
477    }
478
479    for (uint i = 0; i < _dvb_main_listeners.size(); i++)
480        _dvb_main_listeners[i]->HandleSDT(tsid, sdt);
481}
482
483bool DVBStreamData::HasEITPIDChanges(const uint_vec_t &in_use_pids) const
484{
485    QMutexLocker locker(&_listener_lock);
486    bool want_eit = (_eit_rate >= 0.5f) && HasAnyEIT();
487    bool has_eit  = in_use_pids.size();
488    return want_eit != has_eit;
489}
490
491bool DVBStreamData::GetEITPIDChanges(const uint_vec_t &cur_pids,
492                                     uint_vec_t &add_pids,
493                                     uint_vec_t &del_pids) const
494{
495    QMutexLocker locker(&_listener_lock);
496
497    if ((_eit_rate >= 0.5f) && HasAnyEIT())
498    {
499        if (find(cur_pids.begin(), cur_pids.end(),
500                 (uint) DVB_EIT_PID) == cur_pids.end())
501        {
502            add_pids.push_back(DVB_EIT_PID);
503        }
504
505        if (_dvb_eit_dishnet_long &&
506            find(cur_pids.begin(), cur_pids.end(),
507                 (uint) DVB_DNLONG_EIT_PID) == cur_pids.end())
508        {
509            add_pids.push_back(DVB_DNLONG_EIT_PID);
510        }
511
512        if (_dvb_eit_dishnet_long &&
513            find(cur_pids.begin(), cur_pids.end(),
514                 (uint) DVB_BVLONG_EIT_PID) == cur_pids.end())
515        {
516            add_pids.push_back(DVB_BVLONG_EIT_PID);
517        }
518
519        if (_desired_netid == PREMIERE_ONID &&
520            find(cur_pids.begin(), cur_pids.end(),
521                 (uint) PREMIERE_EIT_DIREKT_PID) == cur_pids.end())
522        {
523            add_pids.push_back(PREMIERE_EIT_DIREKT_PID);
524        }
525
526        if (_desired_netid == PREMIERE_ONID &&
527            find(cur_pids.begin(), cur_pids.end(),
528                 (uint) PREMIERE_EIT_SPORT_PID) == cur_pids.end())
529        {
530            add_pids.push_back(PREMIERE_EIT_SPORT_PID);
531        }
532
533        if (find(cur_pids.begin(), cur_pids.end(),
534                 (uint) FREESAT_EIT_PID) == cur_pids.end())
535        {
536            add_pids.push_back(FREESAT_EIT_PID);
537        }
538
539        if (MCA_ONID == _desired_netid && MCA_EIT_TSID == _desired_tsid &&
540            find(cur_pids.begin(), cur_pids.end(),
541                 (uint) MCA_EIT_PID) == cur_pids.end())
542        {
543            add_pids.push_back(MCA_EIT_PID);
544        }
545
546    }
547    else
548    {
549        if (find(cur_pids.begin(), cur_pids.end(),
550                 (uint) DVB_EIT_PID) != cur_pids.end())
551        {
552            del_pids.push_back(DVB_EIT_PID);
553        }
554
555        if (_dvb_eit_dishnet_long &&
556            find(cur_pids.begin(), cur_pids.end(),
557                 (uint) DVB_DNLONG_EIT_PID) != cur_pids.end())
558        {
559            del_pids.push_back(DVB_DNLONG_EIT_PID);
560        }
561
562        if (_dvb_eit_dishnet_long &&
563            find(cur_pids.begin(), cur_pids.end(),
564                 (uint) DVB_BVLONG_EIT_PID) != cur_pids.end())
565        {
566            del_pids.push_back(DVB_BVLONG_EIT_PID);
567        }
568
569        if (_desired_netid == PREMIERE_ONID &&
570            find(cur_pids.begin(), cur_pids.end(),
571                 (uint) PREMIERE_EIT_DIREKT_PID) != cur_pids.end())
572        {
573            del_pids.push_back(PREMIERE_EIT_DIREKT_PID);
574        }
575
576        if (_desired_netid == PREMIERE_ONID &&
577            find(cur_pids.begin(), cur_pids.end(),
578                 (uint) PREMIERE_EIT_SPORT_PID) != cur_pids.end())
579        {
580            del_pids.push_back(PREMIERE_EIT_SPORT_PID);
581        }
582
583        if (find(cur_pids.begin(), cur_pids.end(),
584                 (uint) FREESAT_EIT_PID) != cur_pids.end())
585        {
586            del_pids.push_back(FREESAT_EIT_PID);
587        }
588
589        if (MCA_ONID == _desired_netid && MCA_EIT_TSID == _desired_tsid &&
590            find(cur_pids.begin(), cur_pids.end(),
591                 (uint) MCA_EIT_PID) != cur_pids.end())
592        {
593            del_pids.push_back(MCA_EIT_PID);
594        }
595    }
596
597    return add_pids.size() || del_pids.size();
598}
599
600void DVBStreamData::SetNITSectionSeen(uint section)
601{
602    _nit_section_seen[section>>3] |= bit_sel[section & 0x7];
603}
604
605bool DVBStreamData::NITSectionSeen(uint section) const
606{
607    return (bool) (_nit_section_seen[section>>3] & bit_sel[section & 0x7]);
608}
609
610bool DVBStreamData::HasAllNITSections(void) const
611{
612    for (uint i = 0; i < 32; i++)
613        if (_nit_section_seen[i] != 0xff)
614            return false;
615    return true;
616}
617
618void DVBStreamData::SetNIToSectionSeen(uint section)
619{
620    _nito_section_seen[section>>3] |= bit_sel[section & 0x7];
621}
622
623bool DVBStreamData::NIToSectionSeen(uint section) const
624{
625    return (bool) (_nito_section_seen[section>>3] & bit_sel[section & 0x7]);
626}
627
628bool DVBStreamData::HasAllNIToSections(void) const
629{
630    for (uint i = 0; i < 32; i++)
631        if (_nito_section_seen[i] != 0xff)
632            return false;
633    return true;
634}
635
636void DVBStreamData::SetSDTSectionSeen(uint tsid, uint section)
637{
638    sections_map_t::iterator it = _sdt_section_seen.find(tsid);
639    if (it == _sdt_section_seen.end())
640    {
641        _sdt_section_seen[tsid].resize(32, 0);
642        it = _sdt_section_seen.find(tsid);
643    }
644    (*it)[section>>3] |= bit_sel[section & 0x7];
645}
646
647bool DVBStreamData::SDTSectionSeen(uint tsid, uint section) const
648{
649    sections_map_t::const_iterator it = _sdt_section_seen.find(tsid);
650    if (it == _sdt_section_seen.end())
651        return false;
652    return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
653}
654
655bool DVBStreamData::HasAllSDTSections(uint tsid) const
656{
657    sections_map_t::const_iterator it = _sdt_section_seen.find(tsid);
658    if (it == _sdt_section_seen.end())
659        return false;
660    for (uint i = 0; i < 32; i++)
661        if ((*it)[i] != 0xff)
662            return false;
663    return true;
664}
665
666void DVBStreamData::SetSDToSectionSeen(uint tsid, uint section)
667{
668    sections_map_t::iterator it = _sdto_section_seen.find(tsid);
669    if (it == _sdto_section_seen.end())
670    {
671        _sdto_section_seen[tsid].resize(32, 0);
672        it = _sdto_section_seen.find(tsid);
673    }
674    (*it)[section>>3] |= bit_sel[section & 0x7];
675}
676
677bool DVBStreamData::SDToSectionSeen(uint tsid, uint section) const
678{
679    sections_map_t::const_iterator it = _sdto_section_seen.find(tsid);
680    if (it == _sdto_section_seen.end())
681        return false;
682    return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
683}
684
685bool DVBStreamData::HasAllSDToSections(uint tsid) const
686{
687    sections_map_t::const_iterator it = _sdto_section_seen.find(tsid);
688    if (it == _sdto_section_seen.end())
689        return false;
690    for (uint i = 0; i < 32; i++)
691        if ((*it)[i] != 0xff)
692            return false;
693    return true;
694}
695
696void DVBStreamData::SetBATSectionSeen(uint bid, uint section)
697{
698    sections_map_t::iterator it = _bat_section_seen.find(bid);
699    if (it == _bat_section_seen.end())
700    {
701        _bat_section_seen[bid].resize(32, 0);
702        it = _bat_section_seen.find(bid);
703    }
704    (*it)[section>>3] |= bit_sel[section & 0x7];
705}
706
707bool DVBStreamData::BATSectionSeen(uint bid, uint section) const
708{
709    sections_map_t::const_iterator it = _bat_section_seen.find(bid);
710    if (it == _bat_section_seen.end())
711        return false;
712    return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
713}
714
715bool DVBStreamData::HasAllBATSections(uint bid) const
716{
717    sections_map_t::const_iterator it = _bat_section_seen.find(bid);
718    if (it == _bat_section_seen.end())
719        return false;
720    for (uint i = 0; i < 32; i++)
721        if ((*it)[i] != 0xff)
722            return false;
723    return true;
724}
725
726void DVBStreamData::SetEITSectionSeen(uint original_network_id, uint transport_stream_id,
727                                      uint serviceid, uint tableid,
728                                      uint section, uint segment_last_section)
729{
730    // Array of with bit masks with or 1 to 8 least significant bits cleared
731    static const unsigned char init_bits[8] =
732        { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, };
733
734    if (original_network_id == 0x233a)
735        original_network_id = GenerateUniqueUKOriginalNetworkID(transport_stream_id);
736
737    uint64_t key =
738            uint64_t(original_network_id) << 48 |
739            uint64_t(transport_stream_id)  << 32 |
740            serviceid << 16 | tableid;
741
742    QMap<uint64_t, sections_t>::iterator it = _eit_section_seen.find(key);
743    if (it == _eit_section_seen.end())
744    {
745        _eit_section_seen[key].resize(32, 0);
746        it = _eit_section_seen.find(key);
747    }
748    (*it)[section>>3] |= bit_sel[section & 0x7];
749    (*it)[segment_last_section >> 3] |= init_bits[segment_last_section & 0x7];
750}
751
752bool DVBStreamData::EITSectionSeen(uint original_network_id, uint transport_stream_id,
753                                   uint serviceid, uint tableid,
754                                   uint section) const
755{
756    if (original_network_id == 0x233a)
757        original_network_id = GenerateUniqueUKOriginalNetworkID(transport_stream_id);
758
759    uint64_t key =
760            uint64_t(original_network_id) << 48 |
761            uint64_t(transport_stream_id)  << 32 |
762            serviceid << 16 | tableid;
763
764    QMap<uint64_t, sections_t>::const_iterator it = _eit_section_seen.find(key);
765    if (it == _eit_section_seen.end())
766        return false;
767    return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
768}
769
770bool DVBStreamData::HasAllEITSections(uint original_network_id, uint transport_stream_id,
771                                      uint serviceid, uint tableid) const
772{
773    if (original_network_id == 0x233a)
774        original_network_id = GenerateUniqueUKOriginalNetworkID(transport_stream_id);
775
776    uint64_t key =
777            uint64_t(original_network_id) << 48 |
778            uint64_t(transport_stream_id)  << 32 |
779            serviceid << 16 | tableid;
780
781    QMap<uint64_t, sections_t>::const_iterator it = _eit_section_seen.find(key);
782
783    if (it == _eit_section_seen.end())
784        return false;
785    for (uint i = 0; i < 32; i++)
786        if ((*it)[i] != 0xff)
787            return false;
788    return true;
789}
790
791void DVBStreamData::SetCITSectionSeen(uint contentid, uint section)
792{
793    sections_map_t::iterator it = _cit_section_seen.find(contentid);
794    if (it == _cit_section_seen.end())
795    {
796        _cit_section_seen[contentid].resize(32, 0);
797        it = _cit_section_seen.find(contentid);
798    }
799    (*it)[section>>3] |= bit_sel[section & 0x7];
800}
801
802bool DVBStreamData::CITSectionSeen(uint contentid, uint section) const
803{
804    sections_map_t::const_iterator it = _cit_section_seen.find(contentid);
805    if (it == _cit_section_seen.end())
806        return false;
807    return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
808}
809
810bool DVBStreamData::HasCachedAnyNIT(bool current) const
811{
812    QMutexLocker locker(&_cache_lock);
813
814    if (!current)
815        LOG(VB_GENERAL, LOG_WARNING, LOC +
816            "Currently we ignore \'current\' param");
817
818    return (bool)(_cached_nit.size());
819}
820
821bool DVBStreamData::HasCachedAllNIT(bool current) const
822{
823    QMutexLocker locker(&_cache_lock);
824
825    if (!current)
826        LOG(VB_GENERAL, LOG_WARNING, LOC +
827            "Currently we ignore \'current\' param");
828
829    if (_cached_nit.empty())
830        return false;
831
832    uint last_section = (*_cached_nit.begin())->LastSection();
833    if (!last_section)
834        return true;
835
836    for (uint i = 0; i <= last_section; i++)
837        if (_cached_nit.find(i) == _cached_nit.end())
838            return false;
839
840    return true;
841}
842
843bool DVBStreamData::HasCachedAllSDT(uint tsid, bool current) const
844{
845    QMutexLocker locker(&_cache_lock);
846
847    if (!current)
848        LOG(VB_GENERAL, LOG_WARNING, LOC +
849            "Currently we ignore \'current\' param");
850
851    sdt_cache_t::const_iterator it = _cached_sdts.find(tsid << 8);
852    if (it == _cached_sdts.end())
853        return false;
854
855    uint last_section = (*it)->LastSection();
856    if (!last_section)
857        return true;
858
859    for (uint i = 1; i <= last_section; i++)
860        if (_cached_sdts.find((tsid << 8) | i) == _cached_sdts.end())
861            return false;
862
863    return true;
864}
865
866bool DVBStreamData::HasCachedAnySDT(uint tsid, bool current) const
867{
868    QMutexLocker locker(&_cache_lock);
869
870    if (!current)
871        LOG(VB_GENERAL, LOG_WARNING, LOC +
872            "Currently we ignore \'current\' param");
873
874    for (uint i = 0; i <= 255; i++)
875        if (_cached_sdts.find((tsid << 8) | i) != _cached_sdts.end())
876            return true;
877
878    return false;
879}
880
881bool DVBStreamData::HasCachedSDT(bool current) const
882{
883    QMutexLocker locker(&_cache_lock);
884
885    if (_cached_nit.empty())
886        return false;
887
888    nit_cache_t::const_iterator it = _cached_nit.begin();
889    for (; it != _cached_nit.end(); ++it)
890    {
891        for (uint i = 0; i < (*it)->TransportStreamCount(); i++)
892        {
893            if (HasCachedAllSDT((*it)->TSID(i), current))
894                return true;
895        }
896    }
897
898    return false;
899}
900
901bool DVBStreamData::HasCachedAnySDTs(bool current) const
902{
903    QMutexLocker locker(&_cache_lock);
904    return !_cached_sdts.empty();
905}
906
907bool DVBStreamData::HasCachedAllSDTs(bool current) const
908{
909    QMutexLocker locker(&_cache_lock);
910
911    if (_cached_nit.empty())
912        return false;
913
914    nit_cache_t::const_iterator it = _cached_nit.begin();
915    for (; it != _cached_nit.end(); ++it)
916    {
917        if ((int)(*it)->TransportStreamCount() > _cached_sdts.size())
918            return false;
919
920        for (uint i = 0; i < (*it)->TransportStreamCount(); i++)
921            if (!HasCachedAllSDT((*it)->TSID(i), current))
922                return false;
923    }
924
925    return true;
926}
927
928nit_const_ptr_t DVBStreamData::GetCachedNIT(
929    uint section_num, bool current) const
930{
931    QMutexLocker locker(&_cache_lock);
932
933    if (!current)
934        LOG(VB_GENERAL, LOG_WARNING, LOC +
935            "Currently we ignore \'current\' param");
936
937    nit_ptr_t nit = NULL;
938
939    nit_cache_t::const_iterator it = _cached_nit.find(section_num);
940    if (it != _cached_nit.end())
941        IncrementRefCnt(nit = *it);
942
943    return nit;
944}
945
946nit_vec_t DVBStreamData::GetCachedNIT(bool current) const
947{
948    QMutexLocker locker(&_cache_lock);
949
950    nit_vec_t nits;
951
952    for (uint i = 0; i < 256; i++)
953    {
954        nit_const_ptr_t nit = GetCachedNIT(i, current);
955        if (nit)
956            nits.push_back(nit);
957    }
958
959    return nits;
960}
961
962sdt_const_ptr_t DVBStreamData::GetCachedSDT(
963    uint tsid, uint section_num, bool current) const
964{
965    QMutexLocker locker(&_cache_lock);
966
967    if (!current)
968        LOG(VB_GENERAL, LOG_WARNING, LOC +
969            "Currently we ignore \'current\' param");
970
971    sdt_ptr_t sdt = NULL;
972
973    uint key = (tsid << 8) | section_num;
974    sdt_cache_t::const_iterator it = _cached_sdts.find(key);
975    if (it != _cached_sdts.end())
976        IncrementRefCnt(sdt = *it);
977
978    return sdt;
979}
980
981sdt_vec_t DVBStreamData::GetCachedSDTs(bool current) const
982{
983    QMutexLocker locker(&_cache_lock);
984
985    if (!current)
986        LOG(VB_GENERAL, LOG_WARNING, LOC +
987            "Currently we ignore \'current\' param");
988
989    sdt_vec_t sdts;
990
991    sdt_cache_t::const_iterator it = _cached_sdts.begin();
992    for (; it != _cached_sdts.end(); ++it)
993    {
994        IncrementRefCnt(*it);
995        sdts.push_back(*it);
996    }
997
998    return sdts;
999}
1000
1001void DVBStreamData::ReturnCachedSDTTables(sdt_vec_t &sdts) const
1002{
1003    for (sdt_vec_t::iterator it = sdts.begin(); it != sdts.end(); ++it)
1004        ReturnCachedTable(*it);
1005    sdts.clear();
1006}
1007
1008bool DVBStreamData::DeleteCachedTable(PSIPTable *psip) const
1009{
1010    if (!psip)
1011        return false;
1012
1013    uint tid = psip->TableIDExtension();
1014
1015    QMutexLocker locker(&_cache_lock);
1016    if (_cached_ref_cnt[psip] > 0)
1017    {
1018        _cached_slated_for_deletion[psip] = 1;
1019        return false;
1020    }
1021    else if ((TableID::NIT == psip->TableID()) &&
1022             _cached_nit[psip->Section()])
1023    {
1024        _cached_nit[psip->Section()] = NULL;
1025        delete psip;
1026    }
1027    else if ((TableID::SDT == psip->TableID()) &&
1028             _cached_sdts[tid << 8 | psip->Section()])
1029    {
1030        _cached_sdts[tid << 8 | psip->Section()] = NULL;
1031        delete psip;
1032    }
1033    else
1034    {
1035        return MPEGStreamData::DeleteCachedTable(psip);
1036    }
1037    psip_refcnt_map_t::iterator it;
1038    it = _cached_slated_for_deletion.find(psip);
1039    if (it != _cached_slated_for_deletion.end())
1040        _cached_slated_for_deletion.erase(it);
1041
1042    return true;
1043}
1044
1045void DVBStreamData::CacheNIT(NetworkInformationTable *nit)
1046{
1047    QMutexLocker locker(&_cache_lock);
1048
1049    nit_cache_t::iterator it = _cached_nit.find(nit->Section());
1050    if (it != _cached_nit.end())
1051        DeleteCachedTable(*it);
1052
1053    _cached_nit[nit->Section()] = nit;
1054}
1055
1056void DVBStreamData::CacheSDT(ServiceDescriptionTable *sdt)
1057{
1058    uint key = (sdt->TSID() << 8) | sdt->Section();
1059
1060    QMutexLocker locker(&_cache_lock);
1061
1062    sdt_cache_t::iterator it = _cached_sdts.find(key);
1063    if (it != _cached_sdts.end())
1064        DeleteCachedTable(*it);
1065
1066    _cached_sdts[key] = sdt;
1067}
1068
1069void DVBStreamData::AddDVBMainListener(DVBMainStreamListener *val)
1070{
1071    QMutexLocker locker(&_listener_lock);
1072
1073    dvb_main_listener_vec_t::iterator it = _dvb_main_listeners.begin();
1074    for (; it != _dvb_main_listeners.end(); ++it)
1075        if (((void*)val) == ((void*)*it))
1076            return;
1077
1078    _dvb_main_listeners.push_back(val);
1079}
1080
1081void DVBStreamData::RemoveDVBMainListener(DVBMainStreamListener *val)
1082{
1083    QMutexLocker locker(&_listener_lock);
1084
1085    dvb_main_listener_vec_t::iterator it = _dvb_main_listeners.begin();
1086    for (; it != _dvb_main_listeners.end(); ++it)
1087    {
1088        if (((void*)val) == ((void*)*it))
1089        {
1090            _dvb_main_listeners.erase(it);
1091            return;
1092        }
1093    }
1094}
1095
1096void DVBStreamData::AddDVBOtherListener(DVBOtherStreamListener *val)
1097{
1098    QMutexLocker locker(&_listener_lock);
1099
1100    dvb_other_listener_vec_t::iterator it = _dvb_other_listeners.begin();
1101    for (; it != _dvb_other_listeners.end(); ++it)
1102        if (((void*)val) == ((void*)*it))
1103            return;
1104
1105    _dvb_other_listeners.push_back(val);
1106}
1107
1108void DVBStreamData::RemoveDVBOtherListener(DVBOtherStreamListener *val)
1109{
1110    QMutexLocker locker(&_listener_lock);
1111
1112    dvb_other_listener_vec_t::iterator it = _dvb_other_listeners.begin();
1113    for (; it != _dvb_other_listeners.end(); ++it)
1114    {
1115        if (((void*)val) == ((void*)*it))
1116        {
1117            _dvb_other_listeners.erase(it);
1118            return;
1119        }
1120    }
1121}
1122
1123void DVBStreamData::AddDVBEITListener(DVBEITStreamListener *val)
1124{
1125    QMutexLocker locker(&_listener_lock);
1126
1127    dvb_eit_listener_vec_t::iterator it = _dvb_eit_listeners.begin();
1128    for (; it != _dvb_eit_listeners.end(); ++it)
1129        if (((void*)val) == ((void*)*it))
1130            return;
1131
1132    _dvb_eit_listeners.push_back(val);
1133}
1134
1135void DVBStreamData::RemoveDVBEITListener(DVBEITStreamListener *val)
1136{
1137    QMutexLocker locker(&_listener_lock);
1138
1139    dvb_eit_listener_vec_t::iterator it = _dvb_eit_listeners.begin();
1140    for (; it != _dvb_eit_listeners.end(); ++it)
1141    {
1142        if (((void*)val) == ((void*)*it))
1143        {
1144            _dvb_eit_listeners.erase(it);
1145            return;
1146        }
1147    }
1148}