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

Compare commits

...

21 Commits

Author SHA1 Message Date
Rolf Ahrenberg
dc64c044a1 Fixed installation target bugs (Thanks to Alexander Grothe). 2014-03-09 16:08:44 +02:00
Rolf Ahrenberg
3dcbff0a71 Updated translation files and version number. 2014-01-19 00:20:08 +02:00
Rolf Ahrenberg
5aefd40d65 Updated translation files and HISTORY. 2014-01-14 18:42:06 +02:00
Rolf Ahrenberg
6b0337d078 Added initial support for cDevice::MaySwitchTransponder(). 2014-01-14 18:40:54 +02:00
Rolf Ahrenberg
9e6d784aec Shutdown devices already in cPluginManager::Stop(). 2014-01-14 18:30:14 +02:00
Rolf Ahrenberg
3f3ba2ad1a Fixed a typo. 2014-01-11 00:35:12 +02:00
Rolf Ahrenberg
a4b9570ae6 Updated copyright headers. 2014-01-11 00:24:31 +02:00
Rolf Ahrenberg
767b1bdac7 Added support for cDevice::GetCurrentlyTunedTransponder(). 2014-01-10 23:59:26 +02:00
Rolf Ahrenberg
6f648401a4 Updated translation files and HISTORY. 2014-01-10 23:22:15 +02:00
Rolf Ahrenberg
b0995c9a9e Added support for cDevice::IsTunedToTransponder(). 2014-01-07 22:24:39 +02:00
Rolf Ahrenberg
412af81271 Fixed a mem leak and re-ordered pointer deletions. 2014-01-07 17:55:13 +02:00
Rolf Ahrenberg
43326bb4ea Whitespace cleanup. 2014-01-07 17:55:08 +02:00
Rolf Ahrenberg
555c08bd4d Updated Makefile. 2014-01-06 22:01:55 +02:00
Rolf Ahrenberg
5ad3103626 Fixed scan-build issues. 2014-01-02 21:47:43 +02:00
Rolf Ahrenberg
a4f0bdf737 Added missing CURL timeouts and improved section id scanner. 2014-01-02 21:35:38 +02:00
Rolf Ahrenberg
01b554a2de Updated README. 2013-04-01 23:11:38 +03:00
Rolf Ahrenberg
225b0cc297 Updated for vdr-2.0.0. 2013-04-01 22:36:41 +03:00
Rolf Ahrenberg
d940e616e3 Fixed and refactored the section filtering code, fixed a possible crash in the file protocol, and updated Makefile's install target. 2013-03-27 22:13:15 +02:00
Rolf Ahrenberg
f30817677e Fixed a nasty network byte order bug. 2013-03-17 01:18:58 +02:00
Rolf Ahrenberg
0c6257e4ca Added SetMenuCategory(mcSetupPlugins). 2013-03-13 23:33:37 +02:00
Rolf Ahrenberg
0caf746ef4 Enabled I/O throttling and tweaked buffer timeouts and tweaked max address string size to include a termination NULL byte. 2013-03-11 18:04:27 +02:00
32 changed files with 524 additions and 255 deletions

30
HISTORY
View File

@@ -199,3 +199,33 @@ VDR Plugin 'iptv' Revision History
- Fixed bugs found in the CURL implementation (Thanks - Fixed bugs found in the CURL implementation (Thanks
to Jeremy Hall). to Jeremy Hall).
- Fixed the channel editor. - Fixed the channel editor.
==================================
VDR Plugin 'iptv' Revision History
==================================
2013-04-01: Version 2.0.0
- Updated for vdr-2.0.0.
- Enabled I/O throttling and tweaked buffer timeouts.
- Fixed a nasty network byte order bug.
- Fixed and refactored the section filtering code.
- Fixed a possible crash in the file protocol.
2014-01-10: Version 2.0.1
- Added missing CURL timeouts.
- Improved section id scanner.
- Added support for cDevice::IsTunedToTransponder() and
cDevice::GetCurrentlyTunedTransponder().
- Fixed a memory leak and some issues reported by scan-build.
2014-01-18: Version 2.0.2
- Made devices to shutdown already in cPluginManager::Stop()
to prevent possible crashes while VDR shutdown.
2014-03-09: Version 2.0.3
- Fixed installation target bugs (Thanks to Alexander Grothe).

View File

