Skip to content

Commit 06712fa

Browse files
authored
Merge pull request #3688 from WXbet/lamedb
[scan] extract and store PIDs and CAIDs from PMT during channel scan
2 parents 7f93082 + 7f7e6e1 commit 06712fa

File tree

4 files changed

+215
-14
lines changed

4 files changed

+215
-14
lines changed

lib/dvb/cahandler.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -938,12 +938,34 @@ int eDVBCAService::buildCAPMT(eTable<ProgramMapSection> *ptr)
938938
pmtpid = dvbservice->getCacheEntry(eDVBService::cPMTPID);
939939
if (pmtpid > 0)
940940
{
941-
m_capmt[total++] = 0x0d; // Datastream (DSM CC)
942-
m_capmt[total++] = pmtpid>>8;
943-
m_capmt[total++] = pmtpid&0xFF;
944-
m_capmt[total++] = 0x00;
945-
m_capmt[total++] = 0x00;
946-
m_capmt[8] = (int)m_capmt[8] + 5;
941+
// total is length returned by writeToBuffer, add 5 for header offset
942+
size_t pos = 5 + total;
943+
m_capmt[pos++] = 0x0d; // Datastream (DSM CC)
944+
m_capmt[pos++] = pmtpid>>8;
945+
m_capmt[pos++] = pmtpid&0xFF;
946+
m_capmt[pos++] = 0x00;
947+
m_capmt[pos++] = 0x00;
948+
// update length field - handle both short and long form
949+
// byte 8 is length byte: if bit 7 is set, it indicates number of following length bytes
950+
if (m_capmt[8] & 0x80)
951+
{
952+
// long form: m_capmt[8] = 0x81 or 0x82, actual length in following bytes
953+
int lenbytes = m_capmt[8] & 0x7f;
954+
if (lenbytes == 1)
955+
m_capmt[9] += 5;
956+
else if (lenbytes == 2)
957+
{
958+
int len = (m_capmt[9] << 8) | m_capmt[10];
959+
len += 5;
960+
m_capmt[9] = len >> 8;
961+
m_capmt[10] = len & 0xff;
962+
}
963+
}
964+
else
965+
{
966+
// short form: length directly in byte 8
967+
m_capmt[8] += 5;
968+
}
947969
}
948970
}
949971
}

lib/dvb/scan.cpp

Lines changed: 177 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <fcntl.h>
2+
#include <algorithm>
23
#include <lib/dvb/idvb.h>
34
#include <dvbsi++/descriptor_tag.h>
45
#include <dvbsi++/service_descriptor.h>
@@ -9,6 +10,7 @@
910
#include <dvbsi++/logical_channel_descriptor.h>
1011
#include <dvbsi++/cable_delivery_system_descriptor.h>
1112
#include <dvbsi++/ca_identifier_descriptor.h>
13+
#include <dvbsi++/ca_descriptor.h>
1214
#include <dvbsi++/registration_descriptor.h>
1315
#include <dvbsi++/extension_descriptor.h>
1416
#include <dvbsi++/frequency_list_descriptor.h>
@@ -472,6 +474,11 @@ void eDVBScan::PMTready(int err)
472474
bool have_audio = false;
473475
bool have_video = false;
474476
unsigned short pcrpid = 0xFFFF;
477+
unsigned short videopid = 0xFFFF;
478+
unsigned short audiopid = 0xFFFF;
479+
eDVBService::cacheID audioCacheId = eDVBService::cMPEGAPID;
480+
int videotype = -1; // -1 = MPEG2 (default)
481+
CAID_LIST caids;
475482
std::vector<ProgramMapSection*>::const_iterator i;
476483

