vdr-plugin-iptv/pidscanner.c

165 lines
5.3 KiB
C

/*
* 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"
#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)
: timeout(0),
process(true),
Vpid(0xFFFF),
Apid(0xFFFF),
numVpids(0),
numApids(0)
{
debug("cPidScanner::cPidScanner()\n");
channel = cChannel();
}
cPidScanner::~cPidScanner()
{
debug("cPidScanner::~cPidScanner()\n");
}
void cPidScanner::SetChannel(const cChannel *Channel)
{
if (Channel) {
debug("cPidScanner::SetChannel(): %s\n", Channel->Parameters());
channel = *Channel;
}
else {
debug("cPidScanner::SetChannel()\n");
channel = cChannel();
}
Vpid = 0xFFFF;
numVpids = 0;
Apid = 0xFFFF;
numApids = 0;
process = true;
timeout.Set(PIDSCANNER_TIMEOUT_IN_MS);
}
void cPidScanner::Process(const uint8_t* buf)
{
//debug("cPidScanner::Process()\n");
if (!process)
return;
// Stop scanning after defined timeout
if (timeout.TimedOut()) {
debug("cPidScanner::Process: Timed out determining pids\n");
process = false;
}
// Verify TS packet
if (buf[0] != 0x47) {
error("Not TS packet: 0x%X\n", buf[0]);
return;
}
// Found TS packet
int pid = ts_pid(buf);
int xpid = (buf[1] << 8 | buf[2]);
// Check if payload available
uint8_t count = payload(buf);
if (count == 0)
return;
if (xpid & 0x4000) {
// Stream start (Payload Unit Start Indicator)
uchar *d = (uint8_t*)buf;
d += 4;
// pointer to payload
if (buf[3] & 0x20)
d += d[0] + 1;
// Skip adaption field
if (buf[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)) {
if (pid < Apid) {
debug("cPidScanner::Process: Found lower Apid: 0x%X instead of 0x%X\n", pid, Apid);
Apid = pid;
numApids = 1;
}
else if (pid == Apid) {
++numApids;
debug("cPidScanner::Process: Incrementing Apids, now at %d\n", numApids);
}
}
else if ((sid >= 0xE0) && (sid <= 0xEF)) {
if (pid < Vpid) {
debug("cPidScanner::Process: Found lower Vpid: 0x%X instead of 0x%X\n", pid, Vpid);
Vpid = pid;
numVpids = 1;
}
else if (pid == Vpid) {
++numVpids;
debug("cPidScanner::Process: Incrementing Vpids, now at %d\n", numVpids);
}
}
}
if (((numVpids >= PIDSCANNER_VPID_COUNT) && (numApids >= PIDSCANNER_APID_COUNT)) ||
(abs(numApids - numVpids) >= PIDSCANNER_PID_DELTA_COUNT)) {
// Lock channels for pid updates
if (!Channels.Lock(true, 10)) {
timeout.Set(PIDSCANNER_TIMEOUT_IN_MS);
return;
}
cChannel *IptvChannel = Channels.GetByChannelID(channel.GetChannelID());
if (IptvChannel) {
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
int Atypes[MAXAPIDS + 1] = { 0 };
int Dpids[MAXDPIDS + 1] = { 0 };
int Dtypes[MAXDPIDS + 1] = { 0 };
int Spids[MAXSPIDS + 1] = { 0 };
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
int Ppid = IptvChannel->Ppid();
int Tpid = IptvChannel->Tpid();
bool foundApid = false;
if (numVpids < PIDSCANNER_VPID_COUNT)
Vpid = 0; // No detected video pid
else if (numApids < PIDSCANNER_APID_COUNT)
Apid = 0; // No detected audio pid
for (unsigned int i = 1; i < MAXAPIDS; ++i) {
Apids[i] = IptvChannel->Apid(i);
Atypes[i] = IptvChannel->Atype(i);
if (Apids[i] && (Apids[i] == Apid))
foundApid = true;
}
if (!foundApid) {
Apids[0] = Apid;
Atypes[0] = 4;
}
for (unsigned int i = 0; i < MAXDPIDS; ++i) {
Dpids[i] = IptvChannel->Dpid(i);
Dtypes[i] = IptvChannel->Dtype(i);
}
for (unsigned int i = 0; i < MAXSPIDS; ++i)
Spids[i] = IptvChannel->Spid(i);
debug("cPidScanner::Process(): Vpid=0x%04X, Apid=0x%04X\n", Vpid, Apid);
int Vtype = IptvChannel->Vtype();
IptvChannel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
}
Channels.Unlock();
process = false;
}
}
}
}