@@ -28,10 +28,12 @@ GITTAG = $(shell git describe --always 2>/dev/null)
### The directory environment: ### The directory environment:
# Use package data if installed...otherwise assume we're under the VDR source directory: # Use package data if installed...otherwise assume we're under the VDR source directory:
PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc)) PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell PKG_CONFIG_PATH="$$PKG_CONFIG_PATH:../../.." pkg-config --variable=$(1) vdr))
LIBDIR = $(call PKGCFG,libdir) LIBDIR = $(call PKGCFG,libdir)
LOCDIR = $(call PKGCFG,locdir) LOCDIR = $(call PKGCFG,locdir)
PLGCFG = $(call PKGCFG,plgcfg) PLGCFG = $(call PKGCFG,plgcfg)
RESDIR = $(call PKGCFG,resdir)
CFGDIR = $(call PKGCFG,configdir)
# #
TMPDIR ?= /tmp TMPDIR ?= /tmp
@@ -144,7 +146,12 @@ endif
install-lib: $(SOFILE) install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
install: install-lib install-i18n install-conf:
@mkdir -p $(DESTDIR)$(CFGDIR)/plugins/$(PLUGIN)
@mkdir -p $(DESTDIR)$(RESDIR)/plugins/$(PLUGIN)
@cp -pn $(PLUGIN)/* $(DESTDIR)$(RESDIR)/plugins/$(PLUGIN)/
install: install-lib install-i18n install-conf
dist: $(I18Npo) clean dist: $(I18Npo) clean
@-rm -rf $(TMPDIR)/$(ARCHIVE) @-rm -rf $(TMPDIR)/$(ARCHIVE)

28
README
View File

@@ -41,14 +41,8 @@ MP3 radio streams, mms video streams and so on.
Installation: Installation:
cd /put/your/path/here/VDR/PLUGINS/src
tar -xzf /put/your/path/here/vdr-iptv-X.Y.Z.tgz tar -xzf /put/your/path/here/vdr-iptv-X.Y.Z.tgz
ln -s iptv-X.Y.Z iptv make -C iptv-X.Y.Z install
cd /put/your/path/here/VDR
cp -R PLUGINS/src/iptv/iptv /path/to/vdrresource/plugins/
make
make plugins
./vdr -P iptv
Setup menu: Setup menu:
@@ -89,11 +83,11 @@ Configuration:
- channels.conf - channels.conf
TV4;IPTV:60:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:6:0:0:0 TV6;IPTV:60:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:6:0:0:0
TV3;IPTV:50:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:5:0:0:0 TV5;IPTV:50:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:5:0:0:0
TV2;IPTV:40:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:4:0:0:0 TV4;IPTV:40:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:4:0:0:0
TV1;IPTV:30:S=1|P=0|F=CURL|U=http%3A//foo%3Abar@127.0.0.1%3A3000/TS/2|A=0:I:0:512:650:2321:0:3:0:0:0 TV3;IPTV:30:S=1|P=0|F=CURL|U=http%3A//foo%3Abar@127.0.0.1%3A3000/TS/2|A=0:I:0:512:650:2321:0:3:0:0:0
TV1;IPTV:20:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:2:0:0:0 TV2;IPTV:20:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:2:0:0:0
TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | Source type ("I") | | | | | | Source type ("I")
@@ -171,8 +165,7 @@ Notes:
"disable_ca_updates" patch to the VDR in order to get rid of "Channel not "disable_ca_updates" patch to the VDR in order to get rid of "Channel not
available" messages. available" messages.
- EIT scanning functionality can be disabled for all IPTV channels by applying - EIT scanning functionality is disabled by default.
the "disable_eitscan" patch to the VDR.
- Section id and pid scanners should be disabled after the correct data is - Section id and pid scanners should be disabled after the correct data is
found. This can be made via VDR's channel editor. found. This can be made via VDR's channel editor.
@@ -186,7 +179,12 @@ Notes:
netrc configuration file for authentication: netrc configuration file for authentication:
$(CONFDIR)/iptv/netrc $(CONFDIR)/iptv/netrc
- CURL implementation - You can quite easily figure out correct DVB triplet values by using the
multicat and dvbsnoop tools:
$ multicat -u -d 1620000000 @127.0.0.1:1234 /tmp/video.ts
$ dvbsnoop -s ts -if /tmp/video.ts -tssubdecode -hexdumpbuffer 0x12 | \
grep -m1 -A8 Service_ID | grep _ID
Acknowledgements: Acknowledgements:
- The IPTV section filtering code is derived from Linux kernel. - The IPTV section filtering code is derived from Linux kernel.

View File

@@ -44,7 +44,8 @@
do { \ do { \
if (exp) { \ if (exp) { \
char tmp[64]; \ char tmp[64]; \
error(errstr": %s", strerror_r(errno, tmp, sizeof(tmp))); \ error("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
strerror_r(errno, tmp, sizeof(tmp))); \
func; \ func; \
ret; \ ret; \
} \ } \

View File

@@ -19,6 +19,7 @@ cIptvConfig::cIptvConfig(void)
for (unsigned int i = 0; i < ARRAY_SIZE(disabledFiltersM); ++i) for (unsigned int i = 0; i < ARRAY_SIZE(disabledFiltersM); ++i)
disabledFiltersM[i] = -1; disabledFiltersM[i] = -1;
memset(configDirectoryM, 0, sizeof(configDirectoryM)); memset(configDirectoryM, 0, sizeof(configDirectoryM));
memset(resourceDirectoryM, 0, sizeof(resourceDirectoryM));
} }
unsigned int cIptvConfig::GetDisabledFiltersCount(void) const unsigned int cIptvConfig::GetDisabledFiltersCount(void) const
@@ -45,3 +46,9 @@ void cIptvConfig::SetConfigDirectory(const char *directoryP)
debug("cIptvConfig::%s(%s)", __FUNCTION__, directoryP); debug("cIptvConfig::%s(%s)", __FUNCTION__, directoryP);
ERROR_IF(!realpath(directoryP, configDirectoryM), "Cannot canonicalize configuration directory"); ERROR_IF(!realpath(directoryP, configDirectoryM), "Cannot canonicalize configuration directory");
} }
void cIptvConfig::SetResourceDirectory(const char *directoryP)
{
debug("cIptvConfig::%s(%s)", __FUNCTION__, directoryP);
ERROR_IF(!realpath(directoryP, resourceDirectoryM), "Cannot canonicalize resource directory");
}

View File

@@ -21,6 +21,7 @@ private:
unsigned int sectionFilteringM; unsigned int sectionFilteringM;
int disabledFiltersM[SECTION_FILTER_TABLE_SIZE]; int disabledFiltersM[SECTION_FILTER_TABLE_SIZE];
char configDirectoryM[PATH_MAX]; char configDirectoryM[PATH_MAX];
char resourceDirectoryM[PATH_MAX];
public: public:
cIptvConfig(); cIptvConfig();
@@ -30,6 +31,7 @@ public:
unsigned int GetUseBytes(void) const { return useBytesM; } unsigned int GetUseBytes(void) const { return useBytesM; }
unsigned int GetSectionFiltering(void) const { return sectionFilteringM; } unsigned int GetSectionFiltering(void) const { return sectionFilteringM; }
const char *GetConfigDirectory(void) const { return configDirectoryM; } const char *GetConfigDirectory(void) const { return configDirectoryM; }
const char *GetResourceDirectory(void) const { return resourceDirectoryM; }
unsigned int GetDisabledFiltersCount(void) const; unsigned int GetDisabledFiltersCount(void) const;
int GetDisabledFilters(unsigned int indexP) const; int GetDisabledFilters(unsigned int indexP) const;
void SetTsBufferSize(unsigned int sizeP) { tsBufferSizeM = sizeP; } void SetTsBufferSize(unsigned int sizeP) { tsBufferSizeM = sizeP; }
@@ -39,6 +41,7 @@ public:
void SetSectionFiltering(unsigned int onOffP) { sectionFilteringM = onOffP; } void SetSectionFiltering(unsigned int onOffP) { sectionFilteringM = onOffP; }
void SetDisabledFilters(unsigned int indexP, int numberP); void SetDisabledFilters(unsigned int indexP, int numberP);
void SetConfigDirectory(const char *directoryP); void SetConfigDirectory(const char *directoryP);
void SetResourceDirectory(const char *directoryP);
}; };
extern cIptvConfig IptvConfig; extern cIptvConfig IptvConfig;

210
device.c
View File

@@ -20,25 +20,27 @@ cIptvDevice::cIptvDevice(unsigned int indexP)
isOpenDvrM(false), isOpenDvrM(false),
sidScanEnabledM(false), sidScanEnabledM(false),
pidScanEnabledM(false), pidScanEnabledM(false),
channelIdM(tChannelID::InvalidID) channelM()
{ {
unsigned int bufsize = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize()); unsigned int bufsize = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize());
bufsize -= (bufsize % TS_SIZE); bufsize -= (bufsize % TS_SIZE);
isyslog("creating IPTV device %d (CardIndex=%d)", deviceIndexM, CardIndex()); isyslog("creating IPTV device %d (CardIndex=%d)", deviceIndexM, CardIndex());
tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false, tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false,
*cString::sprintf("IPTV %d", deviceIndexM)); *cString::sprintf("IPTV TS %d", deviceIndexM));
tsBufferM->SetTimeouts(10, 10); if (tsBufferM) {
tsBufferM->SetTimeouts(100, 100);
tsBufferM->SetIoThrottle();
pIptvStreamerM = new cIptvStreamer(*this, tsBufferM->Free());
}
ResetBuffering(); ResetBuffering();
pUdpProtocolM = new cIptvProtocolUdp(); pUdpProtocolM = new cIptvProtocolUdp();
pCurlProtocolM = new cIptvProtocolCurl(); pCurlProtocolM = new cIptvProtocolCurl();
pHttpProtocolM = new cIptvProtocolHttp(); pHttpProtocolM = new cIptvProtocolHttp();
pFileProtocolM = new cIptvProtocolFile(); pFileProtocolM = new cIptvProtocolFile();
pExtProtocolM = new cIptvProtocolExt(); pExtProtocolM = new cIptvProtocolExt();
pIptvStreamerM = new cIptvStreamer(tsBufferM, (100 * TS_SIZE));
pPidScannerM = new cPidScanner(); pPidScannerM = new cPidScanner();
// Initialize filter pointers
memset(secFiltersM, 0, sizeof(secFiltersM));
// Start section handler for iptv device // Start section handler for iptv device
pIptvSectionM = new cIptvSectionFilterHandler(deviceIndexM, bufsize + 1);
StartSectionHandler(); StartSectionHandler();
// Sid scanner must be created after the section handler // Sid scanner must be created after the section handler
AttachFilter(pSidScannerM = new cSidScanner()); AttachFilter(pSidScannerM = new cSidScanner());
@@ -56,21 +58,18 @@ cIptvDevice::cIptvDevice(unsigned int indexP)
cIptvDevice::~cIptvDevice() cIptvDevice::~cIptvDevice()
{ {
debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM); debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
DELETE_POINTER(pIptvStreamerM);
DELETE_POINTER(pUdpProtocolM);
DELETE_POINTER(pCurlProtocolM);
DELETE_POINTER(pHttpProtocolM);
DELETE_POINTER(pFileProtocolM);
DELETE_POINTER(pExtProtocolM);
DELETE_POINTER(tsBufferM);
DELETE_POINTER(pPidScannerM);
DELETE_POINTER(pSidScannerM);
// Stop section handler of iptv device // Stop section handler of iptv device
StopSectionHandler(); StopSectionHandler();
// Destroy all filters DELETE_POINTER(pIptvSectionM);
cMutexLock MutexLock(&mutexM); DELETE_POINTER(pSidScannerM);
for (int i = 0; i < eMaxSecFilterCount; ++i) DELETE_POINTER(pPidScannerM);
DeleteFilter(i); DELETE_POINTER(pIptvStreamerM);
DELETE_POINTER(pExtProtocolM);
DELETE_POINTER(pFileProtocolM);
DELETE_POINTER(pHttpProtocolM);
DELETE_POINTER(pCurlProtocolM);
DELETE_POINTER(pUdpProtocolM);
DELETE_POINTER(tsBufferM);
// Close dvr fifo // Close dvr fifo
if (dvrFdM >= 0) { if (dvrFdM >= 0) {
int fd = dvrFdM; int fd = dvrFdM;
@@ -92,6 +91,15 @@ bool cIptvDevice::Initialize(unsigned int deviceCountP)
return true; return true;
} }
void cIptvDevice::Shutdown(void)
{
debug("cIptvDevice::%s()", __FUNCTION__);
for (int i = 0; i < IPTV_MAX_DEVICES; ++i) {
if (IptvDevicesS[i])
IptvDevicesS[i]->CloseDvr();
}
}
unsigned int cIptvDevice::Count(void) unsigned int cIptvDevice::Count(void)
{ {
unsigned int count = 0; unsigned int count = 0;
@@ -107,7 +115,7 @@ cIptvDevice *cIptvDevice::GetIptvDevice(int cardIndexP)
{ {
//debug("cIptvDevice::%s(%d)", __FUNCTION__, cardIndexP); //debug("cIptvDevice::%s(%d)", __FUNCTION__, cardIndexP);
for (unsigned int i = 0; i < IPTV_MAX_DEVICES; ++i) { for (unsigned int i = 0; i < IPTV_MAX_DEVICES; ++i) {
if ((IptvDevicesS[i] != NULL) && (IptvDevicesS[i]->CardIndex() == cardIndexP)) { if (IptvDevicesS[i] && (IptvDevicesS[i]->CardIndex() == cardIndexP)) {
//debug("cIptvDevice::%s(%d): found!", __FUNCTION__, cardIndexP); //debug("cIptvDevice::%s(%d): found!", __FUNCTION__, cardIndexP);
return IptvDevicesS[i]; return IptvDevicesS[i];
} }
@@ -135,20 +143,7 @@ cString cIptvDevice::GetPidsInformation(void)
cString cIptvDevice::GetFiltersInformation(void) cString cIptvDevice::GetFiltersInformation(void)
{ {
//debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM); //debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
unsigned int count = 0; return cString::sprintf("Active section filters:\n%s", pIptvSectionM ? *pIptvSectionM->GetInformation() : "");
cString s("Active section filters:\n");
// loop through active section filters
cMutexLock MutexLock(&mutexM);
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (secFiltersM[i]) {
s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i,
*secFiltersM[i]->GetSectionStatistic(), secFiltersM[i]->GetPid(),
id_pid(secFiltersM[i]->GetPid()));
if (++count > IPTV_STATS_ACTIVE_FILTERS_COUNT)
break;
}
}
return s;
} }
cString cIptvDevice::GetInformation(unsigned int pageP) cString cIptvDevice::GetInformation(unsigned int pageP)
@@ -183,7 +178,7 @@ cString cIptvDevice::GetInformation(unsigned int pageP)
cString cIptvDevice::DeviceType(void) const cString cIptvDevice::DeviceType(void) const
{ {
debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM); //debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
return "IPTV"; return "IPTV";
} }
@@ -228,7 +223,7 @@ bool cIptvDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
if (channelP && ProvidesTransponder(channelP)) { if (channelP && ProvidesTransponder(channelP)) {
result = hasPriority; result = hasPriority;
if (Receiving()) { if (Receiving()) {
if (channelP->GetChannelID() == channelIdM) if (channelP->GetChannelID() == channelM.GetChannelID())
result = true; result = true;
else else
needsDetachReceivers = Receiving(); needsDetachReceivers = Receiving();
@@ -249,6 +244,21 @@ int cIptvDevice::NumProvidedSystems(void) const
return 1; return 1;
} }
const cChannel *cIptvDevice::GetCurrentlyTunedTransponder(void) const
{
return &channelM;
}
bool cIptvDevice::IsTunedToTransponder(const cChannel *channelP) const
{
return channelP ? (channelP->GetChannelID() == channelM.GetChannelID()) : false;
}
bool cIptvDevice::MaySwitchTransponder(const cChannel *channelP) const
{
return cDevice::MaySwitchTransponder(channelP);
}
bool cIptvDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) bool cIptvDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
{ {
cIptvProtocolIf *protocol; cIptvProtocolIf *protocol;
@@ -284,11 +294,11 @@ bool cIptvDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
sidScanEnabledM = itp.SidScan() ? true : false; sidScanEnabledM = itp.SidScan() ? true : false;
pidScanEnabledM = itp.PidScan() ? true : false; pidScanEnabledM = itp.PidScan() ? true : false;
if (pIptvStreamerM->Set(itp.Address(), itp.Parameter(), deviceIndexM, protocol)) { if (pIptvStreamerM->Set(itp.Address(), itp.Parameter(), deviceIndexM, protocol)) {
channelIdM = channelP->GetChannelID(); channelM = *channelP;
if (sidScanEnabledM && pSidScannerM && IptvConfig.GetSectionFiltering()) if (sidScanEnabledM && pSidScannerM && IptvConfig.GetSectionFiltering())
pSidScannerM->SetChannel(channelIdM); pSidScannerM->SetChannel(channelM.GetChannelID());
if (pidScanEnabledM && pPidScannerM) if (pidScanEnabledM && pPidScannerM)
pPidScannerM->SetChannel(channelIdM); pPidScannerM->SetChannel(channelM.GetChannelID());
} }
return true; return true;
} }
@@ -299,80 +309,19 @@ bool cIptvDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
return true; return true;
} }
bool cIptvDevice::DeleteFilter(unsigned int indexP)
{
if ((indexP < eMaxSecFilterCount) && secFiltersM[indexP]) {
//debug("cIptvDevice::%s(%d): index=%d", __FUNCTION__, deviceIndexM, indexP);
cIptvSectionFilter *tmp = secFiltersM[indexP];
secFiltersM[indexP] = NULL;
delete tmp;
return true;
}
return false;
}
bool cIptvDevice::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
{
//debug("cIptvDevice::%s(%d): pid=%d tid=%02X mask=%02X", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
// loop through section filter table
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
int index = IptvConfig.GetDisabledFilters(i);
// Check if matches
if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
(section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
(section_filter_table[index].mask == maskP)) {
//debug("cIptvDevice::%s(%d): found %s", __FUNCTION__, deviceIndexM, section_filter_table[index].description);
return true;
}
}
return false;
}
int cIptvDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP) int cIptvDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
{ {
// Check if disabled by user //debug("cIptvDevice::%s(%d): pid=%d tid=%d mask=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
if (!IptvConfig.GetSectionFiltering()) if (pIptvSectionM && IptvConfig.GetSectionFiltering())
return -1; return pIptvSectionM->Open(pidP, tidP, maskP);
// Lock
cMutexLock MutexLock(&mutexM);
// Blacklist check, refuse certain filters
if (IsBlackListed(pidP, tidP, maskP))
return -1;
// Search the next free filter slot
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (!secFiltersM[i]) {
//debug("cIptvDevice::%s(%d): pid=%d tid=%02X mask=%02X index=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP, i);
secFiltersM[i] = new cIptvSectionFilter(deviceIndexM, pidP, tidP, maskP);
if (secFiltersM[i])
return i;
break;
}
}
// No free filter slot found
return -1; return -1;
} }
int cIptvDevice::ReadFilter(int handleP, void *bufferP, size_t lengthP)
{
// Lock
cMutexLock MutexLock(&mutexM);
// ... and load
if (secFiltersM[handleP]) {
return secFiltersM[handleP]->Read(bufferP, lengthP);
//debug("cIptvDevice::%s(%d): handle=%d length=%d", __FUNCTION__, deviceIndexM, handleP, lengthP);
}
return 0;
}
void cIptvDevice::CloseFilter(int handleP) void cIptvDevice::CloseFilter(int handleP)
{ {
// Lock //debug("cIptvDevice::%s(%d): handle=%d", __FUNCTION__, deviceIndexM, handleP);
cMutexLock MutexLock(&mutexM); if (pIptvSectionM)
// ... and load pIptvSectionM->Close(handleP);
if (secFiltersM[handleP]) {
//debug("cIptvDevice::%s(%d): handle=%d", __FUNCTION__, deviceIndexM, handleP);
DeleteFilter(handleP);
}
} }
bool cIptvDevice::OpenDvr(void) bool cIptvDevice::OpenDvr(void)
@@ -385,6 +334,8 @@ bool cIptvDevice::OpenDvr(void)
pIptvStreamerM->Open(); pIptvStreamerM->Open();
if (sidScanEnabledM && pSidScannerM && IptvConfig.GetSectionFiltering()) if (sidScanEnabledM && pSidScannerM && IptvConfig.GetSectionFiltering())
pSidScannerM->Open(); pSidScannerM->Open();
if (pidScanEnabledM && pPidScannerM)
pPidScannerM->Open();
isOpenDvrM = true; isOpenDvrM = true;
return true; return true;
} }
@@ -392,7 +343,9 @@ bool cIptvDevice::OpenDvr(void)
void cIptvDevice::CloseDvr(void) void cIptvDevice::CloseDvr(void)
{ {
debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM); debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
if (sidScanEnabledM && pSidScannerM ) if (pidScanEnabledM && pPidScannerM)
pPidScannerM->Close();
if (sidScanEnabledM && pSidScannerM)
pSidScannerM->Close(); pSidScannerM->Close();
if (pIptvStreamerM) if (pIptvStreamerM)
pIptvStreamerM->Close(); pIptvStreamerM->Close();
@@ -430,10 +383,36 @@ bool cIptvDevice::IsBuffering(void) const
return false; return false;
} }
void cIptvDevice::WriteData(uchar *bufferP, int lengthP)
{
//debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
int len;
// Send data to dvr fifo
if (dvrFdM >= 0)
len = write(dvrFdM, bufferP, lengthP);
// Fill up TS buffer
if (tsBufferM) {
len = tsBufferM->Put(bufferP, lengthP);
if (len != lengthP)
tsBufferM->ReportOverflow(lengthP - len);
}
// Filter the sections
if (pIptvSectionM && IptvConfig.GetSectionFiltering())
pIptvSectionM->Write(bufferP, lengthP);
}
unsigned int cIptvDevice::CheckData(void)
{
//debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
if (tsBufferM)
return (unsigned int)tsBufferM->Free();
return 0;
}
bool cIptvDevice::GetTSPacket(uchar *&Data) bool cIptvDevice::GetTSPacket(uchar *&Data)
{ {
//debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM); //debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
if (tsBufferM && !IsBuffering()) { if (isOpenDvrM && tsBufferM && !IsBuffering()) {
if (isPacketDeliveredM) { if (isPacketDeliveredM) {
tsBufferM->Del(TS_SIZE); tsBufferM->Del(TS_SIZE);
isPacketDeliveredM = false; isPacketDeliveredM = false;
@@ -451,26 +430,13 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
} }
} }
tsBufferM->Del(Count); tsBufferM->Del(Count);
error("Skipped %d bytes to sync on TS packet\n", Count); error("Skipped %d bytes to sync on TS packet", Count);
return false; return false;
} }
isPacketDeliveredM = true; isPacketDeliveredM = true;
Data = p; Data = p;
// Update pid statistics // Update pid statistics
AddPidStatistic(ts_pid(p), payload(p)); AddPidStatistic(ts_pid(p), payload(p));
// Send data also to dvr fifo
if (dvrFdM >= 0)
Count = (int)write(dvrFdM, p, TS_SIZE);
// Analyze incomplete streams with built-in pid analyzer
if (pidScanEnabledM && pPidScannerM)
pPidScannerM->Process(p);
// Lock
cMutexLock MutexLock(&mutexM);
// Run the data through all filters
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (secFiltersM[i])
secFiltersM[i]->Process(p);
}
return true; return true;
} }
} }

View File

@@ -10,6 +10,7 @@
#include <vdr/device.h> #include <vdr/device.h>
#include "common.h" #include "common.h"
#include "deviceif.h"
#include "protocoludp.h" #include "protocoludp.h"
#include "protocolcurl.h" #include "protocolcurl.h"
#include "protocolhttp.h" #include "protocolhttp.h"
@@ -21,19 +22,17 @@
#include "sidscanner.h" #include "sidscanner.h"
#include "statistics.h" #include "statistics.h"
class cIptvDevice : public cDevice, public cIptvPidStatistics, public cIptvBufferStatistics { class cIptvDevice : public cDevice, public cIptvPidStatistics, public cIptvBufferStatistics, public cIptvDeviceIf {
// static ones // static ones
public: public:
static unsigned int deviceCount; static unsigned int deviceCount;
static bool Initialize(unsigned int DeviceCount); static bool Initialize(unsigned int DeviceCount);
static void Shutdown(void);
static unsigned int Count(void); static unsigned int Count(void);
static cIptvDevice *GetIptvDevice(int CardIndex); static cIptvDevice *GetIptvDevice(int CardIndex);
// private parts // private parts
private: private:
enum {
eMaxSecFilterCount = 32
};
unsigned int deviceIndexM; unsigned int deviceIndexM;
int dvrFdM; int dvrFdM;
bool isPacketDeliveredM; bool isPacketDeliveredM;
@@ -42,17 +41,17 @@ private:
bool pidScanEnabledM; bool pidScanEnabledM;
cRingBufferLinear *tsBufferM; cRingBufferLinear *tsBufferM;
mutable int tsBufferPrefillM; mutable int tsBufferPrefillM;
tChannelID channelIdM; cChannel channelM;
cIptvProtocolUdp *pUdpProtocolM; cIptvProtocolUdp *pUdpProtocolM;
cIptvProtocolCurl *pCurlProtocolM; cIptvProtocolCurl *pCurlProtocolM;
cIptvProtocolHttp *pHttpProtocolM; cIptvProtocolHttp *pHttpProtocolM;
cIptvProtocolFile *pFileProtocolM; cIptvProtocolFile *pFileProtocolM;
cIptvProtocolExt *pExtProtocolM; cIptvProtocolExt *pExtProtocolM;
cIptvStreamer *pIptvStreamerM; cIptvStreamer *pIptvStreamerM;
cIptvSectionFilterHandler *pIptvSectionM;
cPidScanner *pPidScannerM; cPidScanner *pPidScannerM;
cSidScanner *pSidScannerM; cSidScanner *pSidScannerM;
cMutex mutexM; cMutex mutexM;
cIptvSectionFilter *secFiltersM[eMaxSecFilterCount];
// constructor & destructor // constructor & destructor
public: public:
@@ -74,8 +73,6 @@ private:
private: private:
void ResetBuffering(void); void ResetBuffering(void);
bool IsBuffering(void) const; bool IsBuffering(void) const;
bool DeleteFilter(unsigned int indexP);
bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const;
// for channel info // for channel info
public: public:
@@ -91,6 +88,10 @@ public:
virtual bool ProvidesChannel(const cChannel *channelP, int priorityP = -1, bool *needsDetachReceiversP = NULL) const; virtual bool ProvidesChannel(const cChannel *channelP, int priorityP = -1, bool *needsDetachReceiversP = NULL) const;
virtual bool ProvidesEIT(void) const; virtual bool ProvidesEIT(void) const;
virtual int NumProvidedSystems(void) const; virtual int NumProvidedSystems(void) const;
virtual const cChannel *GetCurrentlyTunedTransponder(void) const;
virtual bool IsTunedToTransponder(const cChannel *channelP) const;
virtual bool MaySwitchTransponder(const cChannel *channelP) const;
protected: protected:
virtual bool SetChannelDevice(const cChannel *channelP, bool liveViewP); virtual bool SetChannelDevice(const cChannel *channelP, bool liveViewP);
@@ -104,7 +105,6 @@ protected:
// for section filtering // for section filtering
public: public:
virtual int OpenFilter(u_short pidP, u_char tidP, u_char maskP); virtual int OpenFilter(u_short pidP, u_char tidP, u_char maskP);
virtual int ReadFilter(int handleP, void *bufferP, size_t lengthP);
virtual void CloseFilter(int handleP); virtual void CloseFilter(int handleP);
// for transponder lock // for transponder lock
@@ -114,6 +114,11 @@ public:
// for common interface // for common interface
public: public:
virtual bool HasInternalCam(void); virtual bool HasInternalCam(void);
// for internal device interface
public:
virtual void WriteData(u_char *bufferP, int lengthP);
virtual unsigned int CheckData(void);
}; };
#endif // __IPTV_DEVICE_H #endif // __IPTV_DEVICE_H

23
deviceif.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* deviceif.h: IPTV plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
*/
#ifndef __IPTV_DEVICEIF_H
#define __IPTV_DEVICEIF_H
class cIptvDeviceIf {
public:
cIptvDeviceIf() {}
virtual ~cIptvDeviceIf() {}
virtual void WriteData(u_char *bufferP, int lengthP) = 0;
virtual unsigned int CheckData(void) = 0;
private:
cIptvDeviceIf(const cIptvDeviceIf&);
cIptvDeviceIf& operator=(const cIptvDeviceIf&);
};
#endif // __IPTV_DEVICEIF_H