477484
for (i = m_PMT->getSections().begin(); i != m_PMT->getSections().end(); ++i)
@@ -485,28 +492,61 @@ void eDVBScan::PMTready(int err)
485492
for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
486493
{
487494
int isaudio = 0, isvideo = 0, is_scrambled = 0, forced_audio = 0, forced_video = 0;
495+
eDVBService::cacheID currentAudioCacheId = eDVBService::cMPEGAPID;
496+
int currentVideoType = -1; // -1 = MPEG2 (default)
488497
switch ((*es)->getType())
489498
{
490499
case 0x1b: // AVC Video Stream (MPEG4 H264)
500+
isvideo = 1;
501+
forced_video = 1;
502+
currentVideoType = 1; // MPEG4_H264
503+
break;
491504
case 0x24: // H265 HEVC
505+
isvideo = 1;
506+
forced_video = 1;
507+
currentVideoType = 7; // H265_HEVC
508+
break;
492509
case 0x10: // MPEG 4 Part 2
510+
isvideo = 1;
511+
forced_video = 1;
512+
currentVideoType = 4; // MPEG4_Part2
513+
break;
493514
case 0x01: // MPEG 1 video
515+
isvideo = 1;
516+
forced_video = 1;
517+
currentVideoType = 5; // MPEG1
518+
break;
494519
case 0x02: // MPEG 2 video
495520
isvideo = 1;
496521
forced_video = 1;
497-
[[fallthrough]];
522+
currentVideoType = -1; // MPEG2 (default, stored as -1)
523+
break;
498524
case 0x03: // MPEG 1 audio
499525
case 0x04: // MPEG 2 audio
526+
if (!isvideo)
527+
{
528+
forced_audio = 1;
529+
isaudio = 1;
530+
currentAudioCacheId = eDVBService::cMPEGAPID;
531+
}
532+
[[fallthrough]];
500533
case 0x0f: // MPEG 2 AAC
501534
case 0x11: // MPEG 4 AAC
502-
if (!isvideo)
535+
if (!isvideo && !forced_audio)
503536
{
504537
forced_audio = 1;
505538
isaudio = 1;
539+
currentAudioCacheId = eDVBService::cAACAPID;
506540
}
507541
[[fallthrough]];
508542
case 0x06: // PES Private
509-
case 0x81: // user private
543+
case 0x81: // user private - often AC3
544+
if ((*es)->getType() == 0x81 && !forced_audio)
545+
{
546+
isaudio = 1;
547+
currentAudioCacheId = eDVBService::cAC3PID;
548+
}
549+
[[fallthrough]];
510550
case 0xEA: // TS_PSI_ST_SMPTE_VC1
511551
for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
512552
desc != (*es)->getDescriptors()->end(); ++desc)
@@ -521,10 +561,24 @@ void eDVBScan::PMTready(int err)
521561
case 0x1C: // TS_PSI_DT_MPEG4_Audio
522562
case 0x2B: // TS_PSI_DT_MPEG2_AAC
523563
case AAC_DESCRIPTOR:
564+
isaudio = 1;
565+
currentAudioCacheId = eDVBService::cAACAPID;
566+
break;
524567
case AC3_DESCRIPTOR:
568+
isaudio = 1;
569+
currentAudioCacheId = eDVBService::cAC3PID;
570+
break;
571+
case ENHANCED_AC3_DESCRIPTOR:
572+
isaudio = 1;
573+
currentAudioCacheId = eDVBService::cDDPPID;
574+
break;
525575
case DTS_DESCRIPTOR:
576+
isaudio = 1;
577+
currentAudioCacheId = eDVBService::cDTSPID;
578+
break;
526579
case AUDIO_STREAM_DESCRIPTOR:
527580
isaudio = 1;
581+
currentAudioCacheId = eDVBService::cMPEGAPID;
528582
break;
529583
case 0x28: // TS_PSI_DT_AVC
530584
case 0x1B: // TS_PSI_DT_MPEG4_Video
@@ -537,9 +591,16 @@ void eDVBScan::PMTready(int err)
537591
switch (d->getFormatIdentifier())
538592
{
539593
case 0x44545331 ... 0x44545333: // DTS1/DTS2/DTS3
594+
isaudio = 1;
595+
currentAudioCacheId = eDVBService::cDTSPID;
596+
break;
540597
case 0x41432d33: // == 'AC-3'
598+
isaudio = 1;
599+
currentAudioCacheId = eDVBService::cAC3PID;
600+
break;
541601
case 0x42535344: // == 'BSSD' (LPCM)
542602
isaudio = 1;
603+
currentAudioCacheId = eDVBService::cLPCMPID;
543604
break;
544605
case 0x56432d31: // == 'VC-1'
545606
isvideo = 1;
@@ -554,16 +615,36 @@ void eDVBScan::PMTready(int err)
554615
}
555616
}
556617
if (tag == CA_DESCRIPTOR)
618+
{
557619
is_scrambled = 1;
620+
CaDescriptor *ca = (CaDescriptor*)(*desc);
621+
uint16_t caid = ca->getCaSystemId();
622+
if (caid != 0 && std::find(caids.begin(), caids.end(), caid) == caids.end())
623+
caids.push_back(caid);
624+
}
558625
}
559626
[[fallthrough]];
560627
default:
561628
break;
562629
}
563630
if (isvideo)
631+
{
564632
have_video = true;
633+
if (videopid == 0xFFFF)
634+
{
635+
videopid = (*es)->getPid();
636+
videotype = currentVideoType;
637+
}
638+
}
565639
else if (isaudio)
640+
{
566641
have_audio = true;
642+
if (audiopid == 0xFFFF)
643+
{
644+
audiopid = (*es)->getPid();
645+
audioCacheId = currentAudioCacheId;
646+
}
647+
}
567648
else
568649
continue;
569650
if (is_scrambled)
@@ -573,16 +654,30 @@ void eDVBScan::PMTready(int err)
573654
desc != pmt.getDescriptors()->end(); ++desc)
574655
{
575656
if ((*desc)->getTag() == CA_DESCRIPTOR)
657+
{
576658
scrambled = true;
659+
CaDescriptor *ca = (CaDescriptor*)(*desc);
660+
uint16_t caid = ca->getCaSystemId();
661+
if (caid != 0 && std::find(caids.begin(), caids.end(), caid) == caids.end())
662+
caids.push_back(caid);
663+
}
577664
}
578665
}
579666
m_pmt_in_progress->second.scrambled = scrambled;
667+
m_pmt_in_progress->second.pcrPid = pcrpid;
668+
m_pmt_in_progress->second.videoPid = videopid;
669+
m_pmt_in_progress->second.audioPid = audiopid;
670+
m_pmt_in_progress->second.audioCacheId = audioCacheId;
671+
m_pmt_in_progress->second.videoType = videotype;
672+
m_pmt_in_progress->second.caids = caids;
580673
if ( have_video )
581674
m_pmt_in_progress->second.serviceType = 1;
582675
else if ( have_audio )
583676
m_pmt_in_progress->second.serviceType = 2;
584677
else
585678
m_pmt_in_progress->second.serviceType = 100;
679+
SCAN_eDebug("[eDVBScan] SID %04x: vpid=%04x (vtype=%d) apid=%04x (cacheId=%d) pcrpid=%04x caids=%d",
680+
m_pmt_in_progress->first, videopid, videotype, audiopid, audioCacheId, pcrpid, (int)caids.size());
586681
}
587682
if (err == -1) // timeout or removed by sdt
588683
m_pmts_to_read.erase(m_pmt_in_progress++);
@@ -1242,6 +1337,20 @@ void eDVBScan::channelDone()
12421337
m_last_service = i.first;
12431338
m_event(evtNewService);
12441339
}
1340+
1341+
/* store cached PIDs from PMT - use service from m_new_services (may exist from SDT) */
1342+
ePtr<eDVBService> target = i.first->second;
1343+
if (m_pmt_in_progress->second.videoPid != 0xFFFF)
1344+
target->setCacheEntry(eDVBService::cVPID, m_pmt_in_progress->second.videoPid);
1345+
if (m_pmt_in_progress->second.audioPid != 0xFFFF)
1346+
target->setCacheEntry(m_pmt_in_progress->second.audioCacheId, m_pmt_in_progress->second.audioPid);
1347+
if (m_pmt_in_progress->second.pcrPid != 0xFFFF)
1348+
target->setCacheEntry(eDVBService::cPCRPID, m_pmt_in_progress->second.pcrPid);
1349+
target->setCacheEntry(eDVBService::cPMTPID, m_pmt_in_progress->second.pmtPid);
1350+
1351+
/* store CAIDs from PMT */
1352+
if (!m_pmt_in_progress->second.caids.empty())
1353+
target->m_ca = m_pmt_in_progress->second.caids;
12451354
}
12461355
else
12471356
SCAN_eDebug("[eDVBScan] dont add... is scrambled!");
@@ -1554,6 +1663,31 @@ void eDVBScan::insertInto(iDVBChannelList *db, bool backgroundscanresult)
15541663
}
15551664
if (service->second->m_ca.size())
15561665
dvb_service->m_ca = service->second->m_ca;
1666+
1667+
/* update cached PIDs from scan if the new service has them */
1668+
int vpid = service->second->getCacheEntry(eDVBService::cVPID);
1669+
if (vpid != -1)
1670+
dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1671+
int vtype = service->second->getCacheEntry(eDVBService::cVTYPE);
1672+
if (vtype != -1)
1673+
dvb_service->setCacheEntry(eDVBService::cVTYPE, vtype);
1674+
/* copy audio PID with correct audio type */
1675+
for (int j = 0; j < eDVBService::nAudioCacheTags; ++j)
1676+
{
1677+
int apid = service->second->getCacheEntry(eDVBService::audioCacheTags[j]);
1678+
if (apid != -1)
1679+
{
1680+
dvb_service->setCacheEntry(eDVBService::audioCacheTags[j], apid);
1681+
break;
1682+
}
1683+
}
1684+
int pcrpid = service->second->getCacheEntry(eDVBService::cPCRPID);
1685+
if (pcrpid != -1)
1686+
dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1687+
int pmtpid = service->second->getCacheEntry(eDVBService::cPMTPID);
1688+
if (pmtpid != -1)
1689+
dvb_service->setCacheEntry(eDVBService::cPMTPID, pmtpid);
1690+
15571691
if (!backgroundscanresult) // do not remove new found flags when this is the result of a 'background scan'
15581692
dvb_service->m_flags &= ~eDVBService::dxNewFound;
15591693
}
@@ -1655,6 +1789,21 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
16551789
ref.set(chid);
16561790
ref.setServiceID(service_id);
16571791

