1
0
mirror of https://github.com/rofafor/vdr-plugin-iptv.git synced 2023-10-10 13:37:03 +02:00
vdr-plugin-iptv/sectionfilter.c

213 lines
5.2 KiB
C
Raw Normal View History

/*
* sectionfilter.c: IPTV plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
*/
#include "config.h"
#include "sectionfilter.h"
2013-02-23 14:31:11 +01:00
cIptvSectionFilter::cIptvSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP)
: pusiSeenM(0),
feedCcM(0),
doneqM(0),
secBufM(NULL),
secBufpM(0),
secLenM(0),
tsFeedpM(0),
pidM(pidP),
devIdM(deviceIndexP)
{
2013-02-23 16:12:46 +01:00
//debug("cIptvSectionFilter::%s(%d, %d)", __FUNCTION__, devIdM, pidM);
2009-02-27 15:05:19 +01:00
int i;
2013-02-23 14:31:11 +01:00
memset(secBufBaseM, 0, sizeof(secBufBaseM));
memset(filterValueM, 0, sizeof(filterValueM));
memset(filterMaskM, 0, sizeof(filterMaskM));
memset(filterModeM, 0, sizeof(filterModeM));
memset(maskAndModeM, 0, sizeof(maskAndModeM));
memset(maskAndNotModeM, 0, sizeof(maskAndNotModeM));
2013-02-23 14:31:11 +01:00
filterValueM[0] = tidP;
filterMaskM[0] = maskP;
// Invert the filter
2009-02-27 15:05:19 +01:00
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i)
2013-02-23 14:31:11 +01:00
filterValueM[i] ^= 0xFF;
2013-02-23 14:31:11 +01:00
uint8_t mask, mode, doneq = 0;
2009-02-27 15:05:19 +01:00
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i) {
2013-02-23 14:31:11 +01:00
mode = filterModeM[i];
mask = filterMaskM[i];
maskAndModeM[i] = (uint8_t)(mask & mode);
maskAndNotModeM[i] = (uint8_t)(mask & ~mode);
doneq |= maskAndNotModeM[i];
2008-01-30 22:57:33 +01:00
}
2013-02-23 14:31:11 +01:00
doneqM = doneq ? 1 : 0;
// Create filtering buffer
2013-02-23 14:31:11 +01:00
ringbufferM = new cRingBufferLinear(KILOBYTE(128), 0, false, *cString::sprintf("IPTV SECTION %d/%d", devIdM, pidM));
if (ringbufferM)
ringbufferM->SetTimeouts(10, 10);
else
2013-02-23 14:31:11 +01:00
error("Failed to allocate buffer for section filter (device=%d pid=%d): ", devIdM, pidM);
}
cIptvSectionFilter::~cIptvSectionFilter()
{
2013-02-23 16:12:46 +01:00
//debug("cIptvSectionFilter::%s(%d, %d)", __FUNCTION__, devIdM, pidM);
2013-02-23 14:31:11 +01:00
DELETE_POINTER(ringbufferM);
secBufM = NULL;
}
int cIptvSectionFilter::Read(void *Data, size_t Length)
{
int count = 0;
2013-02-23 14:31:11 +01:00
uchar *p = ringbufferM->Get(count);
if (p && count > 0) {
memcpy(Data, p, count);
2013-02-23 14:31:11 +01:00
ringbufferM->Del(count);
}
return count;
}
2013-02-23 14:31:11 +01:00
inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *dataP)
{
2013-02-23 14:31:11 +01:00
return (uint16_t)(3 + ((dataP[1] & 0x0f) << 8) + dataP[2]);
}
2009-02-27 15:05:19 +01:00
void cIptvSectionFilter::New(void)
{
2013-02-23 14:31:11 +01:00
tsFeedpM = secBufpM = secLenM = 0;
secBufM = secBufBaseM;
}
2009-02-27 15:05:19 +01:00
int cIptvSectionFilter::Filter(void)
{
2013-02-23 14:31:11 +01:00
if (secBufM) {
2011-06-15 16:49:15 +02:00
int i;
uint8_t neq = 0;
2009-03-20 16:43:31 +01:00
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i) {
2013-02-23 14:31:11 +01:00
uint8_t calcxor = (uint8_t)(filterValueM[i] ^ secBufM[i]);
if (maskAndModeM[i] & calcxor)
2009-03-20 16:43:31 +01:00
return 0;
2013-02-23 14:31:11 +01:00
neq |= (maskAndNotModeM[i] & calcxor);
2009-03-20 16:43:31 +01:00
}
2013-02-23 14:31:11 +01:00
if (doneqM && !neq)
2009-03-20 16:43:31 +01:00
return 0;
2013-02-23 14:31:11 +01:00
if (ringbufferM) {
int len = ringbufferM->Put(secBufM, secLenM);
if (len != secLenM)
ringbufferM->ReportOverflow(secLenM - len);
2009-03-20 16:43:31 +01:00
// Update statistics
2009-06-19 12:28:53 +02:00
AddSectionStatistic(len, 1);
2009-03-20 16:43:31 +01:00
}
2007-09-24 19:20:58 +02:00
}
2009-02-27 15:05:19 +01:00
return 0;
}
2009-02-27 15:05:19 +01:00
inline int cIptvSectionFilter::Feed(void)
{
2009-02-27 15:05:19 +01:00
if (Filter() < 0)
2007-09-24 19:20:58 +02:00
return -1;
2013-02-23 14:31:11 +01:00
secLenM = 0;
return 0;
}
2013-02-23 14:31:11 +01:00
int cIptvSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
{
2013-02-23 14:31:11 +01:00
uint16_t limit, seclen, n;
2013-02-23 14:31:11 +01:00
if (tsFeedpM >= DMX_MAX_SECFEED_SIZE)
2007-09-24 19:20:58 +02:00
return 0;
2013-02-23 14:31:11 +01:00
if (tsFeedpM + lenP > DMX_MAX_SECFEED_SIZE)
lenP = (uint8_t)(DMX_MAX_SECFEED_SIZE - tsFeedpM);
2013-02-23 14:31:11 +01:00
if (lenP <= 0)
2007-09-24 19:20:58 +02:00
return 0;
2013-02-23 14:31:11 +01:00
memcpy(secBufBaseM + tsFeedpM, bufP, lenP);
tsFeedpM = uint16_t(tsFeedpM + lenP);
2013-02-23 14:31:11 +01:00
limit = tsFeedpM;
2007-09-24 19:20:58 +02:00
if (limit > DMX_MAX_SECFEED_SIZE)
2009-03-20 17:00:17 +01:00
return -1; // internal error should never happen
2009-02-27 15:05:19 +01:00
// Always set secbuf
2013-02-23 14:31:11 +01:00
secBufM = secBufBaseM + secBufpM;
2013-02-23 14:31:11 +01:00
for (n = 0; secBufpM + 2 < limit; ++n) {
seclen = GetLength(secBufM);
if ((seclen <= 0) || (seclen > DMX_MAX_SECTION_SIZE) || ((seclen + secBufpM) > limit))
2007-09-24 19:20:58 +02:00
return 0;
2013-02-23 14:31:11 +01:00
secLenM = seclen;
if (pusiSeenM)
2009-02-27 15:05:19 +01:00
Feed();
2013-02-23 14:31:11 +01:00
secBufpM = uint16_t(secBufpM + seclen);
secBufM += seclen;
2007-09-24 19:20:58 +02:00
}
return 0;
}
2013-02-23 14:31:11 +01:00
void cIptvSectionFilter::Process(const uint8_t* dataP)
{
2013-02-23 14:31:11 +01:00
if (dataP[0] != TS_SYNC_BYTE)
2007-09-24 19:20:58 +02:00
return;
// Stop if not the PID this filter is looking for
2013-02-23 14:31:11 +01:00
if (ts_pid(dataP) != pidM)
2007-09-24 19:20:58 +02:00
return;
2013-02-23 14:31:11 +01:00
uint8_t count = payload(dataP);
2009-02-27 15:05:19 +01:00
// Check if no payload or out of range
if (count == 0)
2007-09-24 19:20:58 +02:00
return;
2009-02-27 15:05:19 +01:00
// Payload start
2009-06-19 12:28:53 +02:00
uint8_t p = (uint8_t)(TS_SIZE - count);
2013-02-23 14:31:11 +01:00
uint8_t cc = (uint8_t)(dataP[3] & 0x0f);
int ccok = ((feedCcM + 1) & 0x0f) == cc;
feedCcM = cc;
int dc_i = 0;
2013-02-23 14:31:11 +01:00
if (dataP[3] & 0x20) {
2009-02-27 15:05:19 +01:00
// Adaption field present, check for discontinuity_indicator
2013-02-23 14:31:11 +01:00
if ((dataP[4] > 0) && (dataP[5] & 0x80))
2007-09-24 19:20:58 +02:00
dc_i = 1;
}
if (!ccok || dc_i) {
2013-02-23 14:31:11 +01:00
// Discontinuity detected. Reset pusiSeenM = 0 to
2009-02-27 15:05:19 +01:00
// stop feeding of suspicious data until next PUSI=1 arrives
2013-02-23 14:31:11 +01:00
pusiSeenM = 0;
2009-02-27 15:05:19 +01:00
New();
2007-09-24 19:20:58 +02:00
}
2013-02-23 14:31:11 +01:00
if (dataP[1] & 0x40) {
2009-02-27 15:05:19 +01:00
// PUSI=1 (is set), section boundary is here
2013-02-23 14:31:11 +01:00
if (count > 1 && dataP[p] < count) {
const uint8_t *before = &dataP[p + 1];
uint8_t before_len = dataP[p];
2007-09-24 19:20:58 +02:00
const uint8_t *after = &before[before_len];
2009-06-19 12:28:53 +02:00
uint8_t after_len = (uint8_t)(count - 1 - before_len);
2009-02-27 15:05:19 +01:00
CopyDump(before, before_len);
2007-09-24 19:20:58 +02:00
2013-02-23 14:31:11 +01:00
// Before start of new section, set pusiSeenM = 1
pusiSeenM = 1;
2009-02-27 15:05:19 +01:00
New();
CopyDump(after, after_len);
2007-09-24 19:20:58 +02:00
}
}
else {
2009-02-27 15:05:19 +01:00
// PUSI=0 (is not set), no section boundary
2013-02-23 14:31:11 +01:00
CopyDump(&dataP[p], count);
2007-09-24 19:20:58 +02:00
}
}