10
iptv.c
View File

@@ -13,15 +13,15 @@
#include "device.h" #include "device.h"
#include "iptvservice.h" #include "iptvservice.h"
#if defined(APIVERSNUM) && APIVERSNUM < 10738 #if defined(APIVERSNUM) && APIVERSNUM < 20000
#error "VDR-1.7.38 API version or greater is required!" #error "VDR-2.0.0 API version or greater is required!"
#endif #endif
#ifndef GITVERSION #ifndef GITVERSION
#define GITVERSION "" #define GITVERSION ""
#endif #endif
const char VERSION[] = "1.2.1" GITVERSION; const char VERSION[] = "2.0.3" GITVERSION;
static const char DESCRIPTION[] = trNOOP("Experience the IPTV"); static const char DESCRIPTION[] = trNOOP("Experience the IPTV");
class cPluginIptv : public cPlugin { class cPluginIptv : public cPlugin {
@@ -99,7 +99,8 @@ bool cPluginIptv::Initialize(void)
{ {
debug("cPluginIptv::%s()", __FUNCTION__); debug("cPluginIptv::%s()", __FUNCTION__);
// Initialize any background activities the plugin shall perform. // Initialize any background activities the plugin shall perform.
IptvConfig.SetConfigDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N)); IptvConfig.SetConfigDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N));
IptvConfig.SetResourceDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
return cIptvDevice::Initialize(deviceCountM); return cIptvDevice::Initialize(deviceCountM);
} }
@@ -118,6 +119,7 @@ void cPluginIptv::Stop(void)
{ {
debug("cPluginIptv::%s()", __FUNCTION__); debug("cPluginIptv::%s()", __FUNCTION__);
// Stop any background activities the plugin is performing. // Stop any background activities the plugin is performing.
cIptvDevice::Shutdown();
curl_global_cleanup(); curl_global_cleanup();
} }

