Ticket #12932: dvbstreamdata.2.cpp

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