mirror of
https://github.com/rofafor/vdr-plugin-iptv.git
synced 2023-10-10 13:37:03 +02:00
New and improved section filter code from Kernel. Objectified neatly in
separate class.
This commit is contained in:
parent
91f5dced05
commit
679ccd0e35
4
Makefile
4
Makefile
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for a Video Disk Recorder plugin
|
# Makefile for a Video Disk Recorder plugin
|
||||||
#
|
#
|
||||||
# $Id: Makefile,v 1.7 2007/09/19 15:14:32 ajhseppa Exp $
|
# $Id: Makefile,v 1.8 2007/09/24 13:03:38 ajhseppa Exp $
|
||||||
|
|
||||||
# Debugging on/off
|
# Debugging on/off
|
||||||
#IPTV_DEBUG = 1
|
#IPTV_DEBUG = 1
|
||||||
@ -57,7 +57,7 @@ endif
|
|||||||
|
|
||||||
### The object files (add further files here):
|
### The object files (add further files here):
|
||||||
|
|
||||||
OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o protocolhttp.o protocolfile.o pidfilter.o
|
OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o protocolhttp.o protocolfile.o sectionfilter.o
|
||||||
|
|
||||||
### The main target:
|
### The main target:
|
||||||
|
|
||||||
|
100
device.c
100
device.c
@ -3,15 +3,13 @@
|
|||||||
*
|
*
|
||||||
* See the README file for copyright information and how to reach the author.
|
* See the README file for copyright information and how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.c,v 1.35 2007/09/22 17:37:57 rahrenbe Exp $
|
* $Id: device.c,v 1.36 2007/09/24 13:03:38 ajhseppa Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#define IPTV_FILTER_FILENAME "/tmp/vdr-iptv%d.filter%d"
|
|
||||||
|
|
||||||
#define IPTV_MAX_DEVICES 8
|
#define IPTV_MAX_DEVICES 8
|
||||||
|
|
||||||
cIptvDevice * IptvDevices[IPTV_MAX_DEVICES];
|
cIptvDevice * IptvDevices[IPTV_MAX_DEVICES];
|
||||||
@ -34,21 +32,9 @@ cIptvDevice::cIptvDevice(unsigned int Index)
|
|||||||
pHttpProtocol = new cIptvProtocolHttp();
|
pHttpProtocol = new cIptvProtocolHttp();
|
||||||
pFileProtocol = new cIptvProtocolFile();
|
pFileProtocol = new cIptvProtocolFile();
|
||||||
pIptvStreamer = new cIptvStreamer(tsBuffer, &mutex);
|
pIptvStreamer = new cIptvStreamer(tsBuffer, &mutex);
|
||||||
// Initialize filters
|
// Initialize filter pointers
|
||||||
memset(&filter, '\0', sizeof(filter));
|
memset(&secfilters, '\0', sizeof(secfilters));
|
||||||
init_trans(&filter);
|
|
||||||
for (int i = 0; i < eMaxFilterCount; ++i) {
|
|
||||||
struct stat sb;
|
|
||||||
snprintf(filters[i].pipeName, sizeof(filters[i].pipeName),
|
|
||||||
IPTV_FILTER_FILENAME, deviceIndex, i);
|
|
||||||
stat(filters[i].pipeName, &sb);
|
|
||||||
if (S_ISFIFO(sb.st_mode))
|
|
||||||
unlink(filters[i].pipeName);
|
|
||||||
memset(filters[i].pipeName, '\0', sizeof(filters[i].pipeName));
|
|
||||||
filters[i].fifoDesc = -1;
|
|
||||||
filters[i].readDesc = -1;
|
|
||||||
filters[i].active = false;
|
|
||||||
}
|
|
||||||
StartSectionHandler();
|
StartSectionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +44,7 @@ cIptvDevice::~cIptvDevice()
|
|||||||
delete pIptvStreamer;
|
delete pIptvStreamer;
|
||||||
delete pUdpProtocol;
|
delete pUdpProtocol;
|
||||||
delete tsBuffer;
|
delete tsBuffer;
|
||||||
// Iterate over all filters and clear their settings
|
// Destroy all filters
|
||||||
for (int i = 0; i < eMaxFilterCount; ++i)
|
for (int i = 0; i < eMaxFilterCount; ++i)
|
||||||
DeleteFilter(i);
|
DeleteFilter(i);
|
||||||
}
|
}
|
||||||
@ -170,15 +156,9 @@ bool cIptvDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
|||||||
bool cIptvDevice::DeleteFilter(unsigned int Index)
|
bool cIptvDevice::DeleteFilter(unsigned int Index)
|
||||||
{
|
{
|
||||||
debug("cIptvDevice::DeleteFilter(%d) Index=%d\n", deviceIndex, Index);
|
debug("cIptvDevice::DeleteFilter(%d) Index=%d\n", deviceIndex, Index);
|
||||||
if ((Index < eMaxFilterCount) && filters[Index].active) {
|
if ((Index < eMaxFilterCount) && secfilters[Index]) {
|
||||||
close(filters[Index].fifoDesc);
|
delete secfilters[Index];
|
||||||
close(filters[Index].readDesc);
|
secfilters[Index] = NULL;
|
||||||
unlink(filters[Index].pipeName);
|
|
||||||
memset(filters[Index].pipeName, '\0', sizeof(filters[Index].pipeName));
|
|
||||||
filters[Index].fifoDesc = -1;
|
|
||||||
filters[Index].readDesc = -1;
|
|
||||||
filters[Index].active = false;
|
|
||||||
clear_trans_filt(&filter, Index);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -188,33 +168,12 @@ int cIptvDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
|
|||||||
{
|
{
|
||||||
// Search the next free filter slot
|
// Search the next free filter slot
|
||||||
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
|
||||||
if (!filters[i].active) {
|
if (!secfilters[i]) {
|
||||||
debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i);
|
debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i);
|
||||||
uint8_t mask[eMaxFilterMaskLen] = { 0 };
|
|
||||||
uint8_t filt[eMaxFilterMaskLen] = { 0 };
|
secfilters[i] = new cIptvSectionFilter(i, deviceIndex, Pid, Tid,
|
||||||
mask[0] = Mask;
|
Mask);
|
||||||
filt[0] = Tid;
|
return secfilters[i]->GetReadDesc();
|
||||||
int err = set_trans_filt(&filter, i, Pid, &mask[0], &filt[0], 0);
|
|
||||||
if (err < 0)
|
|
||||||
error("Cannot set filter %d\n", i);
|
|
||||||
memset(filters[i].pipeName, '\0', sizeof(filters[i].pipeName));
|
|
||||||
snprintf(filters[i].pipeName, sizeof(filters[i].pipeName),
|
|
||||||
IPTV_FILTER_FILENAME, deviceIndex, i);
|
|
||||||
struct stat sb;
|
|
||||||
stat(filters[i].pipeName, &sb);
|
|
||||||
if (S_ISFIFO(sb.st_mode))
|
|
||||||
unlink(filters[i].pipeName);
|
|
||||||
err = mknod(filters[i].pipeName, 0644 | S_IFIFO, 0);
|
|
||||||
if (err < 0) {
|
|
||||||
char tmp[64];
|
|
||||||
error("ERROR: mknod(): %s", strerror_r(errno, tmp, sizeof(tmp)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Create descriptors
|
|
||||||
filters[i].fifoDesc = open(filters[i].pipeName, O_RDWR | O_NONBLOCK);
|
|
||||||
filters[i].readDesc = open(filters[i].pipeName, O_RDONLY | O_NONBLOCK);
|
|
||||||
filters[i].active = true;
|
|
||||||
return filters[i].readDesc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No free filter slot found
|
// No free filter slot found
|
||||||
@ -225,7 +184,7 @@ bool cIptvDevice::CloseFilter(int Handle)
|
|||||||
{
|
{
|
||||||
debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle);
|
debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle);
|
||||||
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
|
||||||
if (Handle == filters[i].readDesc)
|
if (Handle == secfilters[i]->GetReadDesc())
|
||||||
return DeleteFilter(i);
|
return DeleteFilter(i);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -300,35 +259,10 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
|
|||||||
}
|
}
|
||||||
isPacketDelivered = true;
|
isPacketDelivered = true;
|
||||||
Data = p;
|
Data = p;
|
||||||
memcpy(filter.packet, p, sizeof(filter.packet));
|
// Run the data through all filters
|
||||||
trans_filt(p, TS_SIZE, &filter);
|
|
||||||
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
|
||||||
if (filters[i].active) {
|
if (secfilters[i]) {
|
||||||
section *filtered = get_filt_sec(&filter, i);
|
secfilters[i]->ProcessData(p);
|
||||||
if (filtered->found) {
|
|
||||||
// Select on the fifo emptyness. Using null timeout to return immediately
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
fd_set rfds;
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(filters[i].fifoDesc, &rfds);
|
|
||||||
int retval = select(filters[i].fifoDesc + 1, &rfds, NULL, NULL, &tv);
|
|
||||||
// Check if error
|
|
||||||
if (retval < 0) {
|
|
||||||
char tmp[64];
|
|
||||||
error("ERROR: select(): %s", strerror_r(errno, tmp, sizeof(tmp)));
|
|
||||||
DeleteFilter(i);
|
|
||||||
}
|
|
||||||
// There is no data in the fifo, more can be written
|
|
||||||
else if (!retval) {
|
|
||||||
int err = write(filters[i].fifoDesc, filtered->payload, filtered->length + 3);
|
|
||||||
if (err < 0) {
|
|
||||||
char tmp[64];
|
|
||||||
error("ERROR: write(): %s", strerror_r(errno, tmp, sizeof(tmp)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
15
device.h
15
device.h
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* See the README file for copyright information and how to reach the author.
|
* See the README file for copyright information and how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.h,v 1.15 2007/09/22 08:17:35 ajhseppa Exp $
|
* $Id: device.h,v 1.16 2007/09/24 13:03:38 ajhseppa Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __IPTV_DEVICE_H
|
#ifndef __IPTV_DEVICE_H
|
||||||
@ -16,15 +16,8 @@
|
|||||||
#include "protocolfile.h"
|
#include "protocolfile.h"
|
||||||
#include "streamer.h"
|
#include "streamer.h"
|
||||||
|
|
||||||
#include "pidfilter.h"
|
#include "sectionfilter.h"
|
||||||
|
|
||||||
struct filterInfo {
|
|
||||||
bool active;
|
|
||||||
int fifoDesc;
|
|
||||||
int readDesc;
|
|
||||||
char pipeName[128];
|
|
||||||
int lastProvided;
|
|
||||||
};
|
|
||||||
|
|
||||||
class cIptvDevice : public cDevice {
|
class cIptvDevice : public cDevice {
|
||||||
// static ones
|
// static ones
|
||||||
@ -38,7 +31,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
eMaxFilterCount = 32,
|
eMaxFilterCount = 32,
|
||||||
eMaxFilterMaskLen = 16
|
|
||||||
};
|
};
|
||||||
unsigned int deviceIndex;
|
unsigned int deviceIndex;
|
||||||
bool isPacketDelivered;
|
bool isPacketDelivered;
|
||||||
@ -50,8 +42,7 @@ private:
|
|||||||
cIptvProtocolFile *pFileProtocol;
|
cIptvProtocolFile *pFileProtocol;
|
||||||
cIptvStreamer *pIptvStreamer;
|
cIptvStreamer *pIptvStreamer;
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
trans filter;
|
cIptvSectionFilter* secfilters[eMaxFilterCount];
|
||||||
filterInfo filters[eMaxFilterCount];
|
|
||||||
|
|
||||||
// constructor & destructor
|
// constructor & destructor
|
||||||
public:
|
public:
|
||||||
|
354
sectionfilter.c
Normal file
354
sectionfilter.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* sectionfilter.c: IPTV plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: sectionfilter.c,v 1.1 2007/09/24 13:03:38 ajhseppa Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sectionfilter.h"
|
||||||
|
|
||||||
|
#define IPTV_FILTER_FILENAME "/tmp/vdr-iptv%d.filter%d"
|
||||||
|
|
||||||
|
cIptvSectionFilter::cIptvSectionFilter(int Index, int devInd,
|
||||||
|
u_short Pid, u_char Tid, u_char Mask)
|
||||||
|
: pusi_seen(0),
|
||||||
|
feedcc(0),
|
||||||
|
doneq(0),
|
||||||
|
secbuf(NULL),
|
||||||
|
secbufp(0),
|
||||||
|
seclen(0),
|
||||||
|
tsfeedp(0),
|
||||||
|
crc_val(0),
|
||||||
|
pid(Pid),
|
||||||
|
id(Index)
|
||||||
|
{
|
||||||
|
debug("cIptvSectionFilter::cIptvSectionFilter(%d)\n", Index);
|
||||||
|
|
||||||
|
memset(secbuf_base, '\0', sizeof(secbuf_base));
|
||||||
|
memset(filter_value, '\0', sizeof(filter_value));
|
||||||
|
memset(filter_mask, '\0', sizeof(filter_mask));
|
||||||
|
memset(filter_mode, '\0', sizeof(filter_mode));
|
||||||
|
memset(maskandmode, '\0', sizeof(maskandmode));
|
||||||
|
memset(maskandnotmode, '\0', sizeof(maskandnotmode));
|
||||||
|
memset(pipeName, '\0', sizeof(pipeName));
|
||||||
|
|
||||||
|
SetPipeName(devInd);
|
||||||
|
|
||||||
|
filter_value[0] = !Tid;
|
||||||
|
filter_mask[0] = Mask;
|
||||||
|
|
||||||
|
uint8_t mask, mode, local_doneq = 0;
|
||||||
|
for (int i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
|
||||||
|
mode = filter_mode[i];
|
||||||
|
mask = filter_mask[i];
|
||||||
|
maskandmode[i] = mask & mode;
|
||||||
|
local_doneq |= maskandnotmode[i] = mask & ~mode;
|
||||||
|
}
|
||||||
|
doneq = local_doneq ? 1 : 0;
|
||||||
|
|
||||||
|
struct stat sb;
|
||||||
|
stat(pipeName, &sb);
|
||||||
|
if (S_ISFIFO(sb.st_mode))
|
||||||
|
unlink(pipeName);
|
||||||
|
int err = mknod(pipeName, 0644 | S_IFIFO, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
char tmp[64];
|
||||||
|
error("ERROR: mknod(): %s", strerror_r(errno, tmp, sizeof(tmp)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create descriptors
|
||||||
|
fifoDescriptor = open(pipeName, O_RDWR | O_NONBLOCK);
|
||||||
|
readDescriptor = open(pipeName, O_RDONLY | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
cIptvSectionFilter::~cIptvSectionFilter()
|
||||||
|
{
|
||||||
|
debug("cIptvSectionFilter::~cIptvSectionfilter()\n");
|
||||||
|
close(fifoDescriptor);
|
||||||
|
close(readDescriptor);
|
||||||
|
unlink(pipeName);
|
||||||
|
memset(pipeName, '\0', sizeof(pipeName));
|
||||||
|
fifoDescriptor = -1;
|
||||||
|
readDescriptor = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cIptvSectionFilter::SetPipeName(int deviceIndex)
|
||||||
|
{
|
||||||
|
snprintf(pipeName, sizeof(pipeName), IPTV_FILTER_FILENAME, deviceIndex, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvSectionFilter::GetReadDesc()
|
||||||
|
{
|
||||||
|
return readDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t cIptvSectionFilter::section_length(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t cIptvSectionFilter::ts_pid(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
return ((buf[1] & 0x1f) << 8) + buf[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t cIptvSectionFilter::payload(const uint8_t *tsp)
|
||||||
|
{
|
||||||
|
if (!(tsp[3] & 0x10)) // no payload?
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tsp[3] & 0x20) { // adaptation field?
|
||||||
|
if (tsp[4] > 183) // corrupted data?
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 184 - 1 - tsp[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 184;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvSectionFilter::dvb_dmxdev_section_callback(const uint8_t *buffer1, size_t buffer1_len,
|
||||||
|
const uint8_t *buffer2, size_t buffer2_len,
|
||||||
|
enum dmx_success success)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(fifoDescriptor, &rfds);
|
||||||
|
int retval = select(fifoDescriptor + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
|
||||||
|
// Check if error
|
||||||
|
if (retval < 0) {
|
||||||
|
char tmp[64];
|
||||||
|
error("ERROR: select(): %s", strerror_r(errno, tmp, sizeof(tmp)));
|
||||||
|
}
|
||||||
|
// There is no data in the fifo, more can be written
|
||||||
|
else if (!retval) {
|
||||||
|
#ifdef DEBUG_PRINTF
|
||||||
|
printf("id = %d, pid %d would now write %d data to buffer\n", id, pid, buffer1_len);
|
||||||
|
for (unsigned int i = 0; i < buffer1_len; ++i) {
|
||||||
|
printf("0x%X ", buffer1[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
retval = write(fifoDescriptor, buffer1, buffer1_len);
|
||||||
|
|
||||||
|
if (retval < 0) {
|
||||||
|
char tmp[64];
|
||||||
|
error("ERROR: write(): %s", strerror_r(errno, tmp, sizeof(tmp)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_PRINTF
|
||||||
|
else if (retval) {
|
||||||
|
printf("id %d pid %d data is already present\n", id, pid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cIptvSectionFilter::dvb_dmx_swfilter_section_new()
|
||||||
|
{
|
||||||
|
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||||
|
if (secbufp < tsfeedp) {
|
||||||
|
int i, n = tsfeedp - secbufp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Section padding is done with 0xff bytes entirely.
|
||||||
|
* Due to speed reasons, we won't check all of them
|
||||||
|
* but just first and last.
|
||||||
|
*/
|
||||||
|
if (secbuf[0] != 0xff || secbuf[n - 1] != 0xff) {
|
||||||
|
printf("dvb_demux.c section ts padding loss: %d/%d\n",
|
||||||
|
n, tsfeedp);
|
||||||
|
printf("dvb_demux.c pad data:");
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
printf(" %02x", secbuf[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tsfeedp = secbufp = seclen = 0;
|
||||||
|
secbuf = secbuf_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int cIptvSectionFilter::dvb_dmx_swfilter_sectionfilter()
|
||||||
|
{
|
||||||
|
uint8_t neq = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
|
||||||
|
uint8_t local_xor = filter_value[i] ^ secbuf[i];
|
||||||
|
|
||||||
|
if (maskandmode[i] & local_xor) {
|
||||||
|
#ifdef DEBUG_PRINTF
|
||||||
|
printf("maskandmode discard\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
neq |= maskandnotmode[i] & local_xor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doneq && !neq) {
|
||||||
|
#ifdef DEBUG_PRINTF
|
||||||
|
printf("doneq discard, doneq = 0x%X, neq = 0x%X\n", doneq, !neq);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dvb_dmxdev_section_callback(secbuf, seclen, NULL, 0, DMX_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int cIptvSectionFilter::dvb_dmx_swfilter_section_feed()
|
||||||
|
{
|
||||||
|
if (dvb_dmx_swfilter_sectionfilter() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
seclen = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvSectionFilter::dvb_dmx_swfilter_section_copy_dump(const uint8_t *buf, uint8_t len)
|
||||||
|
{
|
||||||
|
uint16_t limit, seclen_local, n;
|
||||||
|
|
||||||
|
if (tsfeedp >= DMX_MAX_SECFEED_SIZE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
|
||||||
|
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||||
|
printf("dvb_demux.c section buffer full loss: %d/%d\n",
|
||||||
|
tsfeedp + len - DMX_MAX_SECFEED_SIZE,
|
||||||
|
DMX_MAX_SECFEED_SIZE);
|
||||||
|
#endif
|
||||||
|
len = DMX_MAX_SECFEED_SIZE - tsfeedp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(secbuf_base + tsfeedp, buf, len);
|
||||||
|
tsfeedp += len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump all the sections we can find in the data (Emard)
|
||||||
|
*/
|
||||||
|
limit = tsfeedp;
|
||||||
|
if (limit > DMX_MAX_SECFEED_SIZE) {
|
||||||
|
return -1; /* internal error should never happen */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to be sure always set secbuf */
|
||||||
|
secbuf = secbuf_base + secbufp;
|
||||||
|
|
||||||
|
for (n = 0; secbufp + 2 < limit; n++) {
|
||||||
|
seclen_local = section_length(secbuf);
|
||||||
|
if (seclen_local <= 0 || seclen_local > DMX_MAX_SECTION_SIZE
|
||||||
|
|| seclen_local + secbufp > limit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_PRINTF
|
||||||
|
printf("Non-mismatching seclen! %d, limit = %d\n", seclen_local, limit);
|
||||||
|
#endif
|
||||||
|
seclen = seclen_local;
|
||||||
|
crc_val = ~0;
|
||||||
|
/* dump [secbuf .. secbuf+seclen) */
|
||||||
|
if (pusi_seen) {
|
||||||
|
dvb_dmx_swfilter_section_feed();
|
||||||
|
}
|
||||||
|
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||||
|
else
|
||||||
|
printf("dvb_demux.c pusi not seen, discarding section data\n");
|
||||||
|
#endif
|
||||||
|
secbufp += seclen_local; /* secbufp and secbuf moving together is */
|
||||||
|
secbuf += seclen_local; /* redundant but saves pointer arithmetic */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cIptvSectionFilter::ProcessData(const uint8_t* buf)
|
||||||
|
{
|
||||||
|
if (buf[0] != 0x47) {
|
||||||
|
error("Not TS packet: 0x%X\n", buf[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop if not the PID this filter is looking for
|
||||||
|
if (ts_pid(buf) != pid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t count = payload(buf);
|
||||||
|
|
||||||
|
if (count == 0) /* count == 0 if no payload or out of range */
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t p = 188 - count; /* payload start */
|
||||||
|
|
||||||
|
uint8_t cc = buf[3] & 0x0f;
|
||||||
|
int ccok = ((feedcc + 1) & 0x0f) == cc;
|
||||||
|
feedcc = cc;
|
||||||
|
|
||||||
|
int dc_i = 0;
|
||||||
|
if (buf[3] & 0x20) {
|
||||||
|
/* adaption field present, check for discontinuity_indicator */
|
||||||
|
if ((buf[4] > 0) && (buf[5] & 0x80))
|
||||||
|
dc_i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!ccok || dc_i) {
|
||||||
|
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||||
|
printf("dvb_demux.c discontinuity detected %d bytes lost\n",
|
||||||
|
count);
|
||||||
|
/*
|
||||||
|
* those bytes under sume circumstances will again be reported
|
||||||
|
* in the following dvb_dmx_swfilter_section_new
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Discontinuity detected. Reset pusi_seen = 0 to
|
||||||
|
* stop feeding of suspicious data until next PUSI=1 arrives
|
||||||
|
*/
|
||||||
|
pusi_seen = 0;
|
||||||
|
dvb_dmx_swfilter_section_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[1] & 0x40) {
|
||||||
|
/* PUSI=1 (is set), section boundary is here */
|
||||||
|
if (count > 1 && buf[p] < count) {
|
||||||
|
#ifdef DEBUG_PRINTF
|
||||||
|
printf("Valid section\n");
|
||||||
|
#endif
|
||||||
|
const uint8_t *before = &buf[p + 1];
|
||||||
|
uint8_t before_len = buf[p];
|
||||||
|
const uint8_t *after = &before[before_len];
|
||||||
|
uint8_t after_len = count - 1 - before_len;
|
||||||
|
|
||||||
|
dvb_dmx_swfilter_section_copy_dump(before, before_len);
|
||||||
|
/* before start of new section, set pusi_seen = 1 */
|
||||||
|
pusi_seen = 1;
|
||||||
|
dvb_dmx_swfilter_section_new();
|
||||||
|
dvb_dmx_swfilter_section_copy_dump(after, after_len);
|
||||||
|
}
|
||||||
|
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
|
||||||
|
else if (count > 0)
|
||||||
|
printf("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
/* PUSI=0 (is not set), no section boundary */
|
||||||
|
dvb_dmx_swfilter_section_copy_dump(&buf[p], count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
117
sectionfilter.h
Normal file
117
sectionfilter.h
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* sectionfilter.h: IPTV plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: sectionfilter.h,v 1.1 2007/09/24 13:03:39 ajhseppa Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IPTV_SECTIONFILTER_H
|
||||||
|
#define __IPTV_SECTIONFILTER_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifndef DMX_MAX_FILTER_SIZE
|
||||||
|
#define DMX_MAX_FILTER_SIZE 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DMX_MAX_SECTION_SIZE
|
||||||
|
#define DMX_MAX_SECTION_SIZE 4096
|
||||||
|
#endif
|
||||||
|
#ifndef DMX_MAX_SECFEED_SIZE
|
||||||
|
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DVB_DEMUX_MASK_MAX 18
|
||||||
|
|
||||||
|
class cIptvSectionFilter {
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum dmx_success {
|
||||||
|
DMX_OK = 0, /* Received Ok */
|
||||||
|
DMX_LENGTH_ERROR, /* Incorrect length */
|
||||||
|
DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
|
||||||
|
DMX_CRC_ERROR, /* Incorrect CRC */
|
||||||
|
DMX_FRAME_ERROR, /* Frame alignment error */
|
||||||
|
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
|
||||||
|
DMX_MISSED_ERROR /* Receiver missed packet */
|
||||||
|
} ;
|
||||||
|
|
||||||
|
int fifoDescriptor;
|
||||||
|
int readDescriptor;
|
||||||
|
|
||||||
|
int pusi_seen;
|
||||||
|
int feedcc;
|
||||||
|
int doneq;
|
||||||
|
|
||||||
|
uint8_t *secbuf;
|
||||||
|
uint8_t secbuf_base[DMX_MAX_SECFEED_SIZE];
|
||||||
|
uint16_t secbufp;
|
||||||
|
uint16_t seclen;
|
||||||
|
uint16_t tsfeedp;
|
||||||
|
uint32_t crc_val;
|
||||||
|
|
||||||
|
uint16_t pid;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t filter_value[DMX_MAX_FILTER_SIZE];
|
||||||
|
uint8_t filter_mask[DMX_MAX_FILTER_SIZE];
|
||||||
|
uint8_t filter_mode[DMX_MAX_FILTER_SIZE];
|
||||||
|
|
||||||
|
uint8_t maskandmode[DMX_MAX_FILTER_SIZE];
|
||||||
|
uint8_t maskandnotmode[DMX_MAX_FILTER_SIZE];
|
||||||
|
|
||||||
|
char pipeName[128];
|
||||||
|
|
||||||
|
inline uint16_t section_length(const uint8_t *buf);
|
||||||
|
inline uint16_t ts_pid(const uint8_t *buf);
|
||||||
|
inline uint8_t payload(const uint8_t *tsp);
|
||||||
|
|
||||||
|
int dvb_dmxdev_section_callback(const uint8_t *buffer1,
|
||||||
|
size_t buffer1_len,
|
||||||
|
const uint8_t *buffer2,
|
||||||
|
size_t buffer2_len,
|
||||||
|
enum dmx_success success);
|
||||||
|
|
||||||
|
void dvb_dmx_swfilter_section_new();
|
||||||
|
|
||||||
|
int dvb_dmx_swfilter_sectionfilter();
|
||||||
|
|
||||||
|
inline int dvb_dmx_swfilter_section_feed();
|
||||||
|
|
||||||
|
int dvb_dmx_swfilter_section_copy_dump(const uint8_t *buf,
|
||||||
|
uint8_t len);
|
||||||
|
|
||||||
|
int GetFifoDesc();
|
||||||
|
void ClearPipeName();
|
||||||
|
void SetPipeName(int deviceIndex);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// constructor & destructor
|
||||||
|
cIptvSectionFilter(int Index, int devInd, u_short Pid, u_char Tid,
|
||||||
|
u_char Mask);
|
||||||
|
|
||||||
|
virtual ~cIptvSectionFilter();
|
||||||
|
|
||||||
|
void ProcessData(const uint8_t* buf);
|
||||||
|
|
||||||
|
int GetReadDesc();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __IPTV_SECTIONFILTER_H
|
||||||
|
|
Loading…
Reference in New Issue
Block a user