View File

@@ -39,7 +39,6 @@ void cPidScanner::SetChannel(const tChannelID &channelIdP)
aPidM = 0xFFFF; aPidM = 0xFFFF;
numApidsM = 0; numApidsM = 0;
processM = true; processM = true;
timeoutM.Set(PIDSCANNER_TIMEOUT_IN_MS);
} }
void cPidScanner::Process(const uint8_t* bufP) void cPidScanner::Process(const uint8_t* bufP)
@@ -56,7 +55,7 @@ void cPidScanner::Process(const uint8_t* bufP)
// Verify TS packet // Verify TS packet
if (bufP[0] != 0x47) { if (bufP[0] != 0x47) {
error("Not TS packet: 0x%X\n", bufP[0]); error("Not TS packet: 0x%02X", bufP[0]);
return; return;
} }

View File

@@ -13,6 +13,12 @@
class cPidScanner { class cPidScanner {
private: private:
enum {
PIDSCANNER_APID_COUNT = 5, /* minimum count of audio pid samples for pid detection */
PIDSCANNER_VPID_COUNT = 5, /* minimum count of video pid samples for pid detection */
PIDSCANNER_PID_DELTA_COUNT = 100, /* minimum count of pid samples for audio/video only pid detection */
PIDSCANNER_TIMEOUT_IN_MS = 15000 /* 15s timeout for detection */
};
cTimeMs timeoutM; cTimeMs timeoutM;
tChannelID channelIdM; tChannelID channelIdM;
bool processM; bool processM;
@@ -26,6 +32,8 @@ public:
~cPidScanner(); ~cPidScanner();
void SetChannel(const tChannelID &channelIdP); void SetChannel(const tChannelID &channelIdP);
void Process(const uint8_t* bufP); void Process(const uint8_t* bufP);
void Open() { debug("cPidScanner::%s()", __FUNCTION__); timeoutM.Set(PIDSCANNER_TIMEOUT_IN_MS); }
void Close() { debug("cPidScanner::%s()", __FUNCTION__); timeoutM.Set(0); }
}; };
#endif // __PIDSCANNER_H #endif // __PIDSCANNER_H

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala # Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package. # This file is distributed under the same license as the iptv package.
# Tobias <vdr@e-tobi.net>, 2007. # Tobias <vdr@e-tobi.net>, 2007.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-iptv 1.2.1\n" "Project-Id-Version: vdr-iptv 2.0.3\n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2012-06-03 06:03+0300\n" "POT-Creation-Date: 2014-03-09 03:09+0200\n"
"PO-Revision-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2014-03-09 03:09+0200\n"
"Last-Translator: Tobias Grimm <tg@e-tobi.net>\n" "Last-Translator: Tobias Grimm <tg@e-tobi.net>\n"
"Language-Team: German <vdr@linuxtv.org>\n" "Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n" "Language: de\n"

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala # Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package. # This file is distributed under the same license as the iptv package.
# Rolf Ahrenberg # Rolf Ahrenberg
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-iptv 1.2.1\n" "Project-Id-Version: vdr-iptv 2.0.3\n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2012-06-03 06:03+0300\n" "POT-Creation-Date: 2014-03-09 03:09+0200\n"
"PO-Revision-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2014-03-09 03:09+0200\n"
"Last-Translator: Rolf Ahrenberg\n" "Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n" "Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n" "Language: fi\n"

View File

@@ -1,15 +1,15 @@
# French translations for iptv package. # French translations for iptv package.
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala # Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package. # This file is distributed under the same license as the iptv package.
# Bruno ROUSSEL <bruno.roussel@free.fr>, 2007. # Bruno ROUSSEL <bruno.roussel@free.fr>, 2007.
# NIVAL Michaël <mnival@club-internet.fr>, 2008. # NIVAL Michaël <mnival@club-internet.fr>, 2008.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-iptv 1.2.1\n" "Project-Id-Version: vdr-iptv 2.0.3\n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2012-06-03 06:03+0300\n" "POT-Creation-Date: 2014-03-09 03:09+0200\n"
"PO-Revision-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2014-03-09 03:09+0200\n"
"Last-Translator: NIVAL Michaël <mnival@club-internet.fr>\n" "Last-Translator: NIVAL Michaël <mnival@club-internet.fr>\n"
"Language-Team: French <vdr@linuxtv.org>\n" "Language-Team: French <vdr@linuxtv.org>\n"
"Language: fr\n" "Language: fr\n"

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala # Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package. # This file is distributed under the same license as the iptv package.
# Diego Pierotto <vdr-italian@tiscali.it>, 2008. # Diego Pierotto <vdr-italian@tiscali.it>, 2008.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-iptv 1.2.1\n" "Project-Id-Version: vdr-iptv 2.0.3\n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2012-06-03 06:03+0300\n" "POT-Creation-Date: 2014-03-09 03:09+0200\n"
"PO-Revision-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2014-03-09 03:09+0200\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n" "Language-Team: Italian <vdr@linuxtv.org>\n"
"Language: it\n" "Language: it\n"

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala # Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package. # This file is distributed under the same license as the iptv package.
# Carel, 2010. # Carel, 2010.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-iptv 1.2.1\n" "Project-Id-Version: vdr-iptv 2.0.3\n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2012-06-03 06:03+0300\n" "POT-Creation-Date: 2014-03-09 03:09+0200\n"
"PO-Revision-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2014-03-09 03:09+0200\n"
"Last-Translator: Carel\n" "Last-Translator: Carel\n"
"Language-Team: Dutch <vdr@linuxtv.org>\n" "Language-Team: Dutch <vdr@linuxtv.org>\n"
"Language: nl\n" "Language: nl\n"

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala # Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package. # This file is distributed under the same license as the iptv package.
# Alexander Gross <Bikalexander@gmail.com>, 2008. # Alexander Gross <Bikalexander@gmail.com>, 2008.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-iptv 1.2.1\n" "Project-Id-Version: vdr-iptv 2.0.3\n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2012-06-03 06:03+0300\n" "POT-Creation-Date: 2014-03-09 03:09+0200\n"
"PO-Revision-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2014-03-09 03:09+0200\n"
"Last-Translator: Alexander Gross <Bikalexander@gmail.com>\n" "Last-Translator: Alexander Gross <Bikalexander@gmail.com>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n" "Language-Team: Russian <vdr@linuxtv.org>\n"
"Language: ru\n" "Language: ru\n"

View File