1792+
/* copy cached PIDs and CAIDs from PMT if available (only if PMT was already processed) */
1793+
if (it != m_pmts_to_read.end() && it->second.videoPid != 0xFFFF)
1794+
{
1795+
service->setCacheEntry(eDVBService::cVPID, it->second.videoPid);
1796+
if (it->second.videoType != -1) // only set if not MPEG2 (default)
1797+
service->setCacheEntry(eDVBService::cVTYPE, it->second.videoType);
1798+
if (it->second.audioPid != 0xFFFF)
1799+
service->setCacheEntry(it->second.audioCacheId, it->second.audioPid);
1800+
if (it->second.pcrPid != 0xFFFF)
1801+
service->setCacheEntry(eDVBService::cPCRPID, it->second.pcrPid);
1802+
service->setCacheEntry(eDVBService::cPMTPID, it->second.pmtPid);
1803+
if (!it->second.caids.empty())
1804+
service->m_ca = it->second.caids;
1805+
}
1806+
16581807
for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
16591808
desc != (*s)->getDescriptors()->end(); ++desc)
16601809
{
@@ -1704,7 +1853,9 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
17041853
for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
17051854
{
17061855
SCAN_eDebugNoNewLine(" %04x", *i);
1707-
service->m_ca.push_front(*i);
1856+
/* avoid duplicates - CAIDs may already be set from PMT */
1857+
if (std::find(service->m_ca.begin(), service->m_ca.end(), *i) == service->m_ca.end())
1858+
service->m_ca.push_front(*i);
17081859
}
17091860
SCAN_eDebugNoNewLine("\n");
17101861
break;
@@ -1738,7 +1889,8 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
17381889
}
17391890
if (m_pmt_running && m_pmt_in_progress->first == service_id)
17401891
m_abort_current_pmt = true;
1741-
else
1892+
else if (it != m_pmts_to_read.end() && (it->second.videoPid != 0xFFFF || it->second.audioPid != 0xFFFF))
1893+
/* only erase if PMT was already processed (has video or audio), otherwise channelDone() needs it */
17421894
m_pmts_to_read.erase(service_id);
17431895
}
17441896

