Ticket #7923: ca-key-patch-2.diff

File ca-key-patch-2.diff, 15.0 KB (added by Mike Nix <mnix@…>, 10 years ago)

Technically better solution. Also adds CAT caching and processing.

  • mpegstreamdata.cpp

     
    2121
    2222//#define DEBUG_MPEG_RADIO // uncomment to strip video streams from TS stream
    2323
     24// Defined:   CA pids are added to the PMT
     25// Undefined: CA pids are added as listening pids only
     26// Undefined option is cleaner and seems to work. Also has the benefit
     27// of not requiring the CAT to be cached before handling the PMT
     28// so it won't break if there is no CAT.
     29//#define ADD_CA_TO_PMT
     30
    2431void init_sections(sections_t &sect, uint last_section)
    2532{
    2633    static const unsigned char init_bits[8] =
     
    8693    memset(_si_time_offsets, 0, sizeof(_si_time_offsets));
    8794
    8895    AddListeningPID(MPEG_PAT_PID);
     96    AddListeningPID(MPEG_CAT_PID);
    8997}
    9098
    9199MPEGStreamData::~MPEGStreamData()
     
    209217        for (; it2 != _cached_pmts.end(); ++it2)
    210218            DeleteCachedTable(*it2);
    211219        _cached_pmts.clear();
     220
     221        cat_cache_t::iterator it3 = _cached_cats.begin();
     222        for (; it3 != _cached_cats.end(); ++it3)
     223            DeleteCachedTable(*it3);
     224        _cached_cats.clear();
    212225    }
    213226
    214227    ResetDecryptionMonitoringState();
    215228
    216229    AddListeningPID(MPEG_PAT_PID);
     230    AddListeningPID(MPEG_CAT_PID);
    217231}
    218232
    219233void MPEGStreamData::DeletePartialPES(uint pid)
     
    505519        VERBOSE(VB_RECORD, "no PAT yet...");
    506520        return false; // no way to properly rewrite pids without PAT
    507521    }
     522#ifdef ADD_CA_TO_PMT
     523    if (!HasCachedAnyCAT())
     524    {
     525        VERBOSE(VB_RECORD, "no CAT yet...");
     526        return false;
     527    }
     528#endif
    508529    pmt.Parse();
    509530
    510531    uint programNumber = 1; // MPEG Program Number
     
    517538
    518539    if (!_strip_pmt_descriptors)
    519540    {
     541#ifdef ADD_CA_TO_PMT
     542/*
     543   Do not exclude the CA descriptors or we break AU (auto update).
     544   This is especially noticable on the Optus C1 Aurora service
     545   where all AU data is in a separate PID.
     546*/
     547        gdesc = MPEGDescriptor::Parse(pmt.ProgramInfo(), pmt.ProgramInfoLength());
     548
     549/* looks like we also need to bring in the PIDs listed in the
     550   CAT (Conditional Access Table). The program keys in the PIDs
     551   referenced in the PMT seem to be changed daily, and the ones
     552   in the CAT are changed weekly.
     553*/
     554        cat_vec_t cats = GetCachedCATs();
     555        VERBOSE(VB_RECORD, QString("Adding CA PIDS from %1 CAT tables").arg(cats.size()));
     556        for (uint i = 0; i < cats.size(); i++)
     557        {
     558           desc_list_t cdesc = MPEGDescriptor::ParseOnlyInclude(
     559               cats[i]->Descriptors(), cats[i]->DescriptorsLength(),
     560               DescriptorID::conditional_access);
     561           if (cdesc.size())
     562              gdesc.insert(gdesc.end(), cdesc.begin(), cdesc.end());
     563        }
     564#else
    520565        gdesc = MPEGDescriptor::ParseAndExclude(
    521566            pmt.ProgramInfo(), pmt.ProgramInfoLength(),
    522567            DescriptorID::conditional_access);
     568#endif
    523569
    524570        // If there is no caption descriptor in PMT, copy any caption
    525571        // descriptor found in VCT to global descriptors...
     
    618664        return false;
    619665    }
    620666
     667#ifndef ADD_CA_TO_PMT
     668    desc_list_t cdesc = MPEGDescriptor::ParseOnlyInclude(
     669         pmt.ProgramInfo(), pmt.ProgramInfoLength(),
     670         DescriptorID::conditional_access);
     671
     672    VERBOSE(VB_RECORD, QString("Adding %1 CA pids from PMT").arg(cdesc.size()));
     673    for (uint i = 0; i < cdesc.size(); i++)
     674    {
     675        ConditionalAccessDescriptor cad(cdesc[i]);
     676        VERBOSE(VB_RECORD, QString("CA PID from PMT:%1").arg(cad.PID()));
     677        AddListeningPID(cad.PID());
     678    }
     679#endif
     680
    621681    _pids_audio.clear();
    622682    for (uint i = 0; i < audioPIDs.size(); i++)
    623683        AddAudioPID(audioPIDs[i]);
     
    679739    }
    680740
    681741    if (TableID::CAT == table_id)
    682         return false;
     742    {
     743        if (VersionCAT(psip.TableIDExtension()) != version)
     744           return false;
     745        return CATSectionSeen(psip.TableIDExtension(), psip.Section());
     746    }
    683747
    684748    if (TableID::PMT == table_id)
    685749    {
     
    720784        }
    721785        case TableID::CAT:
    722786        {
     787            uint tsid = psip.TableIDExtension();
     788            SetVersionCAT(tsid, version, psip.LastSection());
     789            SetCATSectionSeen(tsid, psip.Section());
     790
    723791            ConditionalAccessTable cat(psip);
    724792
    725             _listener_lock.lock();
    726             for (uint i = 0; i < _mpeg_listeners.size(); i++)
    727                 _mpeg_listeners[i]->HandleCAT(&cat);
    728             _listener_lock.unlock();
     793            if (_cache_tables)
     794                CacheCAT(&cat);
    729795
     796            ProcessCAT(&cat);
     797
    730798            return true;
    731799        }
    732800        case TableID::PMT:
     
    798866    }
    799867}
    800868
     869
     870void MPEGStreamData::ProcessCAT(const ConditionalAccessTable *cat)
     871{
     872    _listener_lock.lock();
     873    for (uint i = 0; i < _mpeg_listeners.size(); i++)
     874        _mpeg_listeners[i]->HandleCAT(cat);
     875    _listener_lock.unlock();
     876   
     877#ifndef ADD_CA_TO_PMT
     878    desc_list_t cdesc = MPEGDescriptor::ParseOnlyInclude(
     879         cat->Descriptors(), cat->DescriptorsLength(),
     880         DescriptorID::conditional_access);
     881
     882    VERBOSE(VB_RECORD, QString("Adding %1 CA pids from CAT").arg(cdesc.size()));
     883    for (uint i = 0; i < cdesc.size(); i++)
     884    {
     885        ConditionalAccessDescriptor cad(cdesc[i]);
     886        VERBOSE(VB_RECORD, QString("CA PID from CAT:%1").arg(cad.PID()));
     887        AddListeningPID(cad.PID());
     888    }
     889#endif
     890}
     891           
    801892void MPEGStreamData::ProcessPMT(const ProgramMapTable *pmt)
    802893{
    803894    _listener_lock.lock();
     
    9671058{
    9681059    bool ok = !tspacket.TransportError();
    9691060
     1061    VERBOSE(VB_RECORD, tspacket.toString());
     1062
    9701063    if (IsEncryptionTestPID(tspacket.PID()))
    9711064    {
    9721065        ProcessEncryptedPacket(tspacket);
     
    11461239    return true;
    11471240}
    11481241
     1242void MPEGStreamData::SetCATSectionSeen(uint tsid, uint section)
     1243{
     1244    sections_map_t::iterator it = _cat_section_seen.find(tsid);
     1245    if (it == _cat_section_seen.end())
     1246    {
     1247        _cat_section_seen[tsid].resize(32, 0);
     1248        it = _cat_section_seen.find(tsid);
     1249    }
     1250    (*it)[section>>3] |= bit_sel[section & 0x7];
     1251}
     1252
     1253bool MPEGStreamData::CATSectionSeen(uint tsid, uint section) const
     1254{
     1255    sections_map_t::const_iterator it = _cat_section_seen.find(tsid);
     1256    if (it == _cat_section_seen.end())
     1257        return false;
     1258    return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
     1259}
     1260
     1261bool MPEGStreamData::HasAllCATSections(uint tsid) const
     1262{
     1263    sections_map_t::const_iterator it = _cat_section_seen.find(tsid);
     1264    if (it == _cat_section_seen.end())
     1265        return false;
     1266    for (uint i = 0; i < 32; i++)
     1267        if ((*it)[i] != 0xff)
     1268            return false;
     1269    return true;
     1270}
     1271
    11491272void MPEGStreamData::SetPMTSectionSeen(uint prog_num, uint section)
    11501273{
    11511274    sections_map_t::iterator it = _pmt_section_seen.find(prog_num);
     
    12211344    return _cached_pats.size();
    12221345}
    12231346
     1347bool MPEGStreamData::HasCachedAllCAT(uint tsid) const
     1348{
     1349    QMutexLocker locker(&_cache_lock);
     1350
     1351    cat_cache_t::const_iterator it = _cached_cats.find(tsid << 8);
     1352    if (it == _cached_cats.end())
     1353        return false;
     1354
     1355    uint last_section = (*it)->LastSection();
     1356    if (!last_section)
     1357        return true;
     1358
     1359    for (uint i = 1; i <= last_section; i++)
     1360        if (_cached_cats.find((tsid << 8) | i) == _cached_cats.end())
     1361            return false;
     1362
     1363    return true;
     1364}
     1365
     1366bool MPEGStreamData::HasCachedAnyCAT(uint tsid) const
     1367{
     1368    QMutexLocker locker(&_cache_lock);
     1369
     1370    for (uint i = 0; i <= 255; i++)
     1371        if (_cached_cats.find((tsid << 8) | i) != _cached_cats.end())
     1372            return true;
     1373
     1374    return false;
     1375}
     1376
     1377bool MPEGStreamData::HasCachedAnyCAT(void) const
     1378{
     1379    QMutexLocker locker(&_cache_lock);
     1380    return _cached_cats.size();
     1381}
     1382
    12241383bool MPEGStreamData::HasCachedAllPMT(uint pnum) const
    12251384{
    12261385    QMutexLocker locker(&_cache_lock);
     
    13241483    return pats;
    13251484}
    13261485
     1486const cat_ptr_t MPEGStreamData::GetCachedCAT(
     1487    uint tsid, uint section_num) const
     1488{
     1489    QMutexLocker locker(&_cache_lock);
     1490    ConditionalAccessTable *cat = NULL;
     1491
     1492    uint key = (tsid << 8) | section_num;
     1493    cat_cache_t::const_iterator it = _cached_cats.find(key);
     1494    if (it != _cached_cats.end())
     1495        IncrementRefCnt(cat = *it);
     1496
     1497    return cat;
     1498}
     1499
     1500cat_vec_t MPEGStreamData::GetCachedCATs(uint tsid) const
     1501{
     1502    QMutexLocker locker(&_cache_lock);
     1503    cat_vec_t cats;
     1504
     1505    for (uint i=0; i < 256; i++)
     1506    {
     1507        ConditionalAccessTable *cat = GetCachedCAT(tsid, i);
     1508        if (cat)
     1509            cats.push_back(cat);
     1510    }
     1511
     1512    return cats;
     1513}
     1514
     1515cat_vec_t MPEGStreamData::GetCachedCATs(void) const
     1516{
     1517    QMutexLocker locker(&_cache_lock);
     1518    cat_vec_t cats;
     1519
     1520    cat_cache_t::const_iterator it = _cached_cats.begin();
     1521    for (; it != _cached_cats.end(); ++it)
     1522    {
     1523        ConditionalAccessTable* cat = *it;
     1524        IncrementRefCnt(cat);
     1525        cats.push_back(cat);
     1526    }
     1527
     1528    return cats;
     1529}
     1530
    13271531const pmt_ptr_t MPEGStreamData::GetCachedPMT(
    13281532    uint program_num, uint section_num) const
    13291533{
     
    14011605    pats.clear();
    14021606}
    14031607
     1608void MPEGStreamData::ReturnCachedCATTables(cat_vec_t &cats) const
     1609{
     1610    for (cat_vec_t::iterator it = cats.begin(); it != cats.end(); ++it)
     1611        ReturnCachedTable(*it);
     1612    cats.clear();
     1613}
     1614
     1615void MPEGStreamData::ReturnCachedCATTables(cat_map_t &cats) const
     1616{
     1617    for (cat_map_t::iterator it = cats.begin(); it != cats.end(); ++it)
     1618        ReturnCachedCATTables(*it);
     1619    cats.clear();
     1620}
     1621
    14041622void MPEGStreamData::ReturnCachedPMTTables(pmt_vec_t &pmts) const
    14051623{
    14061624    for (pmt_vec_t::iterator it = pmts.begin(); it != pmts.end(); ++it)
     
    14401658        _cached_pats[(tid << 8) | psip->Section()] = NULL;
    14411659        delete psip;
    14421660    }
     1661    else if (TableID::CAT == psip->TableID() &&
     1662             (_cached_cats[(tid << 8) | psip->Section()] == psip))
     1663    {
     1664        _cached_cats[(tid << 8) | psip->Section()] = NULL;
     1665        delete psip;
     1666    }
    14431667    else if ((TableID::PMT == psip->TableID()) &&
    14441668             (_cached_pmts[(tid << 8) | psip->Section()] == psip))
    14451669    {
     
    14731697    _cached_pats[key] = pat;
    14741698}
    14751699
     1700void MPEGStreamData::CacheCAT(const ConditionalAccessTable *_cat)
     1701{
     1702    ConditionalAccessTable *cat = new ConditionalAccessTable(*_cat);
     1703    uint key = (_cat->TableIDExtension() << 8) | _cat->Section();
     1704
     1705    QMutexLocker locker(&_cache_lock);
     1706
     1707    cat_cache_t::iterator it = _cached_cats.find(key);
     1708    if (it != _cached_cats.end())
     1709        DeleteCachedTable(*it);
     1710
     1711    _cached_cats[key] = cat;
     1712}
     1713
    14761714void MPEGStreamData::CachePMT(const ProgramMapTable *_pmt)
    14771715{
    14781716    ProgramMapTable *pmt = new ProgramMapTable(*_pmt);
  • mpegstreamdata.h

     
    3333typedef QMap<uint, pat_vec_t>                  pat_map_t;
    3434typedef QMap<uint, ProgramAssociationTable*>   pat_cache_t;
    3535
     36typedef ConditionalAccessTable*                cat_ptr_t;
     37typedef vector<const ConditionalAccessTable*>  cat_vec_t;
     38typedef QMap<uint, cat_vec_t>                  cat_map_t;
     39typedef QMap<uint, ConditionalAccessTable*>    cat_cache_t;
     40
    3641typedef ProgramMapTable*                pmt_ptr_t;
    3742typedef vector<const ProgramMapTable*>  pmt_vec_t;
    3843typedef QMap<uint, pmt_vec_t>           pmt_map_t;
     
    169174        return *it;
    170175    }
    171176
     177    void SetVersionCAT(uint tsid, int version, uint last_section)
     178    {
     179        if (VersionCAT(tsid) == version)
     180            return;
     181        _cat_version[tsid] = version;
     182        init_sections(_cat_section_seen[tsid], last_section);
     183    }
     184    int  VersionCAT(uint tsid) const
     185    {
     186        const QMap<uint, int>::const_iterator it = _cat_version.find(tsid);
     187        if (it == _cat_version.end())
     188            return -1;
     189        return *it;
     190    }
     191
    172192    void SetVersionPMT(uint program_num, int version, uint last_section)
    173193    {
    174194        if (VersionPMT(program_num) == version)
     
    189209    bool PATSectionSeen(   uint tsid, uint section) const;
    190210    bool HasAllPATSections(uint tsid) const;
    191211
     212    void SetCATSectionSeen(uint tsid, uint section);
     213    bool CATSectionSeen(   uint tsid, uint section) const;
     214    bool HasAllCATSections(uint tsid) const;
     215
    192216    void SetPMTSectionSeen(uint prog_num, uint section);
    193217    bool PMTSectionSeen(   uint prog_num, uint section) const;
    194218    bool HasAllPMTSections(uint prog_num) const;
     
    200224    bool HasCachedAnyPAT(uint tsid) const;
    201225    bool HasCachedAnyPAT(void) const;
    202226
     227    bool HasCachedAllCAT(uint tsid) const;
     228    bool HasCachedAnyCAT(uint tsid) const;
     229    bool HasCachedAnyCAT(void) const;
     230
    203231    bool HasCachedAllPMT(uint program_num) const;
    204232    bool HasCachedAnyPMT(uint program_num) const;
    205233    bool HasCachedAllPMTs(void) const;
     
    210238    pat_vec_t       GetCachedPATs(void) const;
    211239    pat_map_t       GetCachedPATMap(void) const;
    212240
     241    const cat_ptr_t GetCachedCAT(uint tsid, uint section_num) const;
     242    cat_vec_t       GetCachedCATs(uint tsid) const;
     243    cat_vec_t       GetCachedCATs(void) const;
     244    cat_map_t       GetCachedCATMap(void) const;
     245
    213246    const pmt_ptr_t GetCachedPMT(uint program_num, uint section_num) const;
    214247    pmt_vec_t GetCachedPMTs(void) const;
    215248    pmt_map_t GetCachedPMTMap(void) const;
     
    217250    virtual void ReturnCachedTable(const PSIPTable *psip) const;
    218251    virtual void ReturnCachedPATTables(pat_vec_t&) const;
    219252    virtual void ReturnCachedPATTables(pat_map_t&) const;
     253    virtual void ReturnCachedCATTables(cat_vec_t&) const;
     254    virtual void ReturnCachedCATTables(cat_map_t&) const;
    220255    virtual void ReturnCachedPMTTables(pmt_vec_t&) const;
    221256    virtual void ReturnCachedPMTTables(pmt_map_t&) const;
    222257
     
    297332        { _partial_pes_packet_cache.remove(pid); }
    298333    void DeletePartialPES(uint pid);
    299334    void ProcessPAT(const ProgramAssociationTable *pat);
     335    void ProcessCAT(const ConditionalAccessTable *pat);
    300336    void ProcessPMT(const ProgramMapTable *pmt);
    301337    void ProcessEncryptedPacket(const TSPacket&);
    302338
     
    308344    void IncrementRefCnt(const PSIPTable *psip) const;
    309345    virtual bool DeleteCachedTable(PSIPTable *psip) const;
    310346    void CachePAT(const ProgramAssociationTable *pat);
     347    void CacheCAT(const ConditionalAccessTable *pat);
    311348    void CachePMT(const ProgramMapTable *pmt);
    312349
    313350  protected:
     
    348385
    349386    // Table versions
    350387    QMap<uint, int>           _pat_version;
     388    QMap<uint, int>           _cat_version;
    351389    QMap<uint, int>           _pmt_version;
    352390
    353391    sections_map_t            _pat_section_seen;
     392    sections_map_t            _cat_section_seen;
    354393    sections_map_t            _pmt_section_seen;
    355394
    356395    // PSIP construction
     
    360399    bool                             _cache_tables;
    361400    mutable QMutex                   _cache_lock;
    362401    mutable pat_cache_t              _cached_pats;
     402    mutable cat_cache_t              _cached_cats;
    363403    mutable pmt_cache_t              _cached_pmts;
    364404    mutable psip_refcnt_map_t        _cached_ref_cnt;
    365405    mutable psip_refcnt_map_t        _cached_slated_for_deletion;