@@ -9,14 +9,18 @@
#include "config.h" #include "config.h"
#include "protocolcurl.h" #include "protocolcurl.h"
#ifdef CURLOPT_RTSPHEADER
#define USE_RTSP
#endif
#define iptv_curl_easy_setopt(X, Y, Z) \ #define iptv_curl_easy_setopt(X, Y, Z) \
if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \ if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \
error("curl_easy_setopt(%s, %s, %s) failed: %d\n", #X, #Y, #Z, res); \ error("curl_easy_setopt(%s, %s) failed: %s (%d)", #Y, #Z, curl_easy_strerror(res), res); \
} }
#define iptv_curl_easy_perform(X) \ #define iptv_curl_easy_perform(X) \
if ((res = curl_easy_perform((X))) != CURLE_OK) { \ if ((res = curl_easy_perform((X))) != CURLE_OK) { \
error("curl_easy_perform(%s) failed: %d\n", #X, res); \ error("curl_easy_perform() failed: %s (%d)", curl_easy_strerror(res), res); \
} }
cIptvProtocolCurl::cIptvProtocolCurl() cIptvProtocolCurl::cIptvProtocolCurl()
@@ -34,8 +38,10 @@ cIptvProtocolCurl::cIptvProtocolCurl()
pausedM(false) pausedM(false)
{ {
debug("cIptvProtocolCurl::%s()", __FUNCTION__); debug("cIptvProtocolCurl::%s()", __FUNCTION__);
if (ringBufferM) if (ringBufferM) {
ringBufferM->SetTimeouts(100, 0); ringBufferM->SetTimeouts(100, 0);
ringBufferM->SetIoThrottle();
}
Connect(); Connect();
} }
@@ -67,7 +73,7 @@ size_t cIptvProtocolCurl::WriteRtspCallback(void *ptrP, size_t sizeP, size_t nme
//debug("cIptvProtocolCurl::%s(%zu)", __FUNCTION__, len); //debug("cIptvProtocolCurl::%s(%zu)", __FUNCTION__, len);
// Validate packet header ('$') and channel (0) // Validate packet header ('$') and channel (0)
if (obj && (p[0] == 0x24 ) && (p[1] == 0)) { if (obj && (p[0] == 0x24) && (p[1] == 0)) {
int length = (p[2] << 8) | p[3]; int length = (p[2] << 8) | p[3];
if (length > 3) { if (length > 3) {
// Skip interleave header // Skip interleave header
@@ -208,7 +214,7 @@ unsigned char *cIptvProtocolCurl::GetData(int &lenP)
break; break;
} }
} }
error("IPTV skipped %d bytes to sync on TS packet\n", count); error("IPTV skipped %d bytes to sync on TS packet", count);
ringBufferM->Del(count); ringBufferM->Del(count);
lenP = 0; lenP = 0;
return NULL; return NULL;
@@ -258,7 +264,8 @@ bool cIptvProtocolCurl::Connect()
iptv_curl_easy_setopt(handleM, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL); iptv_curl_easy_setopt(handleM, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
iptv_curl_easy_setopt(handleM, CURLOPT_NETRC_FILE, *netrc); iptv_curl_easy_setopt(handleM, CURLOPT_NETRC_FILE, *netrc);
// Set timeout // Set timeouts
iptv_curl_easy_setopt(handleM, CURLOPT_TIMEOUT, (long)eConnectTimeoutS);
iptv_curl_easy_setopt(handleM, CURLOPT_CONNECTTIMEOUT, (long)eConnectTimeoutS); iptv_curl_easy_setopt(handleM, CURLOPT_CONNECTTIMEOUT, (long)eConnectTimeoutS);
// Set user-agent // Set user-agent
@@ -272,6 +279,7 @@ bool cIptvProtocolCurl::Connect()
// Protocol specific initializations // Protocol specific initializations
switch (modeM) { switch (modeM) {
#ifdef USE_RTSP
case eModeRtsp: case eModeRtsp:
{ {
cString uri, control, transport, range; cString uri, control, transport, range;
@@ -315,7 +323,7 @@ bool cIptvProtocolCurl::Connect()
iptv_curl_easy_perform(handleM); iptv_curl_easy_perform(handleM);
} }
break; break;
#endif
case eModeHttp: case eModeHttp:
case eModeHttps: case eModeHttps:
{ {
@@ -338,6 +346,10 @@ bool cIptvProtocolCurl::Connect()
break; break;
case eModeFile: case eModeFile:
// Set timeout
iptv_curl_easy_setopt(handleM, CURLOPT_TIMEOUT_MS, 10L);
break;
case eModeUnknown: case eModeUnknown:
default: default:
break; break;
@@ -364,6 +376,7 @@ bool cIptvProtocolCurl::Disconnect()
if (handleM && multiM) { if (handleM && multiM) {
// Mode specific tricks // Mode specific tricks
switch (modeM) { switch (modeM) {
#ifdef USE_RTSP
case eModeRtsp: case eModeRtsp:
{ {
CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;
@@ -375,7 +388,7 @@ bool cIptvProtocolCurl::Disconnect()
rtspControlM = ""; rtspControlM = "";
} }
break; break;
#endif
case eModeHttp: case eModeHttp:
case eModeHttps: case eModeHttps:
case eModeFile: case eModeFile:
@@ -422,6 +435,7 @@ int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
// Fill up the buffer // Fill up the buffer
if (handleM && multiM) { if (handleM && multiM) {
switch (modeM) { switch (modeM) {
#ifdef USE_RTSP
case eModeRtsp: case eModeRtsp:
{ {
cMutexLock MutexLock(&mutexM); cMutexLock MutexLock(&mutexM);
@@ -431,7 +445,7 @@ int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
// @todo - How to detect eof? // @todo - How to detect eof?
} }
break; break;
#endif
case eModeFile: case eModeFile:
case eModeHttp: case eModeHttp:
case eModeHttps: case eModeHttps:
@@ -444,9 +458,9 @@ int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
res = curl_multi_perform(multiM, &running_handles); res = curl_multi_perform(multiM, &running_handles);
} while (res == CURLM_CALL_MULTI_PERFORM); } while (res == CURLM_CALL_MULTI_PERFORM);
// Shall we continue filling up the buffer? // Use 20% threshold before continuing to filling up the buffer.
mutexM.Lock(); mutexM.Lock();
if (pausedM && (ringBufferM->Free() > ringBufferM->Available())) { if (pausedM && (ringBufferM->Available() < (MEGABYTE(IptvConfig.GetTsBufferSize()) / 5))) {
debug("cIptvProtocolCurl::%s(continue): free=%d available=%d", __FUNCTION__, debug("cIptvProtocolCurl::%s(continue): free=%d available=%d", __FUNCTION__,
ringBufferM->Free(), ringBufferM->Available()); ringBufferM->Free(), ringBufferM->Available());
pausedM = false; pausedM = false;

View File

@@ -158,7 +158,7 @@ bool cIptvProtocolExt::Set(const char* locationP, const int parameterP, const in
if (!isempty(locationP)) { if (!isempty(locationP)) {
struct stat stbuf; struct stat stbuf;
// Update script file and parameter // Update script file and parameter
scriptFileM = cString::sprintf("%s/%s", IptvConfig.GetConfigDirectory(), locationP); scriptFileM = cString::sprintf("%s/%s", IptvConfig.GetResourceDirectory(), locationP);
if ((stat(*scriptFileM, &stbuf) != 0) || (strstr(*scriptFileM, "..") != 0)) { if ((stat(*scriptFileM, &stbuf) != 0) || (strstr(*scriptFileM, "..") != 0)) {
error("Non-existent or relative path script '%s'", *scriptFileM); error("Non-existent or relative path script '%s'", *scriptFileM);
return false; return false;

View File

@@ -60,7 +60,7 @@ int cIptvProtocolFile::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
{ {
//debug("cIptvProtocolFile::%s()", __FUNCTION__); //debug("cIptvProtocolFile::%s()", __FUNCTION__);
// Check errors // Check errors
if (ferror(fileStreamM)) { if (!fileStreamM || ferror(fileStreamM)) {
debug("cIptvProtocolFile::%s(): stream error", __FUNCTION__); debug("cIptvProtocolFile::%s(): stream error", __FUNCTION__);
return -1; return -1;
} }

View File

@@ -113,13 +113,13 @@ bool cIptvProtocolHttp::GetHeaderLine(char* destP, unsigned int destLenP,
++bufptr; ++bufptr;
// Check that buffer won't be exceeded // Check that buffer won't be exceeded
if (recvLenP >= destLenP) { if (recvLenP >= destLenP) {
error("Header wouldn't fit into buffer\n"); error("Header wouldn't fit into buffer");
recvLenP = 0; recvLenP = 0;
return false; return false;
} }
} }
else { else {
error("No HTTP response received in 500ms\n"); error("No HTTP response received in 500ms");
return false; return false;
} }
} }
@@ -143,14 +143,14 @@ bool cIptvProtocolHttp::ProcessHeaders(void)
if (!GetHeaderLine(buf, sizeof(buf), lineLength)) if (!GetHeaderLine(buf, sizeof(buf), lineLength))
return false; return false;
if (!responseFound && sscanf(buf, fmt, &version, &response) != 2) { if (!responseFound && sscanf(buf, fmt, &version, &response) != 2) {
error("Expected HTTP header not found\n"); error("Expected HTTP header not found");
continue; continue;
} }
else else
responseFound = true; responseFound = true;
// Allow only 'OK' and 'Partial Content' // Allow only 'OK' and 'Partial Content'
if ((response != 200) && (response != 206)) { if ((response != 200) && (response != 206)) {
error("Invalid HTTP response (%d): %s\n", response, buf); error("Invalid HTTP response (%d): %s", response, buf);
return false; return false;
} }
} }

View File

@@ -17,9 +17,9 @@ cIptvSectionFilter::cIptvSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t
secLenM(0), secLenM(0),
tsFeedpM(0), tsFeedpM(0),
pidM(pidP), pidM(pidP),
devIdM(deviceIndexP) deviceIndexM(deviceIndexP)
{ {
//debug("cIptvSectionFilter::%s(%d, %d)", __FUNCTION__, devIdM, pidM); //debug("cIptvSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
int i; int i;
memset(secBufBaseM, 0, sizeof(secBufBaseM)); memset(secBufBaseM, 0, sizeof(secBufBaseM));
@@ -46,32 +46,32 @@ cIptvSectionFilter::cIptvSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t
} }
doneqM = doneq ? 1 : 0; doneqM = doneq ? 1 : 0;
// Create filtering buffer // Create sockets
ringbufferM = new cRingBufferLinear(KILOBYTE(128), 0, false, *cString::sprintf("IPTV SECTION %d/%d", devIdM, pidM)); socketM[0] = socketM[1] = -1;
if (ringbufferM) if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socketM) != 0) {
ringbufferM->SetTimeouts(10, 10); char tmp[64];
else error("Opening section filter sockets failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp)));
error("Failed to allocate buffer for section filter (device=%d pid=%d): ", devIdM, pidM); }
else if ((fcntl(socketM[0], F_SETFL, O_NONBLOCK) != 0) || (fcntl(socketM[1], F_SETFL, O_NONBLOCK) != 0)) {
char tmp[64];
error("Setting section filter socket to non-blocking mode failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp)));
}
} }
cIptvSectionFilter::~cIptvSectionFilter() cIptvSectionFilter::~cIptvSectionFilter()
{ {
//debug("cIptvSectionFilter::%s(%d, %d)", __FUNCTION__, devIdM, pidM); //debug("cIptvSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
DELETE_POINTER(ringbufferM); int tmp = socketM[1];
socketM[1] = -1;
if (tmp >= 0)
close(tmp);
tmp = socketM[0];
socketM[0] = -1;
if (tmp >= 0)
close(tmp);
secBufM = NULL; secBufM = NULL;
} }
int cIptvSectionFilter::Read(void *Data, size_t Length)
{
int count = 0;
uchar *p = ringbufferM->Get(count);
if (p && count > 0) {
memcpy(Data, p, count);
ringbufferM->Del(count);
}
return count;
}
inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *dataP) inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *dataP)
{ {
return (uint16_t)(3 + ((dataP[1] & 0x0f) << 8) + dataP[2]); return (uint16_t)(3 + ((dataP[1] & 0x0f) << 8) + dataP[2]);
@@ -99,10 +99,10 @@ int cIptvSectionFilter::Filter(void)
if (doneqM && !neq) if (doneqM && !neq)
return 0; return 0;
if (ringbufferM) { // There is no data in the read socket, more can be written
int len = ringbufferM->Put(secBufM, secLenM); if ((socketM[0] >= 0) && (socketM[1] >= 0) /*&& !select_single_desc(socketM[0], 0, false)*/) {
if (len != secLenM) ssize_t len = write(socketM[1], secBufM, secLenM);
ringbufferM->ReportOverflow(secLenM - len); ERROR_IF(len < 0, "write()");
// Update statistics // Update statistics
AddSectionStatistic(len, 1); AddSectionStatistic(len, 1);
} }
@@ -210,3 +210,183 @@ void cIptvSectionFilter::Process(const uint8_t* dataP)
CopyDump(&dataP[p], count); CopyDump(&dataP[p], count);
} }
} }
cIptvSectionFilterHandler::cIptvSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
: cThread("IPTV section handler", true),
mutexM(),
deviceIndexM(deviceIndexP),
processedM(false),
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("IPTV SECTION HANDLER %d", deviceIndexP)))
{
debug("cIptvSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
// Initialize filter pointers
memset(filtersM, 0, sizeof(filtersM));
// Create input buffer
if (ringBufferM) {
ringBufferM->SetTimeouts(100, 100);
ringBufferM->SetIoThrottle();
}
else
error("Failed to allocate buffer for section filter handler (device=%d): ", deviceIndexM);
Start();
}
cIptvSectionFilterHandler::~cIptvSectionFilterHandler()
{
debug("cIptvSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
Stop();
DELETE_POINTER(ringBufferM);
// Destroy all filters
cMutexLock MutexLock(&mutexM);
for (int i = 0; i < eMaxSecFilterCount; ++i)
Delete(i);
}
bool cIptvSectionFilterHandler::Stop(void)
{
debug("cIptvSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
// Stop thread
if (Running())
Cancel(3);
return true;
}
void cIptvSectionFilterHandler::Action(void)
{
debug("cIptvSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
// Do the thread loop
while (Running()) {
// Read one TS packet
if (ringBufferM) {
int len = 0;
if (processedM) {
ringBufferM->Del(TS_SIZE);
processedM = false;
}
uchar *p = ringBufferM->Get(len);
if (p && (len >= TS_SIZE)) {
if (*p != TS_SYNC_BYTE) {
for (int i = 1; i < len; ++i) {
if (p[i] == TS_SYNC_BYTE) {
len = i;
break;
}
}
ringBufferM->Del(len);
debug("cIptvSectionFilterHandler::%s(%d): Skipped %d bytes to sync on TS packet", __FUNCTION__, deviceIndexM, len);
continue;
}
// Process TS packet through all filters
mutexM.Lock();
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i])
filtersM[i]->Process(p);
}
mutexM.Unlock();
processedM = true;
continue;
}
}
cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load
}
debug("cIptvSectionFilterHandler::%s(%d): exiting", __FUNCTION__, deviceIndexM);
}
cString cIptvSectionFilterHandler::GetInformation(void)
{
//debug("cIptvSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
// loop through active section filters
cMutexLock MutexLock(&mutexM);
cString s = "";
unsigned int count = 0;
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i]) {
s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i,
*filtersM[i]->GetSectionStatistic(), filtersM[i]->GetPid(),
id_pid(filtersM[i]->GetPid()));
if (++count > IPTV_STATS_ACTIVE_FILTERS_COUNT)
break;
}
}
return s;
}
bool cIptvSectionFilterHandler::Delete(unsigned int indexP)
{
//debug("cIptvSectionFilterHandler::%s(%d): index=%d", __FUNCTION__, deviceIndexM, indexP);
if ((indexP < eMaxSecFilterCount) && filtersM[indexP]) {
//debug("cIptvSectionFilterHandler::%s(%d): found %d", __FUNCTION__, deviceIndexM, indexP);
cIptvSectionFilter *tmp = filtersM[indexP];
filtersM[indexP] = NULL;
delete tmp;
return true;
}
return false;
}
bool cIptvSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
{
//debug("cIptvSectionFilterHandler::%s(%d): pid=%d tid=%02X mask=%02X", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
// loop through section filter table
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
int index = IptvConfig.GetDisabledFilters(i);
// Check if matches
if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
(section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
(section_filter_table[index].mask == maskP)) {
//debug("cIptvSectionFilterHandler::%s(%d): found %s", __FUNCTION__, deviceIndexM, section_filter_table[index].description);
return true;
}
}
return false;
}
int cIptvSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
{
// Lock
cMutexLock MutexLock(&mutexM);
// Blacklist check, refuse certain filters
if (IsBlackListed(pidP, tidP, maskP))
return -1;
// Search the next free filter slot
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (!filtersM[i]) {
filtersM[i] = new cIptvSectionFilter(deviceIndexM, pidP, tidP, maskP);
debug("cIptvSectionFilterHandler::%s(%d): pid=%d tid=%02X mask=%02X handle=%d index=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP, filtersM[i]->GetFd(), i);
return filtersM[i]->GetFd();
}
}
// No free filter slot found
return -1;
}
void cIptvSectionFilterHandler::Close(int handleP)
{
// Lock
cMutexLock MutexLock(&mutexM);
// Search the filter for deletion
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
debug("cIptvSectionFilterHandler::%s(%d): pid=%d handle=%d index=%d", __FUNCTION__, deviceIndexM, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i);
Delete(i);
break;
}
}
}
void cIptvSectionFilterHandler::Write(uchar *bufferP, int lengthP)
{
//debug("cIptvSectionFilterHandler::%s(%d): length=%d", __FUNCTION__, deviceIndexM, lengthP);
// Fill up the buffer
if (ringBufferM) {
int len = ringBufferM->Put(bufferP, lengthP);
if (len != lengthP)
ringBufferM->ReportOverflow(lengthP - len);
}
}

View File

@@ -35,7 +35,8 @@ private:
uint16_t tsFeedpM; uint16_t tsFeedpM;
uint16_t pidM; uint16_t pidM;
int devIdM; int deviceIndexM;
int socketM[2];
uint8_t filterValueM[DMX_MAX_FILTER_SIZE]; uint8_t filterValueM[DMX_MAX_FILTER_SIZE];
uint8_t filterMaskM[DMX_MAX_FILTER_SIZE]; uint8_t filterMaskM[DMX_MAX_FILTER_SIZE];
@@ -44,8 +45,6 @@ private:
uint8_t maskAndModeM[DMX_MAX_FILTER_SIZE]; uint8_t maskAndModeM[DMX_MAX_FILTER_SIZE];
uint8_t maskAndNotModeM[DMX_MAX_FILTER_SIZE]; uint8_t maskAndNotModeM[DMX_MAX_FILTER_SIZE];
cRingBufferLinear *ringbufferM;
inline uint16_t GetLength(const uint8_t *dataP); inline uint16_t GetLength(const uint8_t *dataP);
void New(void); void New(void);
int Filter(void); int Filter(void);
@@ -57,8 +56,35 @@ public:
cIptvSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP); cIptvSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP);
virtual ~cIptvSectionFilter(); virtual ~cIptvSectionFilter();
void Process(const uint8_t* dataP); void Process(const uint8_t* dataP);
int Read(void *bufferP, size_t lengthP); int GetFd(void) { return socketM[0]; }
uint16_t GetPid(void) const { return pidM; } uint16_t GetPid(void) const { return pidM; }
}; };
class cIptvSectionFilterHandler : public cThread {
private:
enum {
eMaxSecFilterCount = 32
};
cMutex mutexM;
int deviceIndexM;
bool processedM;
cRingBufferLinear *ringBufferM;
cIptvSectionFilter *filtersM[eMaxSecFilterCount];
bool Delete(unsigned int indexP);
bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const;
protected:
virtual void Action(void);
public:
cIptvSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cIptvSectionFilterHandler();
bool Stop(void);
cString GetInformation(void);
int Open(u_short pidP, u_char tidP, u_char maskP);
void Close(int handleP);
void Write(u_char *bufferP, int lengthP);
};
#endif // __IPTV_SECTIONFILTER_H #endif // __IPTV_SECTIONFILTER_H