@@ -1770,6 +1922,8 @@ RESULT eDVBScan::processVCT(eDVBNamespace dvbnamespace, const VirtualChannelTabl
17701922
}
17711923
SCAN_eDebugNoNewLine("\n");
17721924

1925+
std::map<unsigned short, struct service>::iterator it = m_pmts_to_read.find(service_id);
1926+
17731927
if (!(m_flags & scanOnlyFree) || !is_crypted)
17741928
{
17751929
char number[32];
@@ -1803,6 +1957,22 @@ RESULT eDVBScan::processVCT(eDVBNamespace dvbnamespace, const VirtualChannelTabl
18031957
ref.setServiceID(service_id);
18041958
ref.setServiceType(servicetype);
18051959
ref.setSourceID(source_id);
1960+
1961+
/* copy cached PIDs and CAIDs from PMT if available (only if PMT was already processed) */
1962+
if (it != m_pmts_to_read.end() && it->second.videoPid != 0xFFFF)
1963+
{
1964+
service->setCacheEntry(eDVBService::cVPID, it->second.videoPid);
1965+
if (it->second.videoType != -1) // only set if not MPEG2 (default)
1966+
service->setCacheEntry(eDVBService::cVTYPE, it->second.videoType);
1967+
if (it->second.audioPid != 0xFFFF)
1968+
service->setCacheEntry(it->second.audioCacheId, it->second.audioPid);
1969+
if (it->second.pcrPid != 0xFFFF)
1970+
service->setCacheEntry(eDVBService::cPCRPID, it->second.pcrPid);
1971+
service->setCacheEntry(eDVBService::cPMTPID, it->second.pmtPid);
1972+
if (!it->second.caids.empty())
1973+
service->m_ca = it->second.caids;
1974+
}
1975+
18061976
service->m_service_name = (*s)->getName();
18071977
/* strip trailing spaces */
18081978
service->m_service_name = service->m_service_name.erase(service->m_service_name.find_last_not_of(" ") + 1);
@@ -1845,7 +2015,8 @@ RESULT eDVBScan::processVCT(eDVBNamespace dvbnamespace, const VirtualChannelTabl
18452015
}
18462016
if (m_pmt_running && m_pmt_in_progress->first == service_id)
18472017
m_abort_current_pmt = true;
1848-
else
2018+
else if (it != m_pmts_to_read.end() && (it->second.videoPid != 0xFFFF || it->second.audioPid != 0xFFFF))
2019+
/* only erase if PMT was already processed (has video or audio), otherwise channelDone() needs it */
18492020
m_pmts_to_read.erase(service_id);
18502021
}
18512022

0 commit comments

Comments
 (0)