mirror of
https://github.com/rofafor/vdr-plugin-iptv.git
synced 2023-10-10 11:37:03 +00:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
547306b67c | ||
|
|
763c83209d | ||
|
|
af85ef1703 | ||
|
|
24ecadf414 | ||
|
|
f4126b7e2c | ||
|
|
c7cbde301b | ||
|
|
06506c41f6 | ||
|
|
c33b05076a | ||
|
|
38bd9a21f6 | ||
|
|
4c7b2ea69b | ||
|
|
c475b26515 | ||
|
|
9145fb8bb8 | ||
|
|
7a8b2962b2 | ||
|
|
626d0402c2 | ||
|
|
b3b06e569f | ||
|
|
ff84c54d50 | ||
|
|
4c39d8cf72 | ||
|
|
0b790260fa | ||
|
|
79113bbe09 | ||
|
|
30de763a4b | ||
|
|
868865c47d | ||
|
|
a73921041f | ||
|
|
49e3a9e23a | ||
|
|
73311873bc | ||
|
|
816c357065 | ||
|
|
5838bda3f0 | ||
|
|
079b02d69e | ||
|
|
6582f137b9 | ||
|
|
2bd31e9eda | ||
|
|
c2f88fbbb3 | ||
|
|
52ae2bdf63 | ||
|
|
1898defeb6 | ||
|
|
21719d3397 | ||
|
|
bf3fc70d2d | ||
|
|
99d6c0f207 | ||
|
|
ca4fdc761f | ||
|
|
37c5ee26ae | ||
|
|
8ba0b3a417 | ||
|
|
cfb60a06ba | ||
|
|
6ed0ebd734 | ||
|
|
2081ab41a8 | ||
|
|
66ab92584b | ||
|
|
05e57802c3 | ||
|
|
55bb0e65df | ||
|
|
ea4f8fde31 | ||
|
|
ef615c4bc5 | ||
|
|
a6d4e850fc | ||
|
|
fd06641449 | ||
|
|
05e52079f8 | ||
|
|
f0469e24cc | ||
|
|
7629e34d2a | ||
|
|
ac458b0c36 | ||
|
|
2d583e8cfa | ||
|
|
b0dba49fbc | ||
|
|
a05766c90d | ||
|
|
d1fdc390c9 | ||
|
|
d126da8ed8 | ||
|
|
2567501b65 | ||
|
|
12b54fbbc2 | ||
|
|
a2d8c367f6 | ||
|
|
3f88e7a911 | ||
|
|
8a96e5b327 | ||
|
|
170cb56263 | ||
|
|
899db53845 | ||
|
|
6eb259e8fb | ||
|
|
204c6020c4 | ||
|
|
c207b5cf6e | ||
|
|
d8585ba0fc | ||
|
|
1a825f5636 | ||
|
|
0720489995 |
45
HISTORY
45
HISTORY
@@ -132,3 +132,48 @@ VDR Plugin 'iptv' Revision History
|
|||||||
|
|
||||||
- Updated for vdr-1.7.13.
|
- Updated for vdr-1.7.13.
|
||||||
- Fixed argument corruption.
|
- Fixed argument corruption.
|
||||||
|
|
||||||
|
2010-03-09: Version 0.4.1
|
||||||
|
|
||||||
|
- Fixed channel parameter corruption.
|
||||||
|
- Added Dutch translation (Thanks to Carel).
|
||||||
|
|
||||||
|
2010-06-06: Version 0.4.2
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.15.
|
||||||
|
|
||||||
|
2012-02-02: Version 0.5.0
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.23.
|
||||||
|
- Renamed Sid scanner to section id scanner and added
|
||||||
|
experimental Tid/Nid support into it.
|
||||||
|
- Added optional source address validation for UDP protocol.
|
||||||
|
- Fixed audio pid detection in pid scanner.
|
||||||
|
- Changed ProvidesChannel() to set the need of detaching
|
||||||
|
receivers due to VDR's channel selection mechanism.
|
||||||
|
- Enabled partial content responses for HTTP protocol.
|
||||||
|
- Fixed EXT protocol execution (Thanks to Peter Holik).
|
||||||
|
- Disable detaching of receivers if retuned to an existing
|
||||||
|
channel (Thanks to Zdeněk Kopřivík).
|
||||||
|
- Canonicalized the configuration directory.
|
||||||
|
- Added support for LDFLAGS.
|
||||||
|
- Added cppcheck target into Makefile.
|
||||||
|
|
||||||
|
2012-04-02: Version 0.5.1
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.27.
|
||||||
|
- Updated Makefile.
|
||||||
|
- Silenced compilation warnings.
|
||||||
|
- Fixed channel switching bugs.
|
||||||
|
- Added support for a service interface.
|
||||||
|
- Changed UDP protocol to always utilize the source address
|
||||||
|
validation.
|
||||||
|
|
||||||
|
2012-04-26: Version 0.5.2
|
||||||
|
|
||||||
|
- Fixed connection problems in HTTP protocol.
|
||||||
|
|
||||||
|
2012-06-03: Version 1.0.0
|
||||||
|
|
||||||
|
- Optimized reading from UDP sockets.
|
||||||
|
- Fixed ProvidesChannel method.
|
||||||
|
|||||||
29
Makefile
29
Makefile
@@ -18,22 +18,24 @@ PLUGIN = iptv
|
|||||||
|
|
||||||
### The version number of this plugin (taken from the main source file):
|
### The version number of this plugin (taken from the main source file):
|
||||||
|
|
||||||
VERSION = $(shell grep 'static const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
|
VERSION = $(shell grep 'const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$5 }' | sed -e 's/[";]//g')
|
||||||
|
GITTAG = $(shell git describe --always 2>/dev/null)
|
||||||
|
|
||||||
### The C++ compiler and options:
|
### The C++ compiler and options:
|
||||||
|
|
||||||
CXX ?= g++
|
CXX ?= g++
|
||||||
CXXFLAGS ?= -fPIC -g -O2 -Wall -Wextra -Wswitch-default -Wfloat-equal -Wundef -Wpointer-arith -Wconversion -Wcast-align -Wredundant-decls -Wno-unused-parameter -Woverloaded-virtual -Wno-parentheses
|
CXXFLAGS ?= -fPIC -g -O3 -Wall -Wextra -Wswitch-default -Wfloat-equal -Wundef -Wpointer-arith -Wconversion -Wcast-align -Wredundant-decls -Wno-unused-parameter -Werror=overloaded-virtual -Wno-parentheses
|
||||||
|
LDFLAGS ?= -Wl,--as-needed
|
||||||
|
|
||||||
### The directory environment:
|
### The directory environment:
|
||||||
|
|
||||||
VDRDIR = ../../..
|
VDRDIR ?= ../../..
|
||||||
LIBDIR = ../../lib
|
LIBDIR ?= ../../lib
|
||||||
TMPDIR = /tmp
|
TMPDIR ?= /tmp
|
||||||
|
|
||||||
### Make sure that necessary options are included:
|
### Make sure that necessary options are included:
|
||||||
|
|
||||||
include $(VDRDIR)/Make.global
|
-include $(VDRDIR)/Make.global
|
||||||
|
|
||||||
### Allow user defined options to overwrite defaults:
|
### Allow user defined options to overwrite defaults:
|
||||||
|
|
||||||
@@ -58,6 +60,10 @@ ifdef IPTV_DEBUG
|
|||||||
DEFINES += -DDEBUG
|
DEFINES += -DDEBUG
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(strip $(GITTAG)),)
|
||||||
|
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all all-redirect
|
.PHONY: all all-redirect
|
||||||
all-redirect: all
|
all-redirect: all
|
||||||
|
|
||||||
@@ -73,7 +79,7 @@ all: libvdr-$(PLUGIN).so i18n
|
|||||||
|
|
||||||
### Implicit rules:
|
### Implicit rules:
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c Makefile
|
||||||
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
|
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
|
||||||
|
|
||||||
### Dependencies:
|
### Dependencies:
|
||||||
@@ -97,7 +103,7 @@ I18Npot = $(PODIR)/$(PLUGIN).pot
|
|||||||
msgfmt -c -o $@ $<
|
msgfmt -c -o $@ $<
|
||||||
|
|
||||||
$(I18Npot): $(wildcard *.c)
|
$(I18Npot): $(wildcard *.c)
|
||||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='Rolf Ahrenberg' -o $@ $^
|
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name='vdr-$(PLUGIN)' --package-version='$(VERSION)' --msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||||
|
|
||||||
%.po: $(I18Npot)
|
%.po: $(I18Npot)
|
||||||
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
|
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
|
||||||
@@ -113,13 +119,13 @@ i18n: $(I18Nmsgs) $(I18Npot)
|
|||||||
### Targets:
|
### Targets:
|
||||||
|
|
||||||
libvdr-$(PLUGIN).so: $(OBJS)
|
libvdr-$(PLUGIN).so: $(OBJS)
|
||||||
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
|
||||||
ifndef IPTV_DEBUG
|
ifndef IPTV_DEBUG
|
||||||
@$(STRIP) $@
|
@$(STRIP) $@
|
||||||
endif
|
endif
|
||||||
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
|
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
|
||||||
|
|
||||||
dist: clean
|
dist: $(I18Npo) clean
|
||||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||||
@mkdir $(TMPDIR)/$(ARCHIVE)
|
@mkdir $(TMPDIR)/$(ARCHIVE)
|
||||||
@cp -a * $(TMPDIR)/$(ARCHIVE)
|
@cp -a * $(TMPDIR)/$(ARCHIVE)
|
||||||
@@ -129,3 +135,6 @@ dist: clean
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
|
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
|
||||||
|
|
||||||
|
cppcheck: $(OBJS)
|
||||||
|
@cppcheck --enable=information,style,unusedFunction -v -f $(OBJS:%.o=%.c)
|
||||||
|
|||||||
19
README
19
README
@@ -100,18 +100,21 @@ Configuration:
|
|||||||
| | | | Stream address (multicast address, URL, file
|
| | | | Stream address (multicast address, URL, file
|
||||||
| | | | location, script location)
|
| | | | location, script location)
|
||||||
| | | Stream protocol ("UDP", "HTTP", "FILE", "EXT")
|
| | | Stream protocol ("UDP", "HTTP", "FILE", "EXT")
|
||||||
| | PID Scan ("0" disable, "1" enable)
|
| | Pid scanner ("0" disable, "1" enable)
|
||||||
| SID Scan ("0" disable, "1" enable)
|
| Section id (Sid/Nid/Tid) scanner ("0" disable, "1" enable)
|
||||||
Unique enumeration
|
Unique enumeration
|
||||||
|
|
||||||
- UDP multicast rules for iptables firewall
|
- UDP multicast rules for iptables firewall
|
||||||
|
|
||||||
# Multicast UDP -packets
|
# Multicast UDP packets
|
||||||
iptables -A INPUT -i eth0 -p udp -d 224.0.0.0/4 --dport 1234 -j ACCEPT
|
iptables -A INPUT -i eth0 -p udp -d 224.0.0.0/4 --dport 1234 -j ACCEPT
|
||||||
|
|
||||||
# IGMP required by multicasts
|
# IGMP required by multicasts
|
||||||
iptables -A INPUT -i eth0 -p igmp -d 224.0.0.0/4 -j ACCEPT
|
iptables -A INPUT -i eth0 -p igmp -d 224.0.0.0/4 -j ACCEPT
|
||||||
|
|
||||||
|
# Default routing for multicast
|
||||||
|
route add -net 224.0.0.0 netmask 224.0.0.0 eth0
|
||||||
|
|
||||||
External streaming:
|
External streaming:
|
||||||
|
|
||||||
- To watch an externally received channel add an EXT entry to channels.conf
|
- To watch an externally received channel add an EXT entry to channels.conf
|
||||||
@@ -154,6 +157,16 @@ Notes:
|
|||||||
script and the iptvstream-notrap.sh script should be used instead in these
|
script and the iptvstream-notrap.sh script should be used instead in these
|
||||||
cases.
|
cases.
|
||||||
|
|
||||||
|
- If received MPEG-2 TS streams carry CA descriptors, you'll have to apply
|
||||||
|
"disable_ca_updates" patch to the VDR in order to get rid of "Channel not
|
||||||
|
available" messages.
|
||||||
|
|
||||||
|
- EIT scanning functionality can be disabled for all IPTV channels by applying
|
||||||
|
the "disable_eitscan" patch to the VDR.
|
||||||
|
|
||||||
|
- Section id and pid scanners should be disabled after the correct data is
|
||||||
|
found. This can be made via VDR's channel editor.
|
||||||
|
|
||||||
Acknowledgements:
|
Acknowledgements:
|
||||||
|
|
||||||
- The IPTV section filtering code is derived from Linux kernel.
|
- The IPTV section filtering code is derived from Linux kernel.
|
||||||
|
|||||||
4
common.h
4
common.h
@@ -30,6 +30,8 @@
|
|||||||
#define IPTV_DEVICE_INFO_GENERAL 1
|
#define IPTV_DEVICE_INFO_GENERAL 1
|
||||||
#define IPTV_DEVICE_INFO_PIDS 2
|
#define IPTV_DEVICE_INFO_PIDS 2
|
||||||
#define IPTV_DEVICE_INFO_FILTERS 3
|
#define IPTV_DEVICE_INFO_FILTERS 3
|
||||||
|
#define IPTV_DEVICE_INFO_PROTOCOL 4
|
||||||
|
#define IPTV_DEVICE_INFO_BITRATE 5
|
||||||
|
|
||||||
#define IPTV_STATS_ACTIVE_PIDS_COUNT 10
|
#define IPTV_STATS_ACTIVE_PIDS_COUNT 10
|
||||||
#define IPTV_STATS_ACTIVE_FILTERS_COUNT 10
|
#define IPTV_STATS_ACTIVE_FILTERS_COUNT 10
|
||||||
@@ -77,5 +79,7 @@ struct section_filter_table_type {
|
|||||||
|
|
||||||
extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE];
|
extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE];
|
||||||
|
|
||||||
|
extern const char VERSION[];
|
||||||
|
|
||||||
#endif // __IPTV_COMMON_H
|
#endif // __IPTV_COMMON_H
|
||||||
|
|
||||||
|
|||||||
4
config.c
4
config.c
@@ -42,6 +42,6 @@ void cIptvConfig::SetDisabledFilters(unsigned int Index, int Number)
|
|||||||
|
|
||||||
void cIptvConfig::SetConfigDirectory(const char *directoryP)
|
void cIptvConfig::SetConfigDirectory(const char *directoryP)
|
||||||
{
|
{
|
||||||
debug("cIptvConfig::SetConfigDirectory(%s)", directoryP);
|
debug("cIptvConfig::SetConfigDirectory(%s)\n", directoryP);
|
||||||
strn0cpy(configDirectory, directoryP, sizeof(configDirectory));
|
ERROR_IF(!realpath(directoryP, configDirectory), "Cannot canonicalize configuration directory");
|
||||||
}
|
}
|
||||||
|
|||||||
2
config.h
2
config.h
@@ -20,7 +20,7 @@ private:
|
|||||||
unsigned int useBytes;
|
unsigned int useBytes;
|
||||||
unsigned int sectionFiltering;
|
unsigned int sectionFiltering;
|
||||||
int disabledFilters[SECTION_FILTER_TABLE_SIZE];
|
int disabledFilters[SECTION_FILTER_TABLE_SIZE];
|
||||||
char configDirectory[255];
|
char configDirectory[PATH_MAX];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvConfig();
|
cIptvConfig();
|
||||||
|
|||||||
68
device.c
68
device.c
@@ -21,7 +21,8 @@ cIptvDevice::cIptvDevice(unsigned int Index)
|
|||||||
isPacketDelivered(false),
|
isPacketDelivered(false),
|
||||||
isOpenDvr(false),
|
isOpenDvr(false),
|
||||||
sidScanEnabled(false),
|
sidScanEnabled(false),
|
||||||
pidScanEnabled(false)
|
pidScanEnabled(false),
|
||||||
|
channelId(tChannelID::InvalidID)
|
||||||
{
|
{
|
||||||
unsigned int bufsize = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize());
|
unsigned int bufsize = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize());
|
||||||
bufsize -= (bufsize % TS_SIZE);
|
bufsize -= (bufsize % TS_SIZE);
|
||||||
@@ -35,13 +36,13 @@ cIptvDevice::cIptvDevice(unsigned int Index)
|
|||||||
pFileProtocol = new cIptvProtocolFile();
|
pFileProtocol = new cIptvProtocolFile();
|
||||||
pExtProtocol = new cIptvProtocolExt();
|
pExtProtocol = new cIptvProtocolExt();
|
||||||
pIptvStreamer = new cIptvStreamer(tsBuffer, (100 * TS_SIZE));
|
pIptvStreamer = new cIptvStreamer(tsBuffer, (100 * TS_SIZE));
|
||||||
pPidScanner = new cPidScanner;
|
pPidScanner = new cPidScanner();
|
||||||
// Initialize filter pointers
|
// Initialize filter pointers
|
||||||
memset(secfilters, '\0', sizeof(secfilters));
|
memset(secfilters, '\0', sizeof(secfilters));
|
||||||
// Start section handler for iptv device
|
// Start section handler for iptv device
|
||||||
StartSectionHandler();
|
StartSectionHandler();
|
||||||
// Sid scanner must be created after the section handler
|
// Sid scanner must be created after the section handler
|
||||||
pSidScanner = new cSidScanner;
|
pSidScanner = new cSidScanner();
|
||||||
if (pSidScanner)
|
if (pSidScanner)
|
||||||
AttachFilter(pSidScanner);
|
AttachFilter(pSidScanner);
|
||||||
// Check if dvr fifo exists
|
// Check if dvr fifo exists
|
||||||
@@ -122,7 +123,7 @@ cIptvDevice *cIptvDevice::GetIptvDevice(int CardIndex)
|
|||||||
cString cIptvDevice::GetGeneralInformation(void)
|
cString cIptvDevice::GetGeneralInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvDevice::GetGeneralInformation(%d)\n", deviceIndex);
|
//debug("cIptvDevice::GetGeneralInformation(%d)\n", deviceIndex);
|
||||||
return cString::sprintf("IPTV device: %d\nCardIndex: %d\n%s%s%sChannel: %s",
|
return cString::sprintf("IPTV device: %d\nCardIndex: %d\nStream: %s\nStream bitrate: %s\n%sChannel: %s",
|
||||||
deviceIndex, CardIndex(),
|
deviceIndex, CardIndex(),
|
||||||
pIptvStreamer ? *pIptvStreamer->GetInformation() : "",
|
pIptvStreamer ? *pIptvStreamer->GetInformation() : "",
|
||||||
pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "",
|
pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "",
|
||||||
@@ -168,6 +169,12 @@ cString cIptvDevice::GetInformation(unsigned int Page)
|
|||||||
case IPTV_DEVICE_INFO_FILTERS:
|
case IPTV_DEVICE_INFO_FILTERS:
|
||||||
info = GetFiltersInformation();
|
info = GetFiltersInformation();
|
||||||
break;
|
break;
|
||||||
|
case IPTV_DEVICE_INFO_PROTOCOL:
|
||||||
|
info = pIptvStreamer ? *pIptvStreamer->GetInformation() : "";
|
||||||
|
break;
|
||||||
|
case IPTV_DEVICE_INFO_BITRATE:
|
||||||
|
info = pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
info = cString::sprintf("%s%s%s",
|
info = cString::sprintf("%s%s%s",
|
||||||
*GetGeneralInformation(),
|
*GetGeneralInformation(),
|
||||||
@@ -178,10 +185,34 @@ cString cIptvDevice::GetInformation(unsigned int Page)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cString cIptvDevice::DeviceType(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::DeviceType(%d)\n", deviceIndex);
|
||||||
|
return "IPTV";
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cIptvDevice::DeviceName(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::DeviceName(%d)\n", deviceIndex);
|
||||||
|
return cString::sprintf("IPTV %d", deviceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvDevice::SignalStrength(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::SignalStrength(%d)\n", deviceIndex);
|
||||||
|
return (100);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvDevice::SignalQuality(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::SignalQuality(%d)\n", deviceIndex);
|
||||||
|
return (100);
|
||||||
|
}
|
||||||
|
|
||||||
bool cIptvDevice::ProvidesSource(int Source) const
|
bool cIptvDevice::ProvidesSource(int Source) const
|
||||||
{
|
{
|
||||||
debug("cIptvDevice::ProvidesSource(%d)\n", deviceIndex);
|
debug("cIptvDevice::ProvidesSource(%d)\n", deviceIndex);
|
||||||
return ((Source & cSource::st_Mask) == (IPTV_SOURCE_CHARACTER << 24));
|
return (cSource::IsType(Source, IPTV_SOURCE_CHARACTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
|
bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
|
||||||
@@ -193,16 +224,30 @@ bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
|
|||||||
bool cIptvDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
bool cIptvDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
bool hasPriority = Priority == IDLEPRIORITY || Priority > this->Priority();
|
||||||
bool needsDetachReceivers = false;
|
bool needsDetachReceivers = false;
|
||||||
|
|
||||||
debug("cIptvDevice::ProvidesChannel(%d)\n", deviceIndex);
|
debug("cIptvDevice::ProvidesChannel(%d)\n", deviceIndex);
|
||||||
if (ProvidesTransponder(Channel))
|
|
||||||
result = true;
|
if (Channel && ProvidesTransponder(Channel)) {
|
||||||
|
result = hasPriority;
|
||||||
|
if (Receiving()) {
|
||||||
|
if (Channel->GetChannelID() == channelId)
|
||||||
|
result = true;
|
||||||
|
else
|
||||||
|
needsDetachReceivers = Receiving();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (NeedsDetachReceivers)
|
if (NeedsDetachReceivers)
|
||||||
*NeedsDetachReceivers = needsDetachReceivers;
|
*NeedsDetachReceivers = needsDetachReceivers;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cIptvDevice::ProvidesEIT(void) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int cIptvDevice::NumProvidedSystems(void) const
|
int cIptvDevice::NumProvidedSystems(void) const
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@@ -214,7 +259,7 @@ bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
cIptvTransponderParameters itp(Channel->Parameters());
|
cIptvTransponderParameters itp(Channel->Parameters());
|
||||||
|
|
||||||
debug("cIptvDevice::SetChannelDevice(%d)\n", deviceIndex);
|
debug("cIptvDevice::SetChannelDevice(%d)\n", deviceIndex);
|
||||||
|
|
||||||
if (isempty(itp.Address())) {
|
if (isempty(itp.Address())) {
|
||||||
error("Unrecognized IPTV address: %s", Channel->Parameters());
|
error("Unrecognized IPTV address: %s", Channel->Parameters());
|
||||||
return false;
|
return false;
|
||||||
@@ -240,10 +285,11 @@ bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
sidScanEnabled = itp.SidScan() ? true : false;
|
sidScanEnabled = itp.SidScan() ? true : false;
|
||||||
pidScanEnabled = itp.PidScan() ? true : false;
|
pidScanEnabled = itp.PidScan() ? true : false;
|
||||||
if (pIptvStreamer->Set(itp.Address(), itp.Parameter(), deviceIndex, protocol)) {
|
if (pIptvStreamer->Set(itp.Address(), itp.Parameter(), deviceIndex, protocol)) {
|
||||||
|
channelId = Channel->GetChannelID();
|
||||||
if (sidScanEnabled && pSidScanner && IptvConfig.GetSectionFiltering())
|
if (sidScanEnabled && pSidScanner && IptvConfig.GetSectionFiltering())
|
||||||
pSidScanner->SetChannel(Channel);
|
pSidScanner->SetChannel(channelId);
|
||||||
if (pidScanEnabled && pPidScanner)
|
if (pidScanEnabled && pPidScanner)
|
||||||
pPidScanner->SetChannel(Channel);
|
pPidScanner->SetChannel(channelId);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -370,7 +416,6 @@ bool cIptvDevice::IsBuffering(void)
|
|||||||
|
|
||||||
bool cIptvDevice::GetTSPacket(uchar *&Data)
|
bool cIptvDevice::GetTSPacket(uchar *&Data)
|
||||||
{
|
{
|
||||||
int Count = 0;
|
|
||||||
//debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
|
//debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
|
||||||
if (tsBuffer && !IsBuffering()) {
|
if (tsBuffer && !IsBuffering()) {
|
||||||
if (isPacketDelivered) {
|
if (isPacketDelivered) {
|
||||||
@@ -379,6 +424,7 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
|
|||||||
// Update buffer statistics
|
// Update buffer statistics
|
||||||
AddBufferStatistic(TS_SIZE, tsBuffer->Available());
|
AddBufferStatistic(TS_SIZE, tsBuffer->Available());
|
||||||
}
|
}
|
||||||
|
int Count = 0;
|
||||||
uchar *p = tsBuffer->Get(Count);
|
uchar *p = tsBuffer->Get(Count);
|
||||||
if (p && Count >= TS_SIZE) {
|
if (p && Count >= TS_SIZE) {
|
||||||
if (*p != TS_SYNC_BYTE) {
|
if (*p != TS_SYNC_BYTE) {
|
||||||
|
|||||||
10
device.h
10
device.h
@@ -41,6 +41,7 @@ private:
|
|||||||
bool pidScanEnabled;
|
bool pidScanEnabled;
|
||||||
cRingBufferLinear *tsBuffer;
|
cRingBufferLinear *tsBuffer;
|
||||||
int tsBufferPrefill;
|
int tsBufferPrefill;
|
||||||
|
tChannelID channelId;
|
||||||
cIptvProtocolUdp *pUdpProtocol;
|
cIptvProtocolUdp *pUdpProtocol;
|
||||||
cIptvProtocolHttp *pHttpProtocol;
|
cIptvProtocolHttp *pHttpProtocol;
|
||||||
cIptvProtocolFile *pFileProtocol;
|
cIptvProtocolFile *pFileProtocol;
|
||||||
@@ -49,7 +50,7 @@ private:
|
|||||||
cPidScanner *pPidScanner;
|
cPidScanner *pPidScanner;
|
||||||
cSidScanner *pSidScanner;
|
cSidScanner *pSidScanner;
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
cIptvSectionFilter* secfilters[eMaxSecFilterCount];
|
cIptvSectionFilter *secfilters[eMaxSecFilterCount];
|
||||||
|
|
||||||
// constructor & destructor
|
// constructor & destructor
|
||||||
public:
|
public:
|
||||||
@@ -74,11 +75,18 @@ private:
|
|||||||
bool DeleteFilter(unsigned int Index);
|
bool DeleteFilter(unsigned int Index);
|
||||||
bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const;
|
bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const;
|
||||||
|
|
||||||
|
// for channel info
|
||||||
|
virtual cString DeviceType(void) const;
|
||||||
|
virtual cString DeviceName(void) const;
|
||||||
|
virtual int SignalStrength(void) const;
|
||||||
|
virtual int SignalQuality(void) const;
|
||||||
|
|
||||||
// for channel selection
|
// for channel selection
|
||||||
public:
|
public:
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
||||||
|
virtual bool ProvidesEIT(void) const;
|
||||||
virtual int NumProvidedSystems(void) const;
|
virtual int NumProvidedSystems(void) const;
|
||||||
protected:
|
protected:
|
||||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||||
|
|||||||
25
iptv.c
25
iptv.c
@@ -11,12 +11,17 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "iptvservice.h"
|
||||||
|
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM < 10713
|
#if defined(APIVERSNUM) && APIVERSNUM < 10727
|
||||||
#error "VDR-1.7.13 API version or greater is required!"
|
#error "VDR-1.7.27 API version or greater is required!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char VERSION[] = "0.4.0";
|
#ifndef GITVERSION
|
||||||
|
#define GITVERSION ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char VERSION[] = "1.0.0" 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 {
|
||||||
@@ -196,8 +201,18 @@ bool cPluginIptv::SetupParse(const char *Name, const char *Value)
|
|||||||
|
|
||||||
bool cPluginIptv::Service(const char *Id, void *Data)
|
bool cPluginIptv::Service(const char *Id, void *Data)
|
||||||
{
|
{
|
||||||
//debug("cPluginIptv::Service()\n");
|
debug("cPluginIptv::Service()\n");
|
||||||
// Handle custom service requests from other plugins
|
if (strcmp(Id,"IptvService-v1.0") == 0) {
|
||||||
|
if (Data) {
|
||||||
|
IptvService_v1_0 *data = (IptvService_v1_0*)Data;
|
||||||
|
cIptvDevice *dev = cIptvDevice::GetIptvDevice(data->cardIndex);
|
||||||
|
if (!dev)
|
||||||
|
return false;
|
||||||
|
data->protocol = dev->GetInformation(IPTV_DEVICE_INFO_PROTOCOL);
|
||||||
|
data->bitrate = dev->GetInformation(IPTV_DEVICE_INFO_BITRATE);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ case ${PARAMETER} in
|
|||||||
URL=""
|
URL=""
|
||||||
WIDTH=720
|
WIDTH=720
|
||||||
HEIGHT=576
|
HEIGHT=576
|
||||||
|
FPS=25
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
URL=""
|
URL=""
|
||||||
@@ -66,6 +67,9 @@ TRANSCODE_OPTS="vcodec=${VCODEC},acodec=${ACODEC},vb=${VBITRATE},ab=${ABITRATE}"
|
|||||||
if [ -n "${WIDTH}" -a -n "${HEIGHT}" ] ; then
|
if [ -n "${WIDTH}" -a -n "${HEIGHT}" ] ; then
|
||||||
TRANSCODE_OPTS="${TRANSCODE_OPTS},width=${WIDTH},height=${HEIGHT}"
|
TRANSCODE_OPTS="${TRANSCODE_OPTS},width=${WIDTH},height=${HEIGHT}"
|
||||||
fi
|
fi
|
||||||
|
if [ -n "${FPS}" ] ; then
|
||||||
|
TRANSCODE_OPTS="${TRANSCODE_OPTS},fps=${FPS}"
|
||||||
|
fi
|
||||||
|
|
||||||
# Create unique pids for the stream
|
# Create unique pids for the stream
|
||||||
let VPID=${PARAMETER}+1
|
let VPID=${PARAMETER}+1
|
||||||
|
|||||||
22
iptvservice.h
Normal file
22
iptvservice.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* iptvservice.h: IPTV plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IPTVSERVICE_H
|
||||||
|
#define __IPTVSERVICE_H
|
||||||
|
|
||||||
|
#include <vdr/tools.h>
|
||||||
|
|
||||||
|
#define stIptv ('I' << 24)
|
||||||
|
|
||||||
|
struct IptvService_v1_0 {
|
||||||
|
unsigned int cardIndex;
|
||||||
|
cString protocol;
|
||||||
|
cString bitrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__IPTVSERVICE_H
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
diff -Nru vdr-1.7.13-vanilla/pat.c vdr-1.7.13-disable_ca_updates/pat.c
|
|
||||||
--- vdr-1.7.13-vanilla/pat.c 2010-01-01 17:40:05.000000000 +0200
|
|
||||||
+++ vdr-1.7.13-disable_ca_updates/pat.c 2010-03-04 13:44:28.000000000 +0200
|
|
||||||
@@ -458,6 +458,7 @@
|
|
||||||
}
|
|
||||||
if (Setup.UpdateChannels >= 2) {
|
|
||||||
Channel->SetPids(Vpid, Ppid, Vtype, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
|
|
||||||
+ if (!Channel->IsPlug())
|
|
||||||
Channel->SetCaIds(CaDescriptors->CaIds());
|
|
||||||
Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
diff -Nru vdr-1.7.13-vanilla/eitscan.c vdr-1.7.13-disable_eitscan/eitscan.c
|
|
||||||
--- vdr-1.7.13-vanilla/eitscan.c 2010-02-07 14:12:05.000000000 +0200
|
|
||||||
+++ vdr-1.7.13-disable_eitscan/eitscan.c 2010-03-04 13:44:17.000000000 +0200
|
|
||||||
@@ -146,7 +146,7 @@
|
|
||||||
if (Device) {
|
|
||||||
for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) {
|
|
||||||
const cChannel *Channel = ScanData->GetChannel();
|
|
||||||
- if (Channel) {
|
|
||||||
+ if (Channel && !Channel->IsPlug()) {
|
|
||||||
if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
|
|
||||||
if (Device->ProvidesTransponder(Channel)) {
|
|
||||||
if (!Device->Receiving()) {
|
|
||||||
11
patches/vdr-1.7.27-disable_ca_updates.patch
Normal file
11
patches/vdr-1.7.27-disable_ca_updates.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
diff -Nru vdr-1.7.27-vanilla/pat.c vdr-1.7.27-disable_ca_updates/pat.c
|
||||||
|
--- vdr-1.7.27-vanilla/pat.c 2012-03-25 15:17:57.000000000 +0300
|
||||||
|
+++ vdr-1.7.27-disable_ca_updates/pat.c 2012-03-31 20:42:14.000000000 +0300
|
||||||
|
@@ -537,6 +537,7 @@
|
||||||
|
}
|
||||||
|
if (Setup.UpdateChannels >= 2) {
|
||||||
|
Channel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
|
||||||
|
+ if (!cSource::IsType(Channel->Source(), 'I'))
|
||||||
|
Channel->SetCaIds(CaDescriptors->CaIds());
|
||||||
|
Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
|
||||||
|
}
|
||||||
37
pidscanner.c
37
pidscanner.c
@@ -13,8 +13,9 @@
|
|||||||
#define PIDSCANNER_VPID_COUNT 5 /* minimum count of video pid samples for pid detection */
|
#define PIDSCANNER_VPID_COUNT 5 /* minimum count of video pid samples for pid detection */
|
||||||
#define PIDSCANNER_PID_DELTA_COUNT 100 /* minimum count of pid samples for audio/video only pid detection */
|
#define PIDSCANNER_PID_DELTA_COUNT 100 /* minimum count of pid samples for audio/video only pid detection */
|
||||||
|
|
||||||
cPidScanner::cPidScanner(void)
|
cPidScanner::cPidScanner(void)
|
||||||
: timeout(0),
|
: timeout(0),
|
||||||
|
channelId(tChannelID::InvalidID),
|
||||||
process(true),
|
process(true),
|
||||||
Vpid(0xFFFF),
|
Vpid(0xFFFF),
|
||||||
Apid(0xFFFF),
|
Apid(0xFFFF),
|
||||||
@@ -22,24 +23,17 @@ cPidScanner::cPidScanner(void)
|
|||||||
numApids(0)
|
numApids(0)
|
||||||
{
|
{
|
||||||
debug("cPidScanner::cPidScanner()\n");
|
debug("cPidScanner::cPidScanner()\n");
|
||||||
channel = cChannel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cPidScanner::~cPidScanner()
|
cPidScanner::~cPidScanner()
|
||||||
{
|
{
|
||||||
debug("cPidScanner::~cPidScanner()\n");
|
debug("cPidScanner::~cPidScanner()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPidScanner::SetChannel(const cChannel *Channel)
|
void cPidScanner::SetChannel(const tChannelID &ChannelId)
|
||||||
{
|
{
|
||||||
if (Channel) {
|
debug("cPidScanner::SetChannel(): %s\n", *ChannelId.ToString());
|
||||||
debug("cPidScanner::SetChannel(): %s\n", Channel->Parameters());
|
channelId = ChannelId;
|
||||||
channel = *Channel;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
debug("cPidScanner::SetChannel()\n");
|
|
||||||
channel = cChannel();
|
|
||||||
}
|
|
||||||
Vpid = 0xFFFF;
|
Vpid = 0xFFFF;
|
||||||
numVpids = 0;
|
numVpids = 0;
|
||||||
Apid = 0xFFFF;
|
Apid = 0xFFFF;
|
||||||
@@ -119,14 +113,17 @@ void cPidScanner::Process(const uint8_t* buf)
|
|||||||
timeout.Set(PIDSCANNER_TIMEOUT_IN_MS);
|
timeout.Set(PIDSCANNER_TIMEOUT_IN_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cChannel *IptvChannel = Channels.GetByChannelID(channel.GetChannelID());
|
cChannel *IptvChannel = Channels.GetByChannelID(channelId);
|
||||||
if (IptvChannel) {
|
if (IptvChannel) {
|
||||||
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
||||||
|
int Atypes[MAXAPIDS + 1] = { 0 };
|
||||||
int Dpids[MAXDPIDS + 1] = { 0 };
|
int Dpids[MAXDPIDS + 1] = { 0 };
|
||||||
|
int Dtypes[MAXDPIDS + 1] = { 0 };
|
||||||
int Spids[MAXSPIDS + 1] = { 0 };
|
int Spids[MAXSPIDS + 1] = { 0 };
|
||||||
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
|
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
|
||||||
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
|
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
|
||||||
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
|
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
|
||||||
|
int Vtype = IptvChannel->Vtype();
|
||||||
int Ppid = IptvChannel->Ppid();
|
int Ppid = IptvChannel->Ppid();
|
||||||
int Tpid = IptvChannel->Tpid();
|
int Tpid = IptvChannel->Tpid();
|
||||||
bool foundApid = false;
|
bool foundApid = false;
|
||||||
@@ -134,20 +131,24 @@ void cPidScanner::Process(const uint8_t* buf)
|
|||||||
Vpid = 0; // No detected video pid
|
Vpid = 0; // No detected video pid
|
||||||
else if (numApids < PIDSCANNER_APID_COUNT)
|
else if (numApids < PIDSCANNER_APID_COUNT)
|
||||||
Apid = 0; // No detected audio pid
|
Apid = 0; // No detected audio pid
|
||||||
for (unsigned int i = 1; i < MAXAPIDS; ++i) {
|
for (unsigned int i = 0; i < MAXAPIDS; ++i) {
|
||||||
Apids[i] = IptvChannel->Apid(i);
|
Apids[i] = IptvChannel->Apid(i);
|
||||||
|
Atypes[i] = IptvChannel->Atype(i);
|
||||||
if (Apids[i] && (Apids[i] == Apid))
|
if (Apids[i] && (Apids[i] == Apid))
|
||||||
foundApid = true;
|
foundApid = true;
|
||||||
}
|
}
|
||||||
if (!foundApid)
|
if (!foundApid) {
|
||||||
Apids[0] = Apid;
|
Apids[0] = Apid;
|
||||||
for (unsigned int i = 0; i < MAXDPIDS; ++i)
|
Atypes[0] = 4;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < MAXDPIDS; ++i) {
|
||||||
Dpids[i] = IptvChannel->Dpid(i);
|
Dpids[i] = IptvChannel->Dpid(i);
|
||||||
|
Dtypes[i] = IptvChannel->Dtype(i);
|
||||||
|
}
|
||||||
for (unsigned int i = 0; i < MAXSPIDS; ++i)
|
for (unsigned int i = 0; i < MAXSPIDS; ++i)
|
||||||
Spids[i] = IptvChannel->Spid(i);
|
Spids[i] = IptvChannel->Spid(i);
|
||||||
debug("cPidScanner::Process(): Vpid=0x%04X, Apid=0x%04X\n", Vpid, Apid);
|
debug("cPidScanner::Process(): Vpid=0x%04X, Apid=0x%04X\n", Vpid, Apid);
|
||||||
int Vtype = IptvChannel->Vtype();
|
IptvChannel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
|
||||||
IptvChannel->SetPids(Vpid, Ppid, Vtype, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
|
|
||||||
}
|
}
|
||||||
Channels.Unlock();
|
Channels.Unlock();
|
||||||
process = false;
|
process = false;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
class cPidScanner {
|
class cPidScanner {
|
||||||
private:
|
private:
|
||||||
cTimeMs timeout;
|
cTimeMs timeout;
|
||||||
cChannel channel;
|
tChannelID channelId;
|
||||||
bool process;
|
bool process;
|
||||||
int Vpid;
|
int Vpid;
|
||||||
int Apid;
|
int Apid;
|
||||||
@@ -24,7 +24,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
cPidScanner(void);
|
cPidScanner(void);
|
||||||
~cPidScanner();
|
~cPidScanner();
|
||||||
void SetChannel(const cChannel *Channel);
|
void SetChannel(const tChannelID &ChannelId);
|
||||||
void Process(const uint8_t* buf);
|
void Process(const uint8_t* buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
15
po/de_DE.po
15
po/de_DE.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2007-10-29 21:19+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Tobias Grimm <tg@e-tobi.net>\n"
|
"Last-Translator: Tobias Grimm <tg@e-tobi.net>\n"
|
||||||
"Language-Team: German\n"
|
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||||
|
"Language: de\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -135,8 +136,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scanne SID"
|
msgstr "Scanne Section IDS"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scanne PIDS"
|
msgstr "Scanne PIDS"
|
||||||
|
|||||||
15
po/fi_FI.po
15
po/fi_FI.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2007-08-12 23:22+0300\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Rolf Ahrenberg\n"
|
"Last-Translator: Rolf Ahrenberg\n"
|
||||||
"Language-Team: <vdr@linuxtv.org>\n"
|
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
||||||
|
"Language: fi\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -150,8 +151,8 @@ msgstr "Lähete-ID"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Radio-ID"
|
msgstr "Radio-ID"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Etsi palvelu-ID"
|
msgstr "Etsi sektiotunnisteet"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Etsi pidit"
|
msgstr "Etsi pidit"
|
||||||
|
|||||||
15
po/fr_FR.po
15
po/fr_FR.po
@@ -6,12 +6,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2008-01-26 13:14+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: NIVAL Michaël <mnival@club-internet.fr>\n"
|
"Last-Translator: NIVAL Michaël <mnival@club-internet.fr>\n"
|
||||||
"Language-Team: French\n"
|
"Language-Team: French <vdr@linuxtv.org>\n"
|
||||||
|
"Language: fr\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -152,8 +153,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scanne les SID"
|
msgstr "Scanne les section ID"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scanne les PID"
|
msgstr "Scanne les PID"
|
||||||
|
|||||||
15
po/it_IT.po
15
po/it_IT.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2008-07-13 03:28+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
||||||
"Language-Team: Italian\n"
|
"Language-Team: Italian <vdr@linuxtv.org>\n"
|
||||||
|
"Language: it\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -151,8 +152,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scansione Sid"
|
msgstr "Scansione Section Ids"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scansione Pids"
|
msgstr "Scansione Pids"
|
||||||
|
|||||||
167
po/nl_NL.po
Normal file
167
po/nl_NL.po
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# VDR plugin language source file.
|
||||||
|
# Copyright (C) 2007 Rolf Ahrenberg & Antti Seppala
|
||||||
|
# This file is distributed under the same license as the iptv package.
|
||||||
|
# Carel, 2010.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
|
"Last-Translator: Carel\n"
|
||||||
|
"Language-Team: Dutch <vdr@linuxtv.org>\n"
|
||||||
|
"Language: nl\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
msgid "PAT (0x00)"
|
||||||
|
msgstr "PAT (0x00)"
|
||||||
|
|
||||||
|
msgid "NIT (0x40)"
|
||||||
|
msgstr "NIT (0x40)"
|
||||||
|
|
||||||
|
msgid "SDT (0x42)"
|
||||||
|
msgstr "SDT (0x42)"
|
||||||
|
|
||||||
|
msgid "EIT (0x4E/0x4F)"
|
||||||
|
msgstr "EIT (0x4E/0x4F)"
|
||||||
|
|
||||||
|
msgid "EIT (0x5X)"
|
||||||
|
msgstr "EIT (0x5X)"
|
||||||
|
|
||||||
|
msgid "EIT (0x6X)"
|
||||||
|
msgstr "EIT (0x6X)"
|
||||||
|
|
||||||
|
msgid "TDT (0x70)"
|
||||||
|
msgstr "TDT (0x70)"
|
||||||
|
|
||||||
|
msgid "Experience the IPTV"
|
||||||
|
msgstr "TV programma's via IP"
|
||||||
|
|
||||||
|
msgid "IPTV Information"
|
||||||
|
msgstr "IPTV informatie"
|
||||||
|
|
||||||
|
msgid "General"
|
||||||
|
msgstr "Algemeen"
|
||||||
|
|
||||||
|
msgid "Pids"
|
||||||
|
msgstr "Pids"
|
||||||
|
|
||||||
|
msgid "Filters"
|
||||||
|
msgstr "Filter"
|
||||||
|
|
||||||
|
msgid "Bits/bytes"
|
||||||
|
msgstr "Bits/Bytes"
|
||||||
|
|
||||||
|
msgid "IPTV information not available!"
|
||||||
|
msgstr "IPTV informatie niet beschikbaar!"
|
||||||
|
|
||||||
|
msgid "TS buffer size [MB]"
|
||||||
|
msgstr "TS buffergrootte [MB]"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define a ringbuffer size for transport streams in megabytes.\n"
|
||||||
|
"\n"
|
||||||
|
"Smaller sizes help memory consumption, but are more prone to buffer overflows."
|
||||||
|
msgstr ""
|
||||||
|
"Stel de grootte van de ringbuffer vast voor transportstreams in megabytes.\n"
|
||||||
|
"\n"
|
||||||
|
"Bij lage waarden zapt VDR sneller maar kunnen leiden tot bufferoverschreidingen en dus dropouts."
|
||||||
|
|
||||||
|
msgid "TS buffer prefill ratio [%]"
|
||||||
|
msgstr "TS buffer-preload [%]"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define a prefill ratio of the ringbuffer for transport streams before data is transferred to VDR.\n"
|
||||||
|
"\n"
|
||||||
|
"This is useful if streaming media over a slow or unreliable connection."
|
||||||
|
msgstr ""
|
||||||
|
"Stel een 'prefil ratio' in voor de ringbuffer voor transportstreams voor de data naar VDR wordt verstuurd.\n"
|
||||||
|
"\n"
|
||||||
|
"Dit is aan te bevelen bij onbetrouwbare of langzame verbindingen."
|
||||||
|
|
||||||
|
msgid "EXT protocol base port"
|
||||||
|
msgstr "EXT protocol basispoort"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define a base port used by EXT protocol.\n"
|
||||||
|
"\n"
|
||||||
|
"The port range is defined by the number of IPTV devices. This setting sets the port which is listened for connections from external applications when using the EXT protocol."
|
||||||
|
msgstr ""
|
||||||
|
"Bepaal de basispoort voor het EXT protocol.\n"
|
||||||
|
"\n"
|
||||||
|
"De poortrange wordt bepaald door het aantal IPTV apparaten. Deze poort luistert naar inkomende verbindingen wanneer het EXT protocol wordt gebruikt."
|
||||||
|
|
||||||
|
msgid "Use section filtering"
|
||||||
|
msgstr "Benutze Abschnittsfilterung"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define whether the section filtering shall be used.\n"
|
||||||
|
"\n"
|
||||||
|
"Section filtering means that IPTV plugin tries to parse and provide VDR with secondary data about the currently active stream. VDR can then use this data for providing various functionalities such as automatic pid change detection and EPG etc.\n"
|
||||||
|
"Enabling this feature does not affect streams that do not contain section data."
|
||||||
|
msgstr ""
|
||||||
|
"Bepaal of er sectionfilterimg moet worden gebrukt.\n"
|
||||||
|
"\n"
|
||||||
|
"Bij sectiefiltering zal de IPTV plugin VDR van extra informatie over de stream voorzien. VDR kan dan bijvoorbeeld automatisch de PIDs wijzigen of de EPG tonen.Het gebruik van deze mogelijkheid heeft geen effect op streams die geen sectiedata bevatten."
|
||||||
|
|
||||||
|
msgid "Disable filters"
|
||||||
|
msgstr "Deactiveer filter"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define number of section filters to be disabled.\n"
|
||||||
|
"\n"
|
||||||
|
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
||||||
|
msgstr ""
|
||||||
|
"Bepaal het aantal de de-activeren sectiefilters.\n"
|
||||||
|
"\n"
|
||||||
|
"Sommige sctiefilters kunnen ongewenste effecten veroorzaken. Door ze hier op te nemen blijft de data intact zodat VDR het kan blijven gebruiken."
|
||||||
|
|
||||||
|
#. TRANSLATORS: note the singular!
|
||||||
|
msgid "Disable filter"
|
||||||
|
msgstr "Deactiveer filter"
|
||||||
|
|
||||||
|
msgid "Define an ill-behaving filter to be blacklisted."
|
||||||
|
msgstr "Blacklist een probleem veroorzakend filter "
|
||||||
|
|
||||||
|
msgid "Help"
|
||||||
|
msgstr "Help"
|
||||||
|
|
||||||
|
msgid "UDP"
|
||||||
|
msgstr "UDP"
|
||||||
|
|
||||||
|
msgid "HTTP"
|
||||||
|
msgstr "HTTP"
|
||||||
|
|
||||||
|
msgid "FILE"
|
||||||
|
msgstr "BESTAND"
|
||||||
|
|
||||||
|
msgid "EXT"
|
||||||
|
msgstr "EXT"
|
||||||
|
|
||||||
|
msgid "Nid"
|
||||||
|
msgstr "Nid"
|
||||||
|
|
||||||
|
msgid "Tid"
|
||||||
|
msgstr "Tid"
|
||||||
|
|
||||||
|
msgid "Rid"
|
||||||
|
msgstr "Rid"
|
||||||
|
|
||||||
|
msgid "Scan section ids"
|
||||||
|
msgstr "Scan section IDS"
|
||||||
|
|
||||||
|
msgid "Scan pids"
|
||||||
|
msgstr "Scan PIDS"
|
||||||
|
|
||||||
|
msgid "Protocol"
|
||||||
|
msgstr "Protocol"
|
||||||
|
|
||||||
|
msgid "Address"
|
||||||
|
msgstr "Adres"
|
||||||
|
|
||||||
|
msgid "Parameter"
|
||||||
|
msgstr "Parameter"
|
||||||
15
po/ru_RU.po
15
po/ru_RU.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2008-03-16 12:14+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Alexander Gross <Bikalexander@gmail.com>\n"
|
"Last-Translator: Alexander Gross <Bikalexander@gmail.com>\n"
|
||||||
"Language-Team: Russian <de@li.org>\n"
|
"Language-Team: Russian <vdr@linuxtv.org>\n"
|
||||||
|
"Language: ru\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -136,8 +137,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Сканировать SID"
|
msgstr "Сканировать section ids"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Сканировать пиды"
|
msgstr "Сканировать пиды"
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
cIptvProtocolExt::cIptvProtocolExt()
|
cIptvProtocolExt::cIptvProtocolExt()
|
||||||
: pid(-1),
|
: pid(-1),
|
||||||
scriptFile(""),
|
scriptFile(""),
|
||||||
scriptParameter(0)
|
scriptParameter(0),
|
||||||
|
streamPort(0)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::cIptvProtocolExt()\n");
|
debug("cIptvProtocolExt::cIptvProtocolExt()\n");
|
||||||
}
|
}
|
||||||
@@ -38,6 +39,8 @@ void cIptvProtocolExt::ExecuteScript(void)
|
|||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::ExecuteScript()\n");
|
debug("cIptvProtocolExt::ExecuteScript()\n");
|
||||||
// Check if already executing
|
// Check if already executing
|
||||||
|
if (isActive || isempty(scriptFile))
|
||||||
|
return;
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
error("Cannot execute script!");
|
error("Cannot execute script!");
|
||||||
return;
|
return;
|
||||||
@@ -51,9 +54,9 @@ void cIptvProtocolExt::ExecuteScript(void)
|
|||||||
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
||||||
close(i);
|
close(i);
|
||||||
// Execute the external script
|
// Execute the external script
|
||||||
cString cmd = cString::sprintf("%s %d %d", *scriptFile, scriptParameter, socketPort);
|
cString cmd = cString::sprintf("%s %d %d", *scriptFile, scriptParameter, streamPort);
|
||||||
debug("cIptvProtocolExt::ExecuteScript(child): %s\n", *cmd);
|
debug("cIptvProtocolExt::ExecuteScript(child): %s\n", *cmd);
|
||||||
if (execl("/bin/sh", "sh", "-c", *cmd, (char *)NULL) == -1) {
|
if (execl("/bin/bash", "sh", "-c", *cmd, (char *)NULL) == -1) {
|
||||||
error("Script execution failed: %s", *cmd);
|
error("Script execution failed: %s", *cmd);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
@@ -67,6 +70,8 @@ void cIptvProtocolExt::ExecuteScript(void)
|
|||||||
void cIptvProtocolExt::TerminateScript(void)
|
void cIptvProtocolExt::TerminateScript(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::TerminateScript(): pid=%d\n", pid);
|
debug("cIptvProtocolExt::TerminateScript(): pid=%d\n", pid);
|
||||||
|
if (!isActive || isempty(scriptFile))
|
||||||
|
return;
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
const unsigned int timeoutms = 100;
|
const unsigned int timeoutms = 100;
|
||||||
unsigned int waitms = 0;
|
unsigned int waitms = 0;
|
||||||
@@ -109,7 +114,7 @@ bool cIptvProtocolExt::Open(void)
|
|||||||
if (!strlen(*scriptFile))
|
if (!strlen(*scriptFile))
|
||||||
return false;
|
return false;
|
||||||
// Create the listening socket
|
// Create the listening socket
|
||||||
OpenSocket(socketPort);
|
OpenSocket(streamPort);
|
||||||
// Execute the external script
|
// Execute the external script
|
||||||
ExecuteScript();
|
ExecuteScript();
|
||||||
isActive = true;
|
isActive = true;
|
||||||
@@ -119,11 +124,11 @@ bool cIptvProtocolExt::Open(void)
|
|||||||
bool cIptvProtocolExt::Close(void)
|
bool cIptvProtocolExt::Close(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::Close()\n");
|
debug("cIptvProtocolExt::Close()\n");
|
||||||
// Close the socket
|
|
||||||
CloseSocket();
|
|
||||||
// Terminate the external script
|
// Terminate the external script
|
||||||
TerminateScript();
|
TerminateScript();
|
||||||
isActive = false;
|
isActive = false;
|
||||||
|
// Close the socket
|
||||||
|
CloseSocket();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +150,7 @@ bool cIptvProtocolExt::Set(const char* Location, const int Parameter, const int
|
|||||||
}
|
}
|
||||||
scriptParameter = Parameter;
|
scriptParameter = Parameter;
|
||||||
// Update listen port
|
// Update listen port
|
||||||
socketPort = IptvConfig.GetExtProtocolBasePort() + Index;
|
streamPort = IptvConfig.GetExtProtocolBasePort() + Index;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ private:
|
|||||||
int pid;
|
int pid;
|
||||||
cString scriptFile;
|
cString scriptFile;
|
||||||
int scriptParameter;
|
int scriptParameter;
|
||||||
|
int streamPort;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void TerminateScript(void);
|
void TerminateScript(void);
|
||||||
|
|||||||
106
protocolhttp.c
106
protocolhttp.c
@@ -19,10 +19,11 @@
|
|||||||
#include "protocolhttp.h"
|
#include "protocolhttp.h"
|
||||||
|
|
||||||
cIptvProtocolHttp::cIptvProtocolHttp()
|
cIptvProtocolHttp::cIptvProtocolHttp()
|
||||||
|
: streamAddr(strdup("")),
|
||||||
|
streamPath(strdup("/")),
|
||||||
|
streamPort(0)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolHttp::cIptvProtocolHttp()\n");
|
debug("cIptvProtocolHttp::cIptvProtocolHttp()\n");
|
||||||
streamAddr = strdup("");
|
|
||||||
streamPath = strdup("/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvProtocolHttp::~cIptvProtocolHttp()
|
cIptvProtocolHttp::~cIptvProtocolHttp()
|
||||||
@@ -40,66 +41,29 @@ bool cIptvProtocolHttp::Connect(void)
|
|||||||
debug("cIptvProtocolHttp::Connect()\n");
|
debug("cIptvProtocolHttp::Connect()\n");
|
||||||
// Check that stream address is valid
|
// Check that stream address is valid
|
||||||
if (!isActive && !isempty(streamAddr) && !isempty(streamPath)) {
|
if (!isActive && !isempty(streamAddr) && !isempty(streamPath)) {
|
||||||
// Ensure that socket is valid
|
// Ensure that socket is valid and connect
|
||||||
OpenSocket(socketPort);
|
OpenSocket(streamPort, streamAddr);
|
||||||
|
if (!ConnectSocket()) {
|
||||||
// First try only the IP address
|
|
||||||
sockAddr.sin_addr.s_addr = inet_addr(streamAddr);
|
|
||||||
|
|
||||||
if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
|
|
||||||
debug("Cannot convert %s directly to internet address\n", streamAddr);
|
|
||||||
|
|
||||||
// It may be a host name, get the name
|
|
||||||
struct hostent *host;
|
|
||||||
host = gethostbyname(streamAddr);
|
|
||||||
if (!host) {
|
|
||||||
char tmp[64];
|
|
||||||
error("%s is not valid address: %s", streamAddr, strerror_r(h_errno, tmp, sizeof(tmp)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockAddr.sin_addr.s_addr = inet_addr(*host->h_addr_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
int err = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
|
|
||||||
// Non-blocking sockets always report in-progress error when connected
|
|
||||||
ERROR_IF_FUNC(err < 0 && errno != EINPROGRESS, "connect()", CloseSocket(), return false);
|
|
||||||
// Select with 800ms timeout on the socket completion, check if it is writable
|
|
||||||
int retval = select_single_desc(socketDesc, 800000, true);
|
|
||||||
if (retval < 0)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
// Select has returned. Get socket errors if there are any
|
|
||||||
int socketStatus = 0;
|
|
||||||
socklen_t len = sizeof(socketStatus);
|
|
||||||
getsockopt(socketDesc, SOL_SOCKET, SO_ERROR, &socketStatus, &len);
|
|
||||||
|
|
||||||
// If not any errors, then socket must be ready and connected
|
|
||||||
if (socketStatus != 0) {
|
|
||||||
char tmp[64];
|
|
||||||
error("Cannot connect to %s: %s", streamAddr, strerror_r(socketStatus, tmp, sizeof(tmp)));
|
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formulate and send HTTP request
|
// Formulate and send HTTP request
|
||||||
cString buffer = cString::sprintf("GET %s HTTP/1.1\r\n"
|
cString buffer = cString::sprintf("GET %s HTTP/1.1\r\n"
|
||||||
"Host: %s\r\n"
|
"Host: %s\r\n"
|
||||||
"User-Agent: vdr-iptv\r\n"
|
"User-Agent: vdr-%s/%s\r\n"
|
||||||
"Range: bytes=0-\r\n"
|
"Range: bytes=0-\r\n"
|
||||||
"Connection: Close\r\n"
|
"Connection: Close\r\n"
|
||||||
"\r\n", streamPath, streamAddr);
|
"\r\n", streamPath, streamAddr, PLUGIN_NAME_I18N, VERSION);
|
||||||
|
|
||||||
debug("Sending http request: %s\n", *buffer);
|
debug("Sending http request: %s\n", *buffer);
|
||||||
ssize_t err2 = send(socketDesc, buffer, strlen(buffer), 0);
|
if (!Write(*buffer, (unsigned int)strlen(*buffer))) {
|
||||||
ERROR_IF_FUNC(err2 < 0, "send()", CloseSocket(), return false);
|
CloseSocket();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Now process headers
|
// Now process headers
|
||||||
if (!ProcessHeaders()) {
|
if (!ProcessHeaders()) {
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update active flag
|
// Update active flag
|
||||||
isActive = true;
|
isActive = true;
|
||||||
}
|
}
|
||||||
@@ -109,7 +73,6 @@ bool cIptvProtocolHttp::Connect(void)
|
|||||||
bool cIptvProtocolHttp::Disconnect(void)
|
bool cIptvProtocolHttp::Disconnect(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolHttp::Disconnect()\n");
|
debug("cIptvProtocolHttp::Disconnect()\n");
|
||||||
// Check that stream address is valid
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
// Close the socket
|
// Close the socket
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
@@ -125,24 +88,15 @@ bool cIptvProtocolHttp::GetHeaderLine(char* dest, unsigned int destLen,
|
|||||||
debug("cIptvProtocolHttp::GetHeaderLine()\n");
|
debug("cIptvProtocolHttp::GetHeaderLine()\n");
|
||||||
bool linefeed = false;
|
bool linefeed = false;
|
||||||
bool newline = false;
|
bool newline = false;
|
||||||
char buf[4096];
|
char *bufptr = dest;
|
||||||
char *bufptr = buf;
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
recvLen = 0;
|
recvLen = 0;
|
||||||
|
|
||||||
|
if (!dest)
|
||||||
|
return false;
|
||||||
|
|
||||||
while (!newline || !linefeed) {
|
while (!newline || !linefeed) {
|
||||||
socklen_t addrlen = sizeof(sockAddr);
|
|
||||||
// Wait 500ms for data
|
// Wait 500ms for data
|
||||||
int retval = select_single_desc(socketDesc, 500000, false);
|
if (ReadChar(bufptr, 500)) {
|
||||||
// Check if error
|
|
||||||
if (retval < 0)
|
|
||||||
return false;
|
|
||||||
// Check if data available
|
|
||||||
else if (retval) {
|
|
||||||
ssize_t retval = recvfrom(socketDesc, bufptr, 1, MSG_DONTWAIT,
|
|
||||||
(struct sockaddr *)&sockAddr, &addrlen);
|
|
||||||
if (retval <= 0)
|
|
||||||
return false;
|
|
||||||
// Parsing end conditions, if line ends with \r\n
|
// Parsing end conditions, if line ends with \r\n
|
||||||
if (linefeed && *bufptr == '\n')
|
if (linefeed && *bufptr == '\n')
|
||||||
newline = true;
|
newline = true;
|
||||||
@@ -155,19 +109,18 @@ bool cIptvProtocolHttp::GetHeaderLine(char* dest, unsigned int destLen,
|
|||||||
++recvLen;
|
++recvLen;
|
||||||
}
|
}
|
||||||
++bufptr;
|
++bufptr;
|
||||||
// Check that buffers won't be exceeded
|
// Check that buffer won't be exceeded
|
||||||
if (recvLen >= sizeof(buf) || recvLen >= destLen) {
|
if (recvLen >= destLen) {
|
||||||
error("Header wouldn't fit into buffer\n");
|
error("Header wouldn't fit into buffer\n");
|
||||||
recvLen = 0;
|
recvLen = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
error("No HTTP response received\n");
|
error("No HTTP response received in 500ms\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(dest, buf, recvLen);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,22 +128,27 @@ bool cIptvProtocolHttp::ProcessHeaders(void)
|
|||||||
{
|
{
|
||||||
debug("cIptvProtocolHttp::ProcessHeaders()\n");
|
debug("cIptvProtocolHttp::ProcessHeaders()\n");
|
||||||
unsigned int lineLength = 0;
|
unsigned int lineLength = 0;
|
||||||
int response = 0;
|
int version = 0, response = 0;
|
||||||
bool responseFound = false;
|
bool responseFound = false;
|
||||||
|
char fmt[32];
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
|
// Generate HTTP response format string with 2 arguments
|
||||||
|
snprintf(fmt, sizeof(fmt), "HTTP/1.%%%zui %%%zui ", sizeof(version) - 1, sizeof(response) - 1);
|
||||||
|
|
||||||
while (!responseFound || lineLength != 0) {
|
while (!responseFound || lineLength != 0) {
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
if (!GetHeaderLine(buf, sizeof(buf), lineLength))
|
if (!GetHeaderLine(buf, sizeof(buf), lineLength))
|
||||||
return false;
|
return false;
|
||||||
if (!responseFound && sscanf(buf, "HTTP/1.%*i %i ", &response) != 1) {
|
if (!responseFound && sscanf(buf, fmt, &version, &response) != 2) {
|
||||||
error("Expected HTTP header not found\n");
|
error("Expected HTTP header not found\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
responseFound = true;
|
responseFound = true;
|
||||||
if (response != 200) {
|
// Allow only 'OK' and 'Partial Content'
|
||||||
error("%s\n", buf);
|
if ((response != 200) && (response != 206)) {
|
||||||
|
error("Invalid HTTP response (%d): %s\n", response, buf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,8 +190,8 @@ bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
streamPath = strcpyrealloc(streamPath, "/");
|
streamPath = strcpyrealloc(streamPath, "/");
|
||||||
socketPort = Parameter;
|
streamPort = Parameter;
|
||||||
//debug("http://%s:%d%s\n", streamAddr, socketPort, streamPath);
|
//debug("http://%s:%d%s\n", streamAddr, streamPort, streamPath);
|
||||||
// Re-connect the socket
|
// Re-connect the socket
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
@@ -243,5 +201,5 @@ bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int
|
|||||||
cString cIptvProtocolHttp::GetInformation(void)
|
cString cIptvProtocolHttp::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvProtocolHttp::GetInformation()");
|
//debug("cIptvProtocolHttp::GetInformation()");
|
||||||
return cString::sprintf("http://%s:%d%s", streamAddr, socketPort, streamPath);
|
return cString::sprintf("http://%s:%d%s", streamAddr, streamPort, streamPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class cIptvProtocolHttp : public cIptvTcpSocket, public cIptvProtocolIf {
|
|||||||
private:
|
private:
|
||||||
char* streamAddr;
|
char* streamAddr;
|
||||||
char* streamPath;
|
char* streamPath;
|
||||||
|
int streamPort;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Connect(void);
|
bool Connect(void);
|
||||||
|
|||||||
@@ -19,9 +19,10 @@
|
|||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
cIptvProtocolUdp::cIptvProtocolUdp()
|
cIptvProtocolUdp::cIptvProtocolUdp()
|
||||||
|
: streamAddr(strdup("")),
|
||||||
|
streamPort(0)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::cIptvProtocolUdp()\n");
|
debug("cIptvProtocolUdp::cIptvProtocolUdp()\n");
|
||||||
streamAddr = strdup("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvProtocolUdp::~cIptvProtocolUdp()
|
cIptvProtocolUdp::~cIptvProtocolUdp()
|
||||||
@@ -33,61 +34,30 @@ cIptvProtocolUdp::~cIptvProtocolUdp()
|
|||||||
free(streamAddr);
|
free(streamAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvProtocolUdp::JoinMulticast(void)
|
|
||||||
{
|
|
||||||
debug("cIptvProtocolUdp::JoinMulticast()\n");
|
|
||||||
// Check that stream address is valid
|
|
||||||
if (!isActive && !isempty(streamAddr)) {
|
|
||||||
// Ensure that socket is valid
|
|
||||||
OpenSocket(socketPort);
|
|
||||||
// Join a new multicast group
|
|
||||||
struct ip_mreq mreq;
|
|
||||||
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
|
|
||||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
||||||
int err = setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
|
|
||||||
sizeof(mreq));
|
|
||||||
ERROR_IF_RET(err < 0, "setsockopt()", return false);
|
|
||||||
// Update multicasting flag
|
|
||||||
isActive = true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cIptvProtocolUdp::DropMulticast(void)
|
|
||||||
{
|
|
||||||
debug("cIptvProtocolUdp::DropMulticast()\n");
|
|
||||||
// Check that stream address is valid
|
|
||||||
if (isActive && !isempty(streamAddr)) {
|
|
||||||
// Ensure that socket is valid
|
|
||||||
OpenSocket(socketPort);
|
|
||||||
// Drop the multicast group
|
|
||||||
struct ip_mreq mreq;
|
|
||||||
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
|
|
||||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
||||||
int err = setsockopt(socketDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
|
|
||||||
sizeof(mreq));
|
|
||||||
ERROR_IF_RET(err < 0, "setsockopt()", return false);
|
|
||||||
// Update multicasting flag
|
|
||||||
isActive = false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cIptvProtocolUdp::Open(void)
|
bool cIptvProtocolUdp::Open(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::Open()\n");
|
debug("cIptvProtocolUdp::Open(): streamAddr=%s\n", streamAddr);
|
||||||
// Join a new multicast group
|
OpenSocket(streamPort, inet_addr(streamAddr));
|
||||||
JoinMulticast();
|
if (!isempty(streamAddr)) {
|
||||||
|
// Join a new multicast group
|
||||||
|
JoinMulticast();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvProtocolUdp::Close(void)
|
bool cIptvProtocolUdp::Close(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::Close()\n");
|
debug("cIptvProtocolUdp::Close(): streamAddr=%s\n", streamAddr);
|
||||||
// Drop the multicast group
|
if (!isempty(streamAddr)) {
|
||||||
DropMulticast();
|
// Drop the multicast group
|
||||||
|
OpenSocket(streamPort, inet_addr(streamAddr));
|
||||||
|
DropMulticast();
|
||||||
|
}
|
||||||
// Close the socket
|
// Close the socket
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
|
// Do NOT reset stream and source addresses
|
||||||
|
//streamAddr = strcpyrealloc(streamAddr, "");
|
||||||
|
//streamPort = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,19 +70,25 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int
|
|||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index);
|
debug("cIptvProtocolUdp::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index);
|
||||||
if (!isempty(Location)) {
|
if (!isempty(Location)) {
|
||||||
// Drop the multicast group
|
// Drop the multicast group
|
||||||
DropMulticast();
|
if (!isempty(streamAddr)) {
|
||||||
// Update stream address and port
|
OpenSocket(streamPort, inet_addr(streamAddr));
|
||||||
streamAddr = strcpyrealloc(streamAddr, Location);
|
DropMulticast();
|
||||||
socketPort = Parameter;
|
}
|
||||||
// Join a new multicast group
|
// Update stream address and port
|
||||||
JoinMulticast();
|
streamAddr = strcpyrealloc(streamAddr, Location);
|
||||||
}
|
streamPort = Parameter;
|
||||||
|
// Join a new multicast group
|
||||||
|
if (!isempty(streamAddr)) {
|
||||||
|
OpenSocket(streamPort, inet_addr(streamAddr));
|
||||||
|
JoinMulticast();
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cIptvProtocolUdp::GetInformation(void)
|
cString cIptvProtocolUdp::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvProtocolUdp::GetInformation()");
|
//debug("cIptvProtocolUdp::GetInformation()");
|
||||||
return cString::sprintf("udp://%s:%d", streamAddr, socketPort);
|
return cString::sprintf("udp://%s:%d", streamAddr, streamPort);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf {
|
class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf {
|
||||||
private:
|
private:
|
||||||
char* streamAddr;
|
char* streamAddr;
|
||||||
|
int streamPort;
|
||||||
private:
|
|
||||||
bool JoinMulticast(void);
|
|
||||||
bool DropMulticast(void);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvProtocolUdp();
|
cIptvProtocolUdp();
|
||||||
|
|||||||
@@ -91,10 +91,10 @@ void cIptvSectionFilter::New(void)
|
|||||||
|
|
||||||
int cIptvSectionFilter::Filter(void)
|
int cIptvSectionFilter::Filter(void)
|
||||||
{
|
{
|
||||||
uint8_t neq = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (secbuf) {
|
if (secbuf) {
|
||||||
|
int i;
|
||||||
|
uint8_t neq = 0;
|
||||||
|
|
||||||
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i) {
|
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i) {
|
||||||
uint8_t local_xor = (uint8_t)(filter_value[i] ^ secbuf[i]);
|
uint8_t local_xor = (uint8_t)(filter_value[i] ^ secbuf[i]);
|
||||||
if (maskandmode[i] & local_xor)
|
if (maskandmode[i] & local_xor)
|
||||||
@@ -138,7 +138,7 @@ int cIptvSectionFilter::CopyDump(const uint8_t *buf, uint8_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memcpy(secbuf_base + tsfeedp, buf, len);
|
memcpy(secbuf_base + tsfeedp, buf, len);
|
||||||
tsfeedp += len;
|
tsfeedp = uint16_t(tsfeedp + len);
|
||||||
|
|
||||||
limit = tsfeedp;
|
limit = tsfeedp;
|
||||||
if (limit > DMX_MAX_SECFEED_SIZE)
|
if (limit > DMX_MAX_SECFEED_SIZE)
|
||||||
@@ -154,7 +154,7 @@ int cIptvSectionFilter::CopyDump(const uint8_t *buf, uint8_t len)
|
|||||||
seclen = seclen_local;
|
seclen = seclen_local;
|
||||||
if (pusi_seen)
|
if (pusi_seen)
|
||||||
Feed();
|
Feed();
|
||||||
secbufp += seclen_local;
|
secbufp = uint16_t(secbufp + seclen_local);
|
||||||
secbuf += seclen_local;
|
secbuf += seclen_local;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
2
setup.c
2
setup.c
@@ -66,7 +66,7 @@ void cIptvMenuInfo::Display(void)
|
|||||||
|
|
||||||
eOSState cIptvMenuInfo::ProcessKey(eKeys Key)
|
eOSState cIptvMenuInfo::ProcessKey(eKeys Key)
|
||||||
{
|
{
|
||||||
switch (Key) {
|
switch (int(Key)) {
|
||||||
case kUp|k_Repeat:
|
case kUp|k_Repeat:
|
||||||
case kUp:
|
case kUp:
|
||||||
case kDown|k_Repeat:
|
case kDown|k_Repeat:
|
||||||
|
|||||||
98
sidscanner.c
98
sidscanner.c
@@ -11,10 +11,19 @@
|
|||||||
#include "sidscanner.h"
|
#include "sidscanner.h"
|
||||||
|
|
||||||
cSidScanner::cSidScanner(void)
|
cSidScanner::cSidScanner(void)
|
||||||
|
: channelId(tChannelID::InvalidID),
|
||||||
|
sidFound(false),
|
||||||
|
nidFound(false),
|
||||||
|
tidFound(false)
|
||||||
{
|
{
|
||||||
debug("cSidScanner::cSidScanner()\n");
|
debug("cSidScanner::cSidScanner()\n");
|
||||||
channel = cChannel();
|
|
||||||
Set(0x00, 0x00); // PAT
|
Set(0x00, 0x00); // PAT
|
||||||
|
Set(0x10, 0x40); // NIT
|
||||||
|
}
|
||||||
|
|
||||||
|
cSidScanner::~cSidScanner()
|
||||||
|
{
|
||||||
|
debug("cSidScanner::~cSidScanner()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSidScanner::SetStatus(bool On)
|
void cSidScanner::SetStatus(bool On)
|
||||||
@@ -23,43 +32,70 @@ void cSidScanner::SetStatus(bool On)
|
|||||||
cFilter::SetStatus(On);
|
cFilter::SetStatus(On);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSidScanner::SetChannel(const cChannel *Channel)
|
void cSidScanner::SetChannel(const tChannelID &ChannelId)
|
||||||
{
|
{
|
||||||
if (Channel) {
|
debug("cSidScanner::SetChannel(): %s\n", *ChannelId.ToString());
|
||||||
debug("cSidScanner::SetChannel(): %s\n", Channel->Parameters());
|
channelId = ChannelId;
|
||||||
channel = *Channel;
|
sidFound = false;
|
||||||
}
|
nidFound = false;
|
||||||
else {
|
tidFound = false;
|
||||||
debug("cSidScanner::SetChannel()\n");
|
|
||||||
channel = cChannel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSidScanner::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
void cSidScanner::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
||||||
{
|
{
|
||||||
|
int newSid = -1, newNid = -1, newTid = -1;
|
||||||
|
|
||||||
//debug("cSidScanner::Process()\n");
|
//debug("cSidScanner::Process()\n");
|
||||||
if ((Pid == 0x00) && (Tid == 0x00) && channel.GetChannelID().Valid()) {
|
if (channelId.Valid()) {
|
||||||
debug("cSidScanner::Process(): Pid=%d Tid=%02X\n", Pid, Tid);
|
if ((Pid == 0x00) && (Tid == 0x00)) {
|
||||||
SI::PAT pat(Data, false);
|
debug("cSidScanner::Process(): Pid=%d Tid=%02X\n", Pid, Tid);
|
||||||
if (!pat.CheckCRCAndParse())
|
SI::PAT pat(Data, false);
|
||||||
return;
|
if (!pat.CheckCRCAndParse())
|
||||||
SI::PAT::Association assoc;
|
return;
|
||||||
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
|
SI::PAT::Association assoc;
|
||||||
if (!assoc.isNITPid()) {
|
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
|
||||||
if (assoc.getServiceId() != channel.Sid()) {
|
if (!assoc.isNITPid()) {
|
||||||
debug("cSidScanner::Process(): Sid=%d\n", assoc.getServiceId());
|
if (assoc.getServiceId() != channelId.Sid()) {
|
||||||
if (!Channels.Lock(true, 10))
|
debug("cSidScanner::Process(): Sid=%d\n", assoc.getServiceId());
|
||||||
return;
|
newSid = assoc.getServiceId();
|
||||||
cChannel *IptvChannel = Channels.GetByChannelID(channel.GetChannelID());
|
}
|
||||||
if (IptvChannel)
|
sidFound = true;
|
||||||
IptvChannel->SetId(IptvChannel->Nid(), IptvChannel->Tid(),
|
break;
|
||||||
assoc.getServiceId(), IptvChannel->Rid());
|
|
||||||
Channels.Unlock();
|
|
||||||
}
|
}
|
||||||
SetChannel(NULL);
|
|
||||||
SetStatus(false);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((Pid == 0x10) && (Tid == 0x40)) {
|
||||||
|
debug("cSidScanner::Process(): Pid=%d Tid=%02X\n", Pid, Tid);
|
||||||
|
SI::NIT nit(Data, false);
|
||||||
|
if (!nit.CheckCRCAndParse())
|
||||||
|
return;
|
||||||
|
SI::NIT::TransportStream ts;
|
||||||
|
for (SI::Loop::Iterator it; nit.transportStreamLoop.getNext(ts, it); ) {
|
||||||
|
if (ts.getTransportStreamId() != channelId.Tid()) {
|
||||||
|
debug("cSidScanner::Process(): TSid=%d\n", ts.getTransportStreamId());
|
||||||
|
newTid = ts.getTransportStreamId();
|
||||||
|
}
|
||||||
|
tidFound = true;
|
||||||
|
break; // default to the first one
|
||||||
|
}
|
||||||
|
if (nit.getNetworkId() != channelId.Nid()) {
|
||||||
|
debug("cSidScanner::Process(): Nid=%d\n", ts.getTransportStreamId());
|
||||||
|
newNid = nit.getNetworkId();
|
||||||
|
}
|
||||||
|
nidFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((newSid >= 0) || (newNid >= 0) || (newTid >= 0)) {
|
||||||
|
if (!Channels.Lock(true, 10))
|
||||||
|
return;
|
||||||
|
cChannel *IptvChannel = Channels.GetByChannelID(channelId);
|
||||||
|
if (IptvChannel)
|
||||||
|
IptvChannel->SetId((newNid < 0) ? IptvChannel->Nid() : newNid, (newTid < 0) ? IptvChannel->Tid() : newTid,
|
||||||
|
(newSid < 0) ? IptvChannel->Sid() : newSid, IptvChannel->Rid());
|
||||||
|
Channels.Unlock();
|
||||||
|
}
|
||||||
|
if (sidFound && nidFound && tidFound) {
|
||||||
|
SetChannel(tChannelID::InvalidID);
|
||||||
|
SetStatus(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,10 @@
|
|||||||
|
|
||||||
class cSidScanner : public cFilter {
|
class cSidScanner : public cFilter {
|
||||||
private:
|
private:
|
||||||
cChannel channel;
|
tChannelID channelId;
|
||||||
|
bool sidFound;
|
||||||
|
bool nidFound;
|
||||||
|
bool tidFound;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
||||||
@@ -21,7 +24,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
cSidScanner(void);
|
cSidScanner(void);
|
||||||
void SetChannel(const cChannel *Channel);
|
~cSidScanner();
|
||||||
|
void SetChannel(const tChannelID &ChannelId);
|
||||||
void Open() { SetStatus(true); }
|
void Open() { SetStatus(true); }
|
||||||
void Close() { SetStatus(false); }
|
void Close() { SetStatus(false); }
|
||||||
};
|
};
|
||||||
|
|||||||
260
socket.c
260
socket.c
@@ -23,6 +23,7 @@ cIptvSocket::cIptvSocket()
|
|||||||
isActive(false)
|
isActive(false)
|
||||||
{
|
{
|
||||||
debug("cIptvSocket::cIptvSocket()\n");
|
debug("cIptvSocket::cIptvSocket()\n");
|
||||||
|
memset(&sockAddr, '\0', sizeof(sockAddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvSocket::~cIptvSocket()
|
cIptvSocket::~cIptvSocket()
|
||||||
@@ -51,10 +52,13 @@ bool cIptvSocket::OpenSocket(const int Port, const bool isUdp)
|
|||||||
socketDesc = socket(PF_INET, SOCK_STREAM, 0);
|
socketDesc = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
|
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
|
||||||
// Make it use non-blocking I/O to avoid stuck read calls
|
// Make it use non-blocking I/O to avoid stuck read calls
|
||||||
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl()",
|
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)",
|
||||||
CloseSocket(), return false);
|
CloseSocket(), return false);
|
||||||
// Allow multiple sockets to use the same PORT number
|
// Allow multiple sockets to use the same PORT number
|
||||||
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0, "setsockopt()",
|
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0, "setsockopt(SO_REUSEADDR)",
|
||||||
|
CloseSocket(), return false);
|
||||||
|
// Allow packet information to be fetched
|
||||||
|
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0, "setsockopt(IP_PKTINFO)",
|
||||||
CloseSocket(), return false);
|
CloseSocket(), return false);
|
||||||
// Bind socket
|
// Bind socket
|
||||||
memset(&sockAddr, '\0', sizeof(sockAddr));
|
memset(&sockAddr, '\0', sizeof(sockAddr));
|
||||||
@@ -78,11 +82,14 @@ void cIptvSocket::CloseSocket(void)
|
|||||||
if (socketDesc >= 0) {
|
if (socketDesc >= 0) {
|
||||||
close(socketDesc);
|
close(socketDesc);
|
||||||
socketDesc = -1;
|
socketDesc = -1;
|
||||||
|
socketPort = 0;
|
||||||
|
memset(&sockAddr, 0, sizeof(sockAddr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UDP socket class
|
// UDP socket class
|
||||||
cIptvUdpSocket::cIptvUdpSocket()
|
cIptvUdpSocket::cIptvUdpSocket()
|
||||||
|
: streamAddr(INADDR_ANY)
|
||||||
{
|
{
|
||||||
debug("cIptvUdpSocket::cIptvUdpSocket()\n");
|
debug("cIptvUdpSocket::cIptvUdpSocket()\n");
|
||||||
}
|
}
|
||||||
@@ -92,12 +99,53 @@ cIptvUdpSocket::~cIptvUdpSocket()
|
|||||||
debug("cIptvUdpSocket::~cIptvUdpSocket()\n");
|
debug("cIptvUdpSocket::~cIptvUdpSocket()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvUdpSocket::OpenSocket(const int Port)
|
bool cIptvUdpSocket::OpenSocket(const int Port, const in_addr_t StreamAddr)
|
||||||
{
|
{
|
||||||
debug("cIptvUdpSocket::OpenSocket()\n");
|
debug("cIptvUdpSocket::OpenSocket()\n");
|
||||||
|
streamAddr = StreamAddr;
|
||||||
return cIptvSocket::OpenSocket(Port, true);
|
return cIptvSocket::OpenSocket(Port, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cIptvUdpSocket::CloseSocket(void)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::CloseSocket()\n");
|
||||||
|
streamAddr = INADDR_ANY;
|
||||||
|
cIptvSocket::CloseSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvUdpSocket::JoinMulticast(void)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::JoinMulticast()\n");
|
||||||
|
// Check if socket exists
|
||||||
|
if (!isActive && (socketDesc >= 0)) {
|
||||||
|
// Join a new multicast group
|
||||||
|
struct ip_mreq mreq;
|
||||||
|
mreq.imr_multiaddr.s_addr = streamAddr;
|
||||||
|
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||||
|
ERROR_IF_RET(setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false);
|
||||||
|
// Update multicasting flag
|
||||||
|
isActive = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvUdpSocket::DropMulticast(void)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::DropMulticast()\n");
|
||||||
|
// Check if socket exists
|
||||||
|
if (isActive && (socketDesc >= 0)) {
|
||||||
|
// Drop the existing multicast group
|
||||||
|
struct ip_mreq mreq;
|
||||||
|
mreq.imr_multiaddr.s_addr = streamAddr;
|
||||||
|
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||||
|
ERROR_IF_RET(setsockopt(socketDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false);
|
||||||
|
// Update multicasting flag
|
||||||
|
isActive = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
||||||
{
|
{
|
||||||
//debug("cIptvUdpSocket::Read()\n");
|
//debug("cIptvUdpSocket::Read()\n");
|
||||||
@@ -106,43 +154,74 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
|||||||
error("Invalid socket in %s\n", __FUNCTION__);
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
socklen_t addrlen = sizeof(sockAddr);
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
// Read data from socket
|
// Read data from socket in a loop
|
||||||
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
do {
|
||||||
len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
|
socklen_t addrlen = sizeof(sockAddr);
|
||||||
(struct sockaddr *)&sockAddr, &addrlen);
|
struct msghdr msgh;
|
||||||
if ((len > 0) && (BufferAddr[0] == TS_SYNC_BYTE)) {
|
struct cmsghdr *cmsg;
|
||||||
return len;
|
struct iovec iov;
|
||||||
}
|
char cbuf[256];
|
||||||
else if (len > 3) {
|
len = 0;
|
||||||
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
|
// Initialize iov and msgh structures
|
||||||
// version
|
memset(&msgh, 0, sizeof(struct msghdr));
|
||||||
unsigned int v = (BufferAddr[0] >> 6) & 0x03;
|
iov.iov_base = BufferAddr;
|
||||||
// extension bit
|
iov.iov_len = BufferLen;
|
||||||
unsigned int x = (BufferAddr[0] >> 4) & 0x01;
|
msgh.msg_control = cbuf;
|
||||||
// cscr count
|
msgh.msg_controllen = sizeof(cbuf);
|
||||||
unsigned int cc = BufferAddr[0] & 0x0F;
|
msgh.msg_name = &sockAddr;
|
||||||
// payload type: MPEG2 TS = 33
|
msgh.msg_namelen = addrlen;
|
||||||
//unsigned int pt = readBuffer[1] & 0x7F;
|
msgh.msg_iov = &iov;
|
||||||
// header lenght
|
msgh.msg_iovlen = 1;
|
||||||
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
msgh.msg_flags = 0;
|
||||||
// check if extension
|
|
||||||
if (x) {
|
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
||||||
// extension header length
|
len = (int)recvmsg(socketDesc, &msgh, MSG_DONTWAIT);
|
||||||
unsigned int ehl = (((BufferAddr[headerlen + 2] & 0xFF) << 8) |
|
else
|
||||||
(BufferAddr[headerlen + 3] & 0xFF));
|
break;
|
||||||
// update header length
|
if (len > 0) {
|
||||||
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
// Process auxiliary received data and validate source address
|
||||||
}
|
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
|
||||||
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
|
||||||
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
|
struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||||
(BufferAddr[headerlen] == TS_SYNC_BYTE)) {
|
if ((i->ipi_addr.s_addr == streamAddr) || (INADDR_ANY == streamAddr)) {
|
||||||
// Set argument point to payload in read buffer
|
if (BufferAddr[0] == TS_SYNC_BYTE)
|
||||||
memmove(BufferAddr, &BufferAddr[headerlen], (len - headerlen));
|
return len;
|
||||||
return (len - headerlen);
|
else if (len > 3) {
|
||||||
}
|
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
|
||||||
}
|
// version
|
||||||
|
unsigned int v = (BufferAddr[0] >> 6) & 0x03;
|
||||||
|
// extension bit
|
||||||
|
unsigned int x = (BufferAddr[0] >> 4) & 0x01;
|
||||||
|
// cscr count
|
||||||
|
unsigned int cc = BufferAddr[0] & 0x0F;
|
||||||
|
// payload type: MPEG2 TS = 33
|
||||||
|
//unsigned int pt = readBuffer[1] & 0x7F;
|
||||||
|
// header lenght
|
||||||
|
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
||||||
|
// check if extension
|
||||||
|
if (x) {
|
||||||
|
// extension header length
|
||||||
|
unsigned int ehl = (((BufferAddr[headerlen + 2] & 0xFF) << 8) |
|
||||||
|
(BufferAddr[headerlen + 3] & 0xFF));
|
||||||
|
// update header length
|
||||||
|
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
||||||
|
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
|
||||||
|
(BufferAddr[headerlen] == TS_SYNC_BYTE)) {
|
||||||
|
// Set argument point to payload in read buffer
|
||||||
|
memmove(BufferAddr, &BufferAddr[headerlen], (len - headerlen));
|
||||||
|
return (len - headerlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (len > 0);
|
||||||
|
ERROR_IF_RET(len < 0 && errno != EAGAIN, "recvmsg()", return -1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,10 +236,64 @@ cIptvTcpSocket::~cIptvTcpSocket()
|
|||||||
debug("cIptvTcpSocket::~cIptvTcpSocket()\n");
|
debug("cIptvTcpSocket::~cIptvTcpSocket()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvTcpSocket::OpenSocket(const int Port)
|
bool cIptvTcpSocket::OpenSocket(const int Port, const char *StreamAddr)
|
||||||
{
|
{
|
||||||
debug("cIptvTcpSocket::OpenSocket()\n");
|
debug("cIptvTcpSocket::OpenSocket()\n");
|
||||||
return cIptvSocket::OpenSocket(Port, false);
|
|
||||||
|
// Socket must be opened before setting the host address
|
||||||
|
bool retval = cIptvSocket::OpenSocket(Port, false);
|
||||||
|
|
||||||
|
// First try only the IP address
|
||||||
|
sockAddr.sin_addr.s_addr = inet_addr(StreamAddr);
|
||||||
|
|
||||||
|
if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
|
||||||
|
debug("Cannot convert %s directly to internet address\n", StreamAddr);
|
||||||
|
|
||||||
|
// It may be a host name, get the name
|
||||||
|
struct hostent *host;
|
||||||
|
host = gethostbyname(StreamAddr);
|
||||||
|
if (!host) {
|
||||||
|
char tmp[64];
|
||||||
|
error("gethostbyname() failed: %s is not valid address: %s", StreamAddr, strerror_r(h_errno, tmp, sizeof(tmp)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockAddr.sin_addr.s_addr = inet_addr(*host->h_addr_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cIptvTcpSocket::CloseSocket(void)
|
||||||
|
{
|
||||||
|
debug("cIptvTcpSocket::CloseSocket()\n");
|
||||||
|
cIptvSocket::CloseSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvTcpSocket::ConnectSocket(void)
|
||||||
|
{
|
||||||
|
debug("cIptvTcpSocket::ConnectSocket()\n");
|
||||||
|
if (!isActive && (socketDesc >= 0)) {
|
||||||
|
int retval = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
|
||||||
|
// Non-blocking sockets always report in-progress error when connected
|
||||||
|
ERROR_IF_RET(retval < 0 && errno != EINPROGRESS, "connect()", return false);
|
||||||
|
// Select with 800ms timeout on the socket completion, check if it is writable
|
||||||
|
retval = select_single_desc(socketDesc, 800000, true);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
// Select has returned. Get socket errors if there are any
|
||||||
|
retval = 0;
|
||||||
|
socklen_t len = sizeof(retval);
|
||||||
|
getsockopt(socketDesc, SOL_SOCKET, SO_ERROR, &retval, &len);
|
||||||
|
// If not any errors, then socket must be ready and connected
|
||||||
|
if (retval != 0) {
|
||||||
|
char tmp[64];
|
||||||
|
error("Connect() failed: %s", strerror_r(retval, tmp, sizeof(tmp)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
||||||
@@ -171,10 +304,49 @@ int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
|||||||
error("Invalid socket in %s\n", __FUNCTION__);
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
int len = 0;
|
||||||
socklen_t addrlen = sizeof(sockAddr);
|
socklen_t addrlen = sizeof(sockAddr);
|
||||||
// Read data from socket
|
// Read data from socket
|
||||||
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
||||||
return (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
|
len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
|
||||||
(struct sockaddr *)&sockAddr, &addrlen);
|
(struct sockaddr *)&sockAddr, &addrlen);
|
||||||
return 0;
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvTcpSocket::ReadChar(char* BufferAddr, unsigned int TimeoutMs)
|
||||||
|
{
|
||||||
|
//debug("cIptvTcpSocket::ReadChar()\n");
|
||||||
|
// Error out if socket not initialized
|
||||||
|
if (socketDesc <= 0) {
|
||||||
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
socklen_t addrlen = sizeof(sockAddr);
|
||||||
|
// Wait 500ms for data
|
||||||
|
int retval = select_single_desc(socketDesc, 1000 * TimeoutMs, false);
|
||||||
|
// Check if error
|
||||||
|
if (retval < 0)
|
||||||
|
return false;
|
||||||
|
// Check if data available
|
||||||
|
else if (retval) {
|
||||||
|
retval = (int)recvfrom(socketDesc, BufferAddr, 1, MSG_DONTWAIT,
|
||||||
|
(struct sockaddr *)&sockAddr, &addrlen);
|
||||||
|
if (retval <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvTcpSocket::Write(const char* BufferAddr, unsigned int BufferLen)
|
||||||
|
{
|
||||||
|
//debug("cIptvTcpSocket::Write()\n");
|
||||||
|
// Error out if socket not initialized
|
||||||
|
if (socketDesc <= 0) {
|
||||||
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ERROR_IF_RET(send(socketDesc, BufferAddr, BufferLen, 0) < 0, "send()", return false);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
18
socket.h
18
socket.h
@@ -11,8 +11,10 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
class cIptvSocket {
|
class cIptvSocket {
|
||||||
protected:
|
private:
|
||||||
int socketPort;
|
int socketPort;
|
||||||
|
|
||||||
|
protected:
|
||||||
int socketDesc;
|
int socketDesc;
|
||||||
struct sockaddr_in sockAddr;
|
struct sockaddr_in sockAddr;
|
||||||
bool isActive;
|
bool isActive;
|
||||||
@@ -27,11 +29,17 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class cIptvUdpSocket : public cIptvSocket {
|
class cIptvUdpSocket : public cIptvSocket {
|
||||||
|
private:
|
||||||
|
in_addr_t streamAddr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvUdpSocket();
|
cIptvUdpSocket();
|
||||||
virtual ~cIptvUdpSocket();
|
virtual ~cIptvUdpSocket();
|
||||||
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
||||||
bool OpenSocket(const int Port);
|
bool OpenSocket(const int Port, const in_addr_t StreamAddr = INADDR_ANY);
|
||||||
|
void CloseSocket(void);
|
||||||
|
bool JoinMulticast(void);
|
||||||
|
bool DropMulticast(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cIptvTcpSocket : public cIptvSocket {
|
class cIptvTcpSocket : public cIptvSocket {
|
||||||
@@ -39,7 +47,11 @@ public:
|
|||||||
cIptvTcpSocket();
|
cIptvTcpSocket();
|
||||||
virtual ~cIptvTcpSocket();
|
virtual ~cIptvTcpSocket();
|
||||||
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
||||||
bool OpenSocket(const int Port);
|
bool OpenSocket(const int Port, const char *StreamAddr);
|
||||||
|
void CloseSocket(void);
|
||||||
|
bool ConnectSocket(void);
|
||||||
|
bool ReadChar(char* BufferAddr, unsigned int TimeoutMs);
|
||||||
|
bool Write(const char* BufferAddr, unsigned int BufferLen);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __IPTV_SOCKET_H
|
#endif // __IPTV_SOCKET_H
|
||||||
|
|||||||
136
source.c
136
source.c
@@ -49,63 +49,75 @@ cString cIptvTransponderParameters::ToString(char Type) const
|
|||||||
bool cIptvTransponderParameters::Parse(const char *s)
|
bool cIptvTransponderParameters::Parse(const char *s)
|
||||||
{
|
{
|
||||||
debug("cIptvTransponderParameters::Parse(): s=%s\n", s);
|
debug("cIptvTransponderParameters::Parse(): s=%s\n", s);
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
const char *delim = "|";
|
if (s && *s) {
|
||||||
char *str = (char *)s;
|
const char *delim = "|";
|
||||||
char *saveptr = NULL;
|
char *str = strdup(s);
|
||||||
char *token = NULL;
|
char *saveptr = NULL;
|
||||||
bool found_s = false;
|
char *token = NULL;
|
||||||
bool found_p = false;
|
bool found_s = false;
|
||||||
bool found_f = true;
|
bool found_p = false;
|
||||||
bool found_u = false;
|
bool found_f = false;
|
||||||
bool found_a = false;
|
bool found_u = false;
|
||||||
|
bool found_a = false;
|
||||||
|
|
||||||
while ((token = (char *)strtok_r(str, delim, &saveptr)) != NULL) {
|
while ((token = strtok_r(str, delim, &saveptr)) != NULL) {
|
||||||
char *data = token + 1;
|
char *data = token;
|
||||||
|
|
||||||
if (data && (*data == '=')) {
|
|
||||||
++data;
|
++data;
|
||||||
switch (*token) {
|
if (data && (*data == '=')) {
|
||||||
case 'S':
|
++data;
|
||||||
sidscan = (int)strtol(data, (char **)NULL, 10);
|
switch (*token) {
|
||||||
found_s = true;
|
case 'S':
|
||||||
break;
|
sidscan = (int)strtol(data, (char **)NULL, 10);
|
||||||
case 'P':
|
found_s = true;
|
||||||
pidscan = (int)strtol(data, (char **)NULL, 10);
|
break;
|
||||||
found_p = true;
|
case 'P':
|
||||||
break;
|
pidscan = (int)strtol(data, (char **)NULL, 10);
|
||||||
case 'F':
|
found_p = true;
|
||||||
if (strstr(data, "UDP"))
|
break;
|
||||||
protocol = eProtocolUDP;
|
case 'F':
|
||||||
else if (strstr(data, "HTTP"))
|
if (strstr(data, "UDP")) {
|
||||||
protocol = eProtocolHTTP;
|
protocol = eProtocolUDP;
|
||||||
else if (strstr(data, "FILE"))
|
found_f = true;
|
||||||
protocol = eProtocolFILE;
|
}
|
||||||
else if (strstr(data, "EXT"))
|
else if (strstr(data, "HTTP")) {
|
||||||
protocol = eProtocolEXT;
|
protocol = eProtocolHTTP;
|
||||||
else
|
found_f = true;
|
||||||
found_u = false;
|
}
|
||||||
break;
|
else if (strstr(data, "FILE")) {
|
||||||
case 'U':
|
protocol = eProtocolFILE;
|
||||||
strn0cpy(address, data, sizeof(address));
|
found_f = true;
|
||||||
found_u = true;
|
}
|
||||||
break;
|
else if (strstr(data, "EXT")) {
|
||||||
case 'A':
|
protocol = eProtocolEXT;
|
||||||
parameter = (int)strtol(data, (char **)NULL, 10);
|
found_f = true;
|
||||||
found_a = true;
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
case 'U':
|
||||||
break;
|
strn0cpy(address, data, sizeof(address));
|
||||||
}
|
found_u = true;
|
||||||
}
|
break;
|
||||||
str = NULL;
|
case 'A':
|
||||||
}
|
parameter = (int)strtol(data, (char **)NULL, 10);
|
||||||
|
found_a = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (found_s && found_p && found_f && found_u && found_a)
|
if (found_s && found_p && found_f && found_u && found_a)
|
||||||
return (true);
|
result = true;
|
||||||
|
else
|
||||||
|
error("Invalid channel parameters: %s\n", str);
|
||||||
|
|
||||||
error("Invalid channel parameters: %s\n", s);
|
free(str);
|
||||||
return (false);
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cIptvSourceParam ------------------------------------------------------
|
// --- cIptvSourceParam ------------------------------------------------------
|
||||||
@@ -115,7 +127,9 @@ cIptvSourceParam::cIptvSourceParam(char Source, const char *Description)
|
|||||||
param(0),
|
param(0),
|
||||||
nid(0),
|
nid(0),
|
||||||
tid(0),
|
tid(0),
|
||||||
rid(0)
|
rid(0),
|
||||||
|
data(),
|
||||||
|
itp()
|
||||||
{
|
{
|
||||||
debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description);
|
debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description);
|
||||||
|
|
||||||
@@ -148,14 +162,14 @@ cOsdItem *cIptvSourceParam::GetOsdItem(void)
|
|||||||
{
|
{
|
||||||
debug("cIptvSourceParam::GetOsdItem()\n");
|
debug("cIptvSourceParam::GetOsdItem()\n");
|
||||||
switch (param++) {
|
switch (param++) {
|
||||||
case 0: return new cMenuEditIntItem( tr("Nid"), &nid, 0);
|
case 0: return new cMenuEditIntItem( tr("Nid"), &nid, 0);
|
||||||
case 1: return new cMenuEditIntItem( tr("Tid"), &tid, 0);
|
case 1: return new cMenuEditIntItem( tr("Tid"), &tid, 0);
|
||||||
case 2: return new cMenuEditIntItem( tr("Rid"), &rid, 0);
|
case 2: return new cMenuEditIntItem( tr("Rid"), &rid, 0);
|
||||||
case 3: return new cMenuEditBoolItem(tr("Scan sid"), &itp.sidscan);
|
case 3: return new cMenuEditBoolItem(tr("Scan section ids"), &itp.sidscan);
|
||||||
case 4: return new cMenuEditBoolItem(tr("Scan pids"), &itp.pidscan);
|
case 4: return new cMenuEditBoolItem(tr("Scan pids"), &itp.pidscan);
|
||||||
case 5: return new cMenuEditStraItem(tr("Protocol"), &itp.protocol, ELEMENTS(protocols), protocols);
|
case 5: return new cMenuEditStraItem(tr("Protocol"), &itp.protocol, ELEMENTS(protocols), protocols);
|
||||||
case 6: return new cMenuEditStrItem( tr("Address"), itp.address, sizeof(itp.address));
|
case 6: return new cMenuEditStrItem( tr("Address"), itp.address, sizeof(itp.address));
|
||||||
case 7: return new cMenuEditIntItem( tr("Parameter"), &itp.parameter, 0, 0xFFFF);
|
case 7: return new cMenuEditIntItem( tr("Parameter"), &itp.parameter, 0, 0xFFFF);
|
||||||
default: return NULL;
|
default: return NULL;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ cString cIptvStreamerStatistics::GetStreamerStatistic()
|
|||||||
long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L;
|
long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L;
|
||||||
if (!IptvConfig.GetUseBytes())
|
if (!IptvConfig.GetUseBytes())
|
||||||
bitrate *= 8;
|
bitrate *= 8;
|
||||||
cString info = cString::sprintf("Stream bitrate: %ld k%s/s\n", bitrate, IptvConfig.GetUseBytes() ? "B" : "bit");
|
cString info = cString::sprintf("%ld k%s/s", bitrate, IptvConfig.GetUseBytes() ? "B" : "bit");
|
||||||
dataBytes = 0;
|
dataBytes = 0;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@@ -164,6 +164,7 @@ void cIptvStreamerStatistics::AddStreamerStatistic(long Bytes)
|
|||||||
// Buffer statistic class
|
// Buffer statistic class
|
||||||
cIptvBufferStatistics::cIptvBufferStatistics()
|
cIptvBufferStatistics::cIptvBufferStatistics()
|
||||||
: dataBytes(0),
|
: dataBytes(0),
|
||||||
|
freeSpace(0),
|
||||||
usedSpace(0),
|
usedSpace(0),
|
||||||
timer(),
|
timer(),
|
||||||
mutex()
|
mutex()
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ bool cIptvStreamer::Set(const char* Location, const int Parameter, const int Ind
|
|||||||
cString cIptvStreamer::GetInformation(void)
|
cString cIptvStreamer::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvStreamer::GetInformation()");
|
//debug("cIptvStreamer::GetInformation()");
|
||||||
cString info("Stream:");
|
cString info;
|
||||||
if (protocol)
|
if (protocol)
|
||||||
info = cString::sprintf("%s %s", *info, *protocol->GetInformation());
|
info = protocol->GetInformation();
|
||||||
return cString::sprintf("%s\n", *info);
|
return info;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user