View File

@@ -124,6 +124,7 @@ cIptvPluginSetup::cIptvPluginSetup()
disabledFilterIndexesM[i] = IptvConfig.GetDisabledFilters(i); disabledFilterIndexesM[i] = IptvConfig.GetDisabledFilters(i);
disabledFilterNamesM[i] = tr(section_filter_table[i].description); disabledFilterNamesM[i] = tr(section_filter_table[i].description);
} }
SetMenuCategory(mcSetupPlugins);
Setup(); Setup();
SetHelp(NULL, NULL, NULL, trVDR("Button$Info")); SetHelp(NULL, NULL, NULL, trVDR("Button$Info"));
} }

View File

@@ -45,7 +45,7 @@ void cSidScanner::Process(u_short pidP, u_char tidP, const u_char *dataP, int le
return; return;
if (channelIdM.Valid()) { if (channelIdM.Valid()) {
if ((pidP == 0x00) && (tidP == 0x00)) { if ((pidP == 0x00) && (tidP == 0x00)) {
debug("cSidScanner::%s(%d, %02X)", __FUNCTION__, pidP, tidP); //debug("cSidScanner::%s(%d, %02X)", __FUNCTION__, pidP, tidP);
SI::PAT pat(dataP, false); SI::PAT pat(dataP, false);
if (!pat.CheckCRCAndParse()) if (!pat.CheckCRCAndParse())
return; return;
@@ -71,15 +71,21 @@ void cSidScanner::Process(u_short pidP, u_char tidP, const u_char *dataP, int le
if (ts.getTransportStreamId() != channelIdM.Tid()) { if (ts.getTransportStreamId() != channelIdM.Tid()) {
debug("cSidScanner::%s(): tsid=%d", __FUNCTION__, ts.getTransportStreamId()); debug("cSidScanner::%s(): tsid=%d", __FUNCTION__, ts.getTransportStreamId());
newTid = ts.getTransportStreamId(); newTid = ts.getTransportStreamId();
tidFoundM = true;
}
if (ts.getOriginalNetworkId() != channelIdM.Nid()) {
debug("cSidScanner::%s(): onid=%d", __FUNCTION__, ts.getOriginalNetworkId());
newNid = ts.getOriginalNetworkId();
nidFoundM = true;
} }
tidFoundM = true;
break; // default to the first one break; // default to the first one
} }
if (nit.getNetworkId() != channelIdM.Nid()) { // fallback for network id if not found already
debug("cSidScanner::%s(): nid=%d\n", __FUNCTION__, ts.getTransportStreamId()); if (!nidFoundM && (nit.getNetworkId() != channelIdM.Nid())) {
debug("cSidScanner::%s(): nid=%d", __FUNCTION__, nit.getNetworkId());
newNid = nit.getNetworkId(); newNid = nit.getNetworkId();
nidFoundM = true;
} }
nidFoundM = true;
} }
} }
if ((newSid >= 0) || (newNid >= 0) || (newTid >= 0)) { if ((newSid >= 0) || (newNid >= 0) || (newTid >= 0)) {

View File

@@ -93,7 +93,7 @@ bool cIptvSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP)
{ {
if (inAddrP) { if (inAddrP) {
// First try only the IP address // First try only the IP address
*inAddrP = htonl(inet_addr(addrP)); *inAddrP = inet_addr(addrP);
if (*inAddrP == htonl(INADDR_NONE)) { if (*inAddrP == htonl(INADDR_NONE)) {
debug("cIptvSocket::%s(%s): cannot convert to address", __FUNCTION__, addrP); debug("cIptvSocket::%s(%s): cannot convert to address", __FUNCTION__, addrP);
// It may be a host name, get the name // It may be a host name, get the name
@@ -104,7 +104,7 @@ bool cIptvSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP)
strerror_r(h_errno, tmp, sizeof(tmp))); strerror_r(h_errno, tmp, sizeof(tmp)));
return false; return false;
} }
*inAddrP = htonl(inet_addr(*host->h_addr_list)); *inAddrP = inet_addr(*host->h_addr_list);
} }
return true; return true;
} }
@@ -226,7 +226,7 @@ int cIptvUdpSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
//debug("cIptvUdpSocket::%s()", __FUNCTION__); //debug("cIptvUdpSocket::%s()", __FUNCTION__);
// Error out if socket not initialized // Error out if socket not initialized
if (socketDescM <= 0) { if (socketDescM <= 0) {
error("Invalid socket in cIptvUdpSocket::%s()\n", __FUNCTION__); error("Invalid socket in cIptvUdpSocket::%s()", __FUNCTION__);
return -1; return -1;
} }
int len = 0; int len = 0;
@@ -359,7 +359,7 @@ int cIptvTcpSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
//debug("cIptvTcpSocket::%s()", __FUNCTION__); //debug("cIptvTcpSocket::%s()", __FUNCTION__);
// Error out if socket not initialized // Error out if socket not initialized
if (socketDescM <= 0) { if (socketDescM <= 0) {
error("Invalid socket in cIptvTcpSocket::%s()\n", __FUNCTION__); error("Invalid socket in cIptvTcpSocket::%s()", __FUNCTION__);
return -1; return -1;
} }
int len = 0; int len = 0;
@@ -376,7 +376,7 @@ bool cIptvTcpSocket::ReadChar(char *bufferAddrP, unsigned int timeoutMsP)
//debug("cIptvTcpSocket::%s()", __FUNCTION__); //debug("cIptvTcpSocket::%s()", __FUNCTION__);
// Error out if socket not initialized // Error out if socket not initialized
if (socketDescM <= 0) { if (socketDescM <= 0) {
error("Invalid socket in cIptvTcpSocket::%s()\n", __FUNCTION__); error("Invalid socket in cIptvTcpSocket::%s()", __FUNCTION__);
return false; return false;
} }
socklen_t addrlen = sizeof(sockAddrM); socklen_t addrlen = sizeof(sockAddrM);
@@ -401,7 +401,7 @@ bool cIptvTcpSocket::Write(const char *bufferAddrP, unsigned int bufferLenP)
//debug("cIptvTcpSocket::%s()", __FUNCTION__); //debug("cIptvTcpSocket::%s()", __FUNCTION__);
// Error out if socket not initialized // Error out if socket not initialized
if (socketDescM <= 0) { if (socketDescM <= 0) {
error("Invalid socket in cIptvTcpSocket::%s()\n", __FUNCTION__); error("Invalid socket in cIptvTcpSocket::%s()", __FUNCTION__);
return false; return false;
} }
ERROR_IF_RET(send(socketDescM, bufferAddrP, bufferLenP, 0) < 0, "send()", return false); ERROR_IF_RET(send(socketDescM, bufferAddrP, bufferLenP, 0) < 0, "send()", return false);

View File

@@ -58,6 +58,7 @@ bool cIptvTransponderParameters::Parse(const char *strP)
if (strP && *strP) { if (strP && *strP) {
const char *delim = "|"; const char *delim = "|";
char *str = strdup(strP); char *str = strdup(strP);
char *p = str;
char *saveptr = NULL; char *saveptr = NULL;
char *token = NULL; char *token = NULL;
bool found_s = false; bool found_s = false;
@@ -120,9 +121,9 @@ bool cIptvTransponderParameters::Parse(const char *strP)
if (found_s && found_p && found_f && found_u && found_a) if (found_s && found_p && found_f && found_u && found_a)
result = true; result = true;
else else
error("Invalid channel parameters: %s\n", str); error("Invalid channel parameters: %s", p);
free(str); free(p);
} }
return (result); return (result);

View File

@@ -20,7 +20,7 @@ private:
int sidScanM; int sidScanM;
int pidScanM; int pidScanM;
int protocolM; int protocolM;
char addressM[NAME_MAX]; char addressM[NAME_MAX + 1];
int parameterM; int parameterM;
public: public:

View File

@@ -44,7 +44,7 @@ cString cIptvSectionStatistics::GetSectionStatistic()
void cIptvSectionStatistics::AddSectionStatistic(long bytesP, long callsP) void cIptvSectionStatistics::AddSectionStatistic(long bytesP, long callsP)
{ {
//debug("cIptvSectionStatistics::%s(%ld, %ld)", __FUNCTION__, bytesP, callsP); //debug("cIptvSectionStatistics::%s(%ld, %ld)", __FUNCTION__, bytesP, callsP);
cMutexLock MutexLock(&mutexM); cMutexLock MutexLock(&mutexM);
filteredDataM += bytesP; filteredDataM += bytesP;
numberOfCallsM += callsP; numberOfCallsM += callsP;

View File

@@ -5,16 +5,13 @@
* *
*/ */
#include <vdr/thread.h>
#include <vdr/ringbuffer.h>
#include "common.h" #include "common.h"
#include "streamer.h" #include "streamer.h"
cIptvStreamer::cIptvStreamer(cRingBufferLinear* ringBufferP, unsigned int packetLenP) cIptvStreamer::cIptvStreamer(cIptvDeviceIf &deviceP, unsigned int packetLenP)
: cThread("IPTV streamer"), : cThread("IPTV streamer"),
ringBufferM(ringBufferP),
sleepM(), sleepM(),
deviceM(&deviceP),
packetBufferLenM(packetLenP), packetBufferLenM(packetLenP),
protocolM(NULL) protocolM(NULL)
{ {
@@ -33,7 +30,6 @@ cIptvStreamer::~cIptvStreamer()
// Close the protocol // Close the protocol
Close(); Close();
protocolM = NULL; protocolM = NULL;
ringBufferM = NULL;
// Free allocated memory // Free allocated memory
free(packetBufferM); free(packetBufferM);
} }
@@ -46,16 +42,12 @@ void cIptvStreamer::Action(void)
// Do the thread loop // Do the thread loop
while (packetBufferM && Running()) { while (packetBufferM && Running()) {
int length = -1; int length = -1;
unsigned int size = min((unsigned int)ringBufferM->Free(), packetBufferLenM); unsigned int size = min(deviceM->CheckData(), packetBufferLenM);
if (protocolM && (size > 0)) if (protocolM && (size > 0))
length = protocolM->Read(packetBufferM, size); length = protocolM->Read(packetBufferM, size);
if (length > 0) { if (length > 0) {
AddStreamerStatistic(length); AddStreamerStatistic(length);
if (ringBufferM) { deviceM->WriteData(packetBufferM, length);
int p = ringBufferM->Put(packetBufferM, length);
if (p != length)
ringBufferM->ReportOverflow(length - p);
}
} }
else else
sleepM.Wait(10); // to avoid busy loop and reduce cpu load sleepM.Wait(10); // to avoid busy loop and reduce cpu load

View File

@@ -11,15 +11,15 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <vdr/thread.h> #include <vdr/thread.h>
#include <vdr/ringbuffer.h>
#include "deviceif.h"
#include "protocolif.h" #include "protocolif.h"
#include "statistics.h" #include "statistics.h"
class cIptvStreamer : public cThread, public cIptvStreamerStatistics { class cIptvStreamer : public cThread, public cIptvStreamerStatistics {
private: private:
cRingBufferLinear* ringBufferM;
cCondWait sleepM; cCondWait sleepM;
cIptvDeviceIf* deviceM;
unsigned char* packetBufferM; unsigned char* packetBufferM;
unsigned int packetBufferLenM; unsigned int packetBufferLenM;
cIptvProtocolIf* protocolM; cIptvProtocolIf* protocolM;
@@ -28,7 +28,7 @@ protected:
virtual void Action(void); virtual void Action(void);
public: public:
cIptvStreamer(cRingBufferLinear* ringBufferP, unsigned int packetLenP); cIptvStreamer(cIptvDeviceIf &deviceP, unsigned int packetLenP);
virtual ~cIptvStreamer(); virtual ~cIptvStreamer();
bool Set(const char* locationP, const int parameterP, const int indexP, cIptvProtocolIf* protocolP); bool Set(const char* locationP, const int parameterP, const int indexP, cIptvProtocolIf* protocolP);
bool Open(void); bool Open(void);