vdr-plugin-iptv/pidscanner.c

160 lines
5.4 KiB
C
Raw Permalink Normal View History

/*
* pidscanner.c: IPTV plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
*/
#include "common.h"
#include "pidscanner.h"
2008-02-02 22:06:14 +01:00
#define PIDSCANNER_TIMEOUT_IN_MS 15000 /* 15s timeout for detection */
#define PIDSCANNER_APID_COUNT 5 /* minimum count of audio pid samples for pid detection */
#define PIDSCANNER_VPID_COUNT 5 /* minimum count of video pid samples for pid detection */
#define PIDSCANNER_PID_DELTA_COUNT 100 /* minimum count of pid samples for audio/video only pid detection */
cPidScanner::cPidScanner(void)
2013-02-23 14:31:11 +01:00
: timeoutM(0),
channelIdM(tChannelID::InvalidID),
processM(true),
vPidM(0xFFFF),
aPidM(0xFFFF),
numVpidsM(0),
numApidsM(0)
{
2015-03-08 13:33:18 +01:00
debug1("%s", __PRETTY_FUNCTION__);
}
cPidScanner::~cPidScanner()
{
2015-03-08 13:33:18 +01:00
debug1("%s", __PRETTY_FUNCTION__);
}
2013-02-23 14:31:11 +01:00
void cPidScanner::SetChannel(const tChannelID &channelIdP)
{
2015-03-08 13:33:18 +01:00
debug1("%s (%s)", __PRETTY_FUNCTION__, *channelIdP.ToString());
2013-02-23 14:31:11 +01:00
channelIdM = channelIdP;
vPidM = 0xFFFF;
numVpidsM = 0;
aPidM = 0xFFFF;
numApidsM = 0;
processM = true;
}
2013-02-23 14:31:11 +01:00
void cPidScanner::Process(const uint8_t* bufP)
{
2015-03-08 13:33:18 +01:00
debug16("%s", __PRETTY_FUNCTION__);
2013-02-23 14:31:11 +01:00
if (!processM)
return;
// Stop scanning after defined timeout
2013-02-23 14:31:11 +01:00
if (timeoutM.TimedOut()) {
2015-03-08 13:33:18 +01:00
debug1("%s Timed out determining pids", __PRETTY_FUNCTION__);
2013-02-23 14:31:11 +01:00
processM = false;
}
// Verify TS packet
2013-02-23 14:31:11 +01:00
if (bufP[0] != 0x47) {
error("Not TS packet: 0x%02X", bufP[0]);
return;
}
// Found TS packet
2013-02-23 14:31:11 +01:00
int pid = ts_pid(bufP);
int xpid = (bufP[1] << 8 | bufP[2]);
// Check if payload available
2013-02-23 14:31:11 +01:00
uint8_t count = payload(bufP);
if (count == 0)
return;
if (xpid & 0x4000) {
// Stream start (Payload Unit Start Indicator)
2013-02-23 14:31:11 +01:00
uchar *d = (uint8_t*)bufP;
d += 4;
// pointer to payload
2013-02-23 14:31:11 +01:00
if (bufP[3] & 0x20)
d += d[0] + 1;
// Skip adaption field
2013-02-23 14:31:11 +01:00
if (bufP[3] & 0x10) {
// Payload present
if ((d[0] == 0) && (d[1] == 0) && (d[2] == 1)) {
// PES packet start
int sid = d[3];
// Stream ID
if ((sid >= 0xC0) && (sid <= 0xDF)) {
2013-02-23 14:31:11 +01:00
if (pid < aPidM) {
2015-03-08 13:33:18 +01:00
debug1("%s Found lower Apid: 0x%X instead of 0x%X", __PRETTY_FUNCTION__, pid, aPidM);
2013-02-23 14:31:11 +01:00
aPidM = pid;
numApidsM = 1;
}
2013-02-23 14:31:11 +01:00
else if (pid == aPidM) {
++numApidsM;
2015-03-08 13:33:18 +01:00
debug1("%s Incrementing Apids, now at %d", __PRETTY_FUNCTION__, numApidsM);
}
}
else if ((sid >= 0xE0) && (sid <= 0xEF)) {
2013-02-23 14:31:11 +01:00
if (pid < vPidM) {
2015-03-08 13:33:18 +01:00
debug1("%s Found lower Vpid: 0x%X instead of 0x%X", __PRETTY_FUNCTION__, pid, vPidM);
2013-02-23 14:31:11 +01:00
vPidM = pid;
numVpidsM = 1;
}
2013-02-23 14:31:11 +01:00
else if (pid == vPidM) {
++numVpidsM;
2015-03-08 13:33:18 +01:00
debug1("%s Incrementing Vpids, now at %d", __PRETTY_FUNCTION__, numVpidsM);
}
}
}
2013-02-23 14:31:11 +01:00
if (((numVpidsM >= PIDSCANNER_VPID_COUNT) && (numApidsM >= PIDSCANNER_APID_COUNT)) ||
(abs(numApidsM - numVpidsM) >= PIDSCANNER_PID_DELTA_COUNT)) {
// Lock channels for pid updates
2015-09-19 16:20:56 +02:00
timeoutM.Set(PIDSCANNER_TIMEOUT_IN_MS);
cStateKey StateKey;
cChannels *Channels = cChannels::GetChannelsWrite(StateKey, 10);
if (!Channels)
return;
2015-09-19 16:20:56 +02:00
bool ChannelsModified = false;
cChannel *IptvChannel = Channels->GetByChannelID(channelIdM);
2009-02-25 21:52:25 +01:00
if (IptvChannel) {
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
2010-06-06 19:36:58 +02:00
int Atypes[MAXAPIDS + 1] = { 0 };
2009-02-25 21:52:25 +01:00
int Dpids[MAXDPIDS + 1] = { 0 };
2010-06-06 19:36:58 +02:00
int Dtypes[MAXDPIDS + 1] = { 0 };
2009-02-25 21:52:25 +01:00
int Spids[MAXSPIDS + 1] = { 0 };
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
int Vtype = IptvChannel->Vtype();
2009-02-25 21:52:25 +01:00
int Ppid = IptvChannel->Ppid();
int Tpid = IptvChannel->Tpid();
bool foundApid = false;
2013-02-23 14:31:11 +01:00
if (numVpidsM < PIDSCANNER_VPID_COUNT)
vPidM = 0; // No detected video pid
else if (numApidsM < PIDSCANNER_APID_COUNT)
aPidM = 0; // No detected audio pid
for (unsigned int i = 0; i < MAXAPIDS; ++i) {
2009-02-25 21:52:25 +01:00
Apids[i] = IptvChannel->Apid(i);
2010-06-06 19:36:58 +02:00
Atypes[i] = IptvChannel->Atype(i);
2013-02-23 14:31:11 +01:00
if (Apids[i] && (Apids[i] == aPidM))
2009-02-25 21:52:25 +01:00
foundApid = true;
}
2010-06-06 19:36:58 +02:00
if (!foundApid) {
2013-02-23 14:31:11 +01:00
Apids[0] = aPidM;
2010-06-06 19:36:58 +02:00
Atypes[0] = 4;
}
for (unsigned int i = 0; i < MAXDPIDS; ++i) {
2009-02-25 21:52:25 +01:00
Dpids[i] = IptvChannel->Dpid(i);
2010-06-06 19:36:58 +02:00
Dtypes[i] = IptvChannel->Dtype(i);
}
2009-02-25 21:52:25 +01:00
for (unsigned int i = 0; i < MAXSPIDS; ++i)
Spids[i] = IptvChannel->Spid(i);
2015-03-08 13:33:18 +01:00
debug1("%s vpid=0x%04X, apid=0x%04X", __PRETTY_FUNCTION__, vPidM, aPidM);
2015-09-19 16:20:56 +02:00
ChannelsModified |= IptvChannel->SetPids(vPidM, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
2009-02-25 21:52:25 +01:00
}
2015-09-19 16:20:56 +02:00
StateKey.Remove(ChannelsModified);
2013-02-23 14:31:11 +01:00
processM = false;
}
}
}
}