1
0
mirror of https://github.com/vdr-projects/vdr.git synced 2025-03-01 10:50:46 +00:00
vdr/sections.c
Klaus Schmidinger 335a572913 Version 1.3.12
- Removed all error messages from cRecordings::ScanVideoDir() and just skipping
  entries that cause errors in order to avoid failure in case of things like
  broken links etc.
- The function cTimers::SetEvents() now immediately returns if there is some user
  input.
- Fixed handling menu status messages when the list contents is scrolled (thanks to
  Alfred Zastrow for reporting this one).
- Fixed checking the last area for misalignment in cOsd::CanHandleAreas() (thanks
  to Reinhard Nissl for reporting this one).
- No longer adding section filters to the list of filters if they can't be opened
  (thanks to Marco Schlüßler for pointing this out).
- Fixed handling error case '-1' when polling section filters (thanks to Marco
  Schlüßler).
- Fixed handling error case '-1' when polling CAM connections.
- Making sure the OSD reports oeWrongAlignment errors before any oeAreasOverlap
  error (suggested by Reinhard Nissl).
- Avoiding flashing effects in the OSD of full featured DVB cards by explicitly
  clearing the OSD windows before opening them (suggested by Marco Schlüßler).
- Experimental support for NVOD channels. Currently these channels are detected
  and linked to their "base" channels using the same mechanisms as for the
  "linked services" (let's see if this is useful). Thanks to Mike parker for
  helping to test this. Also used some input from the 'autopid' patch by Andreas
  Schultz).
- Now storing the name of the service provider (aka "bouquet") in the channel
  name, separated by a semicolon (see man vdr(5) for details). Explicit usage
  of the various parts of the channel name is yet to come.
- The 'radio' channel icon is now only displayed in the ST:TNG skin if the channel
  actually has an APID.
2004-07-18 18:00:00 +02:00

217 lines
5.6 KiB
C

/*
* sections.c: Section data handling
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: sections.c 1.7 2004/07/17 14:26:32 kls Exp $
*/
#include "sections.h"
#include <unistd.h>
#include "channels.h"
#include "device.h"
// --- cFilterHandle----------------------------------------------------------
class cFilterHandle : public cListObject {
public:
cFilterData filterData;
int handle;
int used;
cFilterHandle(const cFilterData &FilterData);
};
cFilterHandle::cFilterHandle(const cFilterData &FilterData)
{
filterData = FilterData;
handle = -1;
used = 0;
}
// --- cSectionHandlerPrivate ------------------------------------------------
class cSectionHandlerPrivate {
public:
cChannel channel;
};
// --- cSectionHandler -------------------------------------------------------
cSectionHandler::cSectionHandler(cDevice *Device)
:cThread("Section handler")
{
shp = new cSectionHandlerPrivate;
device = Device;
active = false;
statusCount = 0;
on = false;
lastIncompleteSection = 0;
Start();
}
cSectionHandler::~cSectionHandler()
{
active = false;
Cancel(3);
cFilter *fi;
while ((fi = filters.First()) != NULL)
Detach(fi);
delete shp;
}
int cSectionHandler::Source(void)
{
return shp->channel.Source();
}
int cSectionHandler::Transponder(void)
{
return shp->channel.Transponder();
}
const cChannel *cSectionHandler::Channel(void)
{
return &shp->channel;
}
void cSectionHandler::Add(const cFilterData *FilterData)
{
Lock();
statusCount++;
cFilterHandle *fh;
for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask))
break;
}
if (!fh) {
int handle = device->OpenFilter(FilterData->pid, FilterData->tid, FilterData->mask);
if (handle >= 0) {
fh = new cFilterHandle(*FilterData);
fh->handle = handle;
filterHandles.Add(fh);
}
}
if (fh)
fh->used++;
Unlock();
}
void cSectionHandler::Del(const cFilterData *FilterData)
{
Lock();
statusCount++;
cFilterHandle *fh;
for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
if (--fh->used <= 0) {
close(fh->handle);
filterHandles.Del(fh);
break;
}
}
}
Unlock();
}
void cSectionHandler::Attach(cFilter *Filter)
{
Lock();
statusCount++;
filters.Add(Filter);
Filter->sectionHandler = this;
Filter->SetStatus(true);
Unlock();
}
void cSectionHandler::Detach(cFilter *Filter)
{
Lock();
statusCount++;
Filter->SetStatus(false);
Filter->sectionHandler = NULL;
filters.Del(Filter, false);
Unlock();
}
void cSectionHandler::SetChannel(const cChannel *Channel)
{
Lock();
shp->channel = Channel ? *Channel : cChannel();
Unlock();
}
void cSectionHandler::SetStatus(bool On)
{
Lock();
if (on != On) {
statusCount++;
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
fi->SetStatus(false);
if (On)
fi->SetStatus(true);
}
on = On;
}
Unlock();
}
void cSectionHandler::Action(void)
{
active = true;
while (active) {
Lock();
int NumFilters = filterHandles.Count();
pollfd pfd[NumFilters];
for (cFilterHandle *fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
int i = fh->Index();
pfd[i].fd = fh->handle;
pfd[i].events = POLLIN;
}
int oldStatusCount = statusCount;
Unlock();
if (poll(pfd, NumFilters, 1000) > 0) {
bool DeviceHasLock = device->HasLock();
if (!DeviceHasLock)
usleep(100000);
for (int i = 0; i < NumFilters; i++) {
if (pfd[i].revents & POLLIN) {
cFilterHandle *fh = NULL;
LOCK_THREAD;
if (statusCount != oldStatusCount)
break;
for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
if (pfd[i].fd == fh->handle)
break;
}
if (fh) {
// Read section data:
unsigned char buf[4096]; // max. allowed size for any EIT section
int r = safe_read(fh->handle, buf, sizeof(buf));
if (!DeviceHasLock)
continue; // we do the read anyway, to flush any data that might have come from a different transponder
if (r > 3) { // minimum number of bytes necessary to get section length
int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
if (len == r) {
// Distribute data to all attached filters:
int pid = fh->filterData.pid;
int tid = buf[0];
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
if (fi->Matches(pid, tid))
fi->Process(pid, tid, buf, len);
}
}
else if (time(NULL) - lastIncompleteSection > 10) { // log them only every 10 seconds
dsyslog("read incomplete section - len = %d, r = %d", len, r);
lastIncompleteSection = time(NULL);
}
}
}
}
}
}
}
}