summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorFrank Schmirler <vdr@schmirler.de>2010-12-02 09:48:23 +0100
committerFrank Schmirler <vdr@schmirler.de>2010-12-02 09:48:23 +0100
commit11b22d9f33d50f20cba1eaee2aadb55d3580d879 (patch)
tree5c4e7fe1046bd9cc1ef7a7b21abe118f43689902 /server
parent435f01649c2ee8c23c21e0680d0a39e773008549 (diff)
downloadvdr-plugin-streamdev-11b22d9f33d50f20cba1eaee2aadb55d3580d879.tar.gz
vdr-plugin-streamdev-11b22d9f33d50f20cba1eaee2aadb55d3580d879.tar.bz2
Streamdev 0.5.0-rc1
Diffstat (limited to 'server')
-rw-r--r--server/Makefile82
-rw-r--r--server/connection.c62
-rw-r--r--server/connection.h20
-rw-r--r--server/connectionHTTP.c360
-rw-r--r--server/connectionHTTP.h19
-rw-r--r--server/connectionIGMP.c4
-rw-r--r--server/connectionVTP.c194
-rw-r--r--server/livestreamer.c40
-rw-r--r--server/livestreamer.h5
-rw-r--r--server/menuHTTP.c8
-rw-r--r--server/menuHTTP.h9
-rw-r--r--server/po/de_DE.po83
-rw-r--r--server/po/fi_FI.po83
-rw-r--r--server/po/fr_FR.po83
-rw-r--r--server/po/it_IT.po85
-rw-r--r--server/po/lt_LT.po83
-rw-r--r--server/po/ru_RU.po83
-rw-r--r--server/po/sk_SK.po85
-rw-r--r--server/recplayer.c11
-rw-r--r--server/setup.c80
-rw-r--r--server/setup.h9
-rw-r--r--server/streamdev-server.c143
-rw-r--r--server/streamdev-server.h33
-rw-r--r--server/streamer.c5
-rw-r--r--server/streamer.h8
25 files changed, 1375 insertions, 302 deletions
diff --git a/server/Makefile b/server/Makefile
new file mode 100644
index 0000000..91c2a93
--- /dev/null
+++ b/server/Makefile
@@ -0,0 +1,82 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile,v 1.1.2.1 2010/06/14 10:40:20 schmirl Exp $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = streamdev-server
+
+### Includes and Defines (add further entries here):
+
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+COMMONOBJS = ../common.o
+
+SERVEROBJS = $(PLUGIN).o \
+ server.o component.o connection.o \
+ componentVTP.o connectionVTP.o \
+ componentHTTP.o connectionHTTP.o menuHTTP.o \
+ componentIGMP.o connectionIGMP.o \
+ streamer.o livestreamer.o livefilter.o recplayer.o \
+ suspend.o setup.o
+
+### The main target:
+
+.PHONY: all i18n clean
+all: libvdr-$(PLUGIN).so i18n
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR = po
+LOCALEDIR = $(VDRDIR)/locale
+I18Npo = $(wildcard $(PODIR)/*.po)
+I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+ msgfmt -c -o $@ $<
+
+$(I18Npot): $(SERVEROBJS:%.o=%.c)
+ xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<http://www.vdr-developer.org/mantisbt/>' -o $@ $^
+
+%.po: $(I18Npot)
+ msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
+ @touch $@
+
+$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+ @mkdir -p $(dir $@)
+ cp $< $@
+
+i18n: $(I18Nmsgs)
+
+### Targets:
+
+libvdr-$(PLUGIN).so: $(SERVEROBJS) $(COMMONOBJS) \
+ ../tools/sockettools.a ../remux/remux.a ../libdvbmpeg/libdvbmpegtools.a
+
+%.so:
+ $(CXX) $(CXXFLAGS) -shared $^ -o $@
+ @cp $@ $(LIBDIR)/$@.$(APIVERSION)
+
+clean:
+ @-rm -f $(COMMONOBJS) $(SERVEROBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~
diff --git a/server/connection.c b/server/connection.c
index 74b2783..6121b7a 100644
--- a/server/connection.c
+++ b/server/connection.c
@@ -1,5 +1,5 @@
/*
- * $Id: connection.c,v 1.12 2009/02/13 10:39:22 schmirl Exp $
+ * $Id: connection.c,v 1.13.2.1 2010/06/11 06:06:02 schmirl Exp $
*/
#include "server/connection.h"
@@ -27,6 +27,66 @@ cServerConnection::~cServerConnection()
{
}
+const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) {
+ const cChannel *channel = NULL;
+ char *string = strdup(String);
+ char *ptr, *end;
+ int apididx = 0;
+
+ if ((ptr = strrchr(string, '+')) != NULL) {
+ *(ptr++) = '\0';
+ apididx = strtoul(ptr, &end, 10);
+ Dprintf("found apididx: %d\n", apididx);
+ }
+
+ if (isnumber(string)) {
+ int temp = strtol(String, NULL, 10);
+ if (temp >= 1 && temp <= Channels.MaxNumber())
+ channel = Channels.GetByNumber(temp);
+ } else {
+ channel = Channels.GetByChannelID(tChannelID::FromString(string));
+
+ if (channel == NULL) {
+ int i = 1;
+ while ((channel = Channels.GetByNumber(i, 1)) != NULL) {
+ if (String == channel->Name())
+ break;
+
+ i = channel->Number() + 1;
+ }
+ }
+ }
+
+ if (channel != NULL && apididx > 0) {
+ int apid = 0, dpid = 0;
+ int index = 1;
+
+ for (int i = 0; channel->Apid(i) != 0; ++i, ++index) {
+ if (index == apididx) {
+ apid = channel->Apid(i);
+ break;
+ }
+ }
+
+ if (apid == 0) {
+ for (int i = 0; channel->Dpid(i) != 0; ++i, ++index) {
+ if (index == apididx) {
+ dpid = channel->Dpid(i);
+ break;
+ }
+ }
+ }
+
+ if (Apid != NULL)
+ *Apid = apid;
+ if (Dpid != NULL)
+ *Dpid = dpid;
+ }
+
+ free(string);
+ return channel;
+}
+
bool cServerConnection::Read(void)
{
int b;
diff --git a/server/connection.h b/server/connection.h
index 2c28a09..dfaff91 100644
--- a/server/connection.h
+++ b/server/connection.h
@@ -1,5 +1,5 @@
/*
- * $Id: connection.h,v 1.7 2009/02/13 10:39:22 schmirl Exp $
+ * $Id: connection.h,v 1.8.2.1 2010/06/11 06:06:02 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
@@ -8,6 +8,11 @@
#include "tools/socket.h"
#include "common.h"
+#include <map>
+
+typedef std::map<std::string,std::string> tStrStrMap;
+typedef std::pair<std::string,std::string> tStrStr;
+
class cChannel;
class cDevice;
@@ -28,6 +33,8 @@ private:
uint m_WriteBytes;
uint m_WriteIndex;
+ tStrStrMap m_Headers;
+
protected:
/* Will be called when a command terminated by a newline has been
received */
@@ -41,6 +48,11 @@ protected:
virtual bool Respond(const char *Message, bool Last = true, ...);
//__attribute__ ((format (printf, 2, 4)));
+ /* Add a request header */
+ void SetHeader(const char *Name, const char *Value, const char *Prefix = "") { m_Headers.insert(tStrStr(std::string(Prefix) + Name, Value)); }
+
+ static const cChannel *ChannelFromString(const char *String, int *Apid = NULL, int *Dpid = NULL);
+
public:
/* If you derive, specify a short string such as HTTP for Protocol, which
will be displayed in error messages */
@@ -87,6 +99,12 @@ public:
virtual void Detach(void) = 0;
virtual void Attach(void) = 0;
+
+ /* This connections protocol name */
+ virtual const char* Protocol(void) const { return m_Protocol; }
+
+ /* std::map with additional information */
+ const tStrStrMap& Headers(void) const { return m_Headers; }
};
inline bool cServerConnection::HasData(void) const
diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c
index 83e568d..b963d64 100644
--- a/server/connectionHTTP.c
+++ b/server/connectionHTTP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionHTTP.c,v 1.17 2009/06/19 06:32:45 schmirl Exp $
+ * $Id: connectionHTTP.c,v 1.17.2.1 2010/06/11 06:06:02 schmirl Exp $
*/
#include <ctype.h>
@@ -13,13 +13,13 @@ cConnectionHTTP::cConnectionHTTP(void):
cServerConnection("HTTP"),
m_Status(hsRequest),
m_LiveStreamer(NULL),
- m_StreamerParameter(""),
m_Channel(NULL),
- m_Apid(0),
m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
m_ChannelList(NULL)
{
Dprintf("constructor hsRequest\n");
+ m_Apid[0] = m_Apid[1] = 0;
+ m_Dpid[0] = m_Dpid[1] = 0;
}
cConnectionHTTP::~cConnectionHTTP()
@@ -37,30 +37,64 @@ bool cConnectionHTTP::Command(char *Cmd)
Dprintf("command %s\n", Cmd);
switch (m_Status) {
case hsRequest:
- Dprintf("Request\n");
- m_Request = Cmd;
- m_Status = hsHeaders;
- return true;
+ // parse METHOD PATH[?QUERY] VERSION
+ {
+ char *p, *q, *v;
+ p = strchr(Cmd, ' ');
+ if (p) {
+ *p = 0;
+ v = strchr(++p, ' ');
+ if (v) {
+ *v = 0;
+ SetHeader("REQUEST_METHOD", Cmd);
+ q = strchr(p, '?');
+ if (q)
+ *q = 0;
+ SetHeader("QUERY_STRING", q ? ++q : "");
+ SetHeader("PATH_INFO", p);
+ m_Status = hsHeaders;
+ return true;
+ }
+ }
+ }
+ return false;
case hsHeaders:
if (*Cmd == '\0') {
m_Status = hsBody;
return ProcessRequest();
}
- if (strncasecmp(Cmd, "Host:", 5) == 0) {
- Dprintf("Host-Header\n");
- m_Host = (std::string) skipspace(Cmd + 5);
- return true;
+ else if (isspace(*Cmd)) {
+ ; //TODO: multi-line header
}
- else if (strncasecmp(Cmd, "Authorization:", 14) == 0) {
- Cmd = skipspace(Cmd + 14);
- if (strncasecmp(Cmd, "Basic", 5) == 0) {
- Dprintf("'Authorization Basic'-Header\n");
- m_Authorization = (std::string) skipspace(Cmd + 5);
- return true;
+ else {
+ // convert header name to CGI conventions:
+ // uppercase, '-' replaced with '_', prefix "HTTP_"
+ char *p;
+ for (p = Cmd; *p != 0 && *p != ':'; p++) {
+ if (*p == '-')
+ *p = '_';
+ else
+ *p = toupper(*p);
+ }
+ if (*p == ':') {
+ *p = 0;
+ p = skipspace(++p);
+ // don't disclose Authorization header
+ if (strcmp(Cmd, "AUTHORIZATION") == 0) {
+ char *q;
+ for (q = p; *q != 0 && *q != ' '; q++)
+ *q = toupper(*q);
+ if (p != q) {
+ *q = 0;
+ SetHeader("AUTH_TYPE", p);
+ m_Authorization = (std::string) skipspace(++q);
+ }
+ }
+ else
+ SetHeader(Cmd, p, "HTTP_");
}
}
- Dprintf("header\n");
return true;
default:
// skip additional blank lines
@@ -73,10 +107,31 @@ bool cConnectionHTTP::Command(char *Cmd)
bool cConnectionHTTP::ProcessRequest(void)
{
+ // keys for Headers() hash
+ const static std::string AUTH_TYPE("AUTH_TYPE");
+ const static std::string REQUEST_METHOD("REQUEST_METHOD");
+ const static std::string PATH_INFO("PATH_INFO");
+
Dprintf("process\n");
- if (!StreamdevHosts.Acceptable(RemoteIpAddr()))
- {
- if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) {
+ if (!StreamdevHosts.Acceptable(RemoteIpAddr())) {
+ bool authOk = opt_auth && !m_Authorization.empty();
+ if (authOk) {
+ tStrStrMap::const_iterator it = Headers().find(AUTH_TYPE);
+
+ if (it == Headers().end()) {
+ // no authorization header present
+ authOk = false;
+ }
+ else if (it->second.compare("BASIC") == 0) {
+ // basic auth
+ authOk &= m_Authorization.compare(opt_auth) == 0;
+ }
+ else {
+ // unsupported auth type
+ authOk = false;
+ }
+ }
+ if (!authOk) {
isyslog("streamdev-server: HTTP authorization required");
DeferClose();
return Respond("HTTP/1.0 401 Authorization Required")
@@ -84,28 +139,22 @@ bool cConnectionHTTP::ProcessRequest(void)
&& Respond("");
}
}
- if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
- switch (m_Job) {
- case hjListing:
- if (m_ChannelList)
- return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
- break;
- case hjTransfer:
- if (m_Channel == NULL) {
- DeferClose();
- return Respond("HTTP/1.0 404 not found");
- }
-
- m_LiveStreamer = new cStreamdevLiveStreamer(0, m_StreamerParameter);
+ if (Headers().at(REQUEST_METHOD).compare("GET") == 0 && ProcessURI(Headers().at(PATH_INFO))) {
+ if (m_ChannelList)
+ return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
+ else if (m_Channel != NULL) {
cDevice *device = GetDevice(m_Channel, 0);
if (device != NULL) {
device->SwitchChannel(m_Channel, false);
- if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) {
+ m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
+ if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) {
m_LiveStreamer->SetDevice(device);
if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt");
- if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) {
+ if (m_StreamType == stEXT) {
+ return Respond("HTTP/1.0 200 OK");
+ } else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) {
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: audio/mpeg")
&& Respond("icy-name: %s", true, m_Channel->Name())
@@ -116,12 +165,46 @@ bool cConnectionHTTP::ProcessRequest(void)
&& Respond("");
}
}
+ DELETENULL(m_LiveStreamer);
}
- DELETENULL(m_LiveStreamer);
DeferClose();
return Respond("HTTP/1.0 409 Channel not available")
&& Respond("");
}
+ else {
+ DeferClose();
+ return Respond("HTTP/1.0 404 not found")
+ && Respond("");
+ }
+ } else if (Headers().at(REQUEST_METHOD).compare("HEAD") == 0 && ProcessURI(Headers().at(PATH_INFO))) {
+ DeferClose();
+ if (m_ChannelList)
+ return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
+ else if (m_Channel != NULL) {
+ cDevice *device = GetDevice(m_Channel, 0);
+ if (device != NULL) {
+ if (m_StreamType == stEXT) {
+ // TODO
+ return Respond("HTTP/1.0 200 OK")
+ && Respond("");
+ } else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) {
+ return Respond("HTTP/1.0 200 OK")
+ && Respond("Content-Type: audio/mpeg")
+ && Respond("icy-name: %s", true, m_Channel->Name())
+ && Respond("");
+ } else {
+ return Respond("HTTP/1.0 200 OK")
+ && Respond("Content-Type: video/mpeg")
+ && Respond("");
+ }
+ }
+ return Respond("HTTP/1.0 409 Channel not available")
+ && Respond("");
+ }
+ else {
+ return Respond("HTTP/1.0 404 not found")
+ && Respond("");
+ }
}
DeferClose();
@@ -136,161 +219,130 @@ void cConnectionHTTP::Flushed(void)
if (m_Status != hsBody)
return;
- switch (m_Job) {
- case hjListing:
- if (m_ChannelList) {
- if (m_ChannelList->HasNext()) {
- if (!Respond("%s", true, m_ChannelList->Next().c_str()))
- DeferClose();
- }
- else {
- DELETENULL(m_ChannelList);
- m_Status = hsFinished;
+ if (m_ChannelList) {
+ if (m_ChannelList->HasNext()) {
+ if (!Respond("%s", true, m_ChannelList->Next().c_str()))
DeferClose();
- }
- return;
}
- // should never be reached
- esyslog("streamdev-server cConnectionHTTP::Flushed(): no channel list");
- m_Status = hsFinished;
- break;
-
- case hjTransfer:
+ else {
+ DELETENULL(m_ChannelList);
+ m_Status = hsFinished;
+ DeferClose();
+ }
+ return;
+ }
+ else if (m_Channel != NULL) {
Dprintf("streamer start\n");
m_LiveStreamer->Start(this);
m_Status = hsFinished;
- break;
+ }
+ else {
+ // should never be reached
+ esyslog("streamdev-server cConnectionHTTP::Flushed(): no job to do");
+ m_Status = hsFinished;
}
}
-bool cConnectionHTTP::CmdGET(const std::string &Opts)
+cChannelList* cConnectionHTTP::ChannelListFromString(const std::string& Path, const std::string& Filebase, const std::string& Fileext) const
{
- const char *ptr, *sp, *pp, *fp, *xp, *qp, *ep;
- const cChannel *chan;
- int apid = 0;
-
- ptr = Opts.c_str();
-
- // find begin of URL
- sp = skipspace(ptr);
- // find end of URL (\0 or first space character)
- for (ep = sp; *ep && !isspace(*ep); ep++)
- ;
- // find begin of query string (first ?)
- for (qp = sp; qp < ep && *qp != '?'; qp++)
- ;
- // find begin of filename (last /)
- for (fp = qp; fp > sp && *fp != '/'; --fp)
- ;
- // find begin of section params (first ;)
- for (pp = sp; pp < fp && *pp != ';'; pp++)
- ;
- // find filename extension (first .)
- for (xp = fp; xp < qp && *xp != '.'; xp++)
- ;
- if (qp - xp > 5) // too long for a filename extension
- xp = qp;
-
- std::string type, filespec, fileext, query;
- // Streamtype with leading / stripped off
- if (pp > sp)
- type = Opts.substr(sp - ptr + 1, pp - sp - 1);
- // Section parameters with leading ; stripped off
- if (fp > pp)
- m_StreamerParameter = Opts.substr(pp - ptr + 1, fp - pp - 1);
- // file basename with leading / stripped off
- if (xp > fp)
- filespec = Opts.substr(fp - ptr + 1, xp - fp - 1);
- // file extension including leading .
- fileext = Opts.substr(xp - ptr, qp - xp);
- // query string including leading ?
- query = Opts.substr(qp - ptr, ep - qp);
+ // keys for Headers() hash
+ const static std::string QUERY_STRING("QUERY_STRING");
+ const static std::string HOST("HTTP_HOST");
- Dprintf("before channelfromstring: type(%s) param(%s) filespec(%s) fileext(%s) query(%s)\n", type.c_str(), m_StreamerParameter.c_str(), filespec.c_str(), fileext.c_str(), query.c_str());
-
- const char* pType = type.c_str();
- if (strcasecmp(pType, "PS") == 0) {
- m_StreamType = stPS;
- } else if (strcasecmp(pType, "PES") == 0) {
- m_StreamType = stPES;
- } else if (strcasecmp(pType, "TS") == 0) {
- m_StreamType = stTS;
- } else if (strcasecmp(pType, "ES") == 0) {
- m_StreamType = stES;
- } else if (strcasecmp(pType, "Extern") == 0) {
- m_StreamType = stExtern;
- }
+ const std::string query = Headers().at(QUERY_STRING);
std::string groupTarget;
cChannelIterator *iterator = NULL;
- if (filespec.compare("tree") == 0) {
+ if (Filebase.compare("tree") == 0) {
const cChannel* c = NULL;
size_t groupIndex = query.find("group=");
if (groupIndex != std::string::npos)
c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
iterator = new cListTree(c);
- groupTarget = filespec + fileext;
- } else if (filespec.compare("groups") == 0) {
+ groupTarget = Filebase + Fileext;
+ } else if (Filebase.compare("groups") == 0) {
iterator = new cListGroups();
- groupTarget = (std::string) "group" + fileext;
- } else if (filespec.compare("group") == 0) {
+ groupTarget = (std::string) "group" + Fileext;
+ } else if (Filebase.compare("group") == 0) {
const cChannel* c = NULL;
size_t groupIndex = query.find("group=");
if (groupIndex != std::string::npos)
c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
iterator = new cListGroup(c);
- } else if (filespec.compare("channels") == 0) {
+ } else if (Filebase.compare("channels") == 0) {
iterator = new cListChannels();
- } else if (filespec.compare("all") == 0 ||
- (filespec.empty() && fileext.empty())) {
+ } else if (Filebase.compare("all") == 0 ||
+ (Filebase.empty() && Fileext.empty())) {
iterator = new cListAll();
}
if (iterator) {
- if (filespec.empty() || fileext.compare(".htm") == 0 || fileext.compare(".html") == 0) {
- m_ChannelList = new cHtmlChannelList(iterator, m_StreamType, (filespec + fileext + query).c_str(), groupTarget.c_str());
- m_Job = hjListing;
- } else if (fileext.compare(".m3u") == 0) {
+ if (Filebase.empty() || Fileext.compare(".htm") == 0 || Fileext.compare(".html") == 0) {
+ std::string self = Filebase + Fileext;
+ if (!query.empty())
+ self += '?' + query;
+ return new cHtmlChannelList(iterator, m_StreamType, self.c_str(), groupTarget.c_str());
+ } else if (Fileext.compare(".m3u") == 0) {
std::string base;
- if (*(m_Host.c_str()))
- base = "http://" + m_Host + "/";
+ tStrStrMap::const_iterator it = Headers().find(HOST);
+ if (it != Headers().end())
+ base = "http://" + it->second + "/";
else
base = (std::string) "http://" + LocalIp() + ":" +
(const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/";
- if (type.empty())
- {
- switch (m_StreamType)
- {
- case stTS: base += "TS/"; break;
- case stPS: base += "PS/"; break;
- case stPES: base += "PES/"; break;
- case stES: base += "ES/"; break;
- case stExtern: base += "Extern/"; break;
- default: break;
-
- }
- } else {
- base += type;
- if (!m_StreamerParameter.empty())
- base += ";" + m_StreamerParameter;
- base += "/";
- }
- m_ChannelList = new cM3uChannelList(iterator, base.c_str());
- m_Job = hjListing;
+ base += Path;
+ return new cM3uChannelList(iterator, base.c_str());
} else {
delete iterator;
- return false;
}
- } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) {
- m_Channel = chan;
- m_Apid = apid;
- Dprintf("Apid is %d\n", apid);
- m_Job = hjTransfer;
+ }
+ return NULL;
+}
+
+bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
+{
+ std::string filespec, fileext;
+ size_t file_pos = PathInfo.rfind('/');
+
+ if (file_pos != std::string::npos) {
+ size_t ext_pos = PathInfo.rfind('.');
+ // file basename with leading / stripped off
+ filespec = PathInfo.substr(file_pos + 1, ext_pos - file_pos - 1);
+ if (ext_pos != std::string::npos)
+ // file extension including leading .
+ fileext = PathInfo.substr(ext_pos);
+ }
+ if (fileext.length() > 5) {
+ //probably not an extension
+ filespec += fileext;
+ fileext.clear();
+ }
+
+ // Streamtype with leading / stripped off
+ std::string type = PathInfo.substr(1, PathInfo.find_first_of("/;", 1) - 1);
+ const char* pType = type.c_str();
+ if (strcasecmp(pType, "PS") == 0) {
+ m_StreamType = stPS;
+ } else if (strcasecmp(pType, "PES") == 0) {
+ m_StreamType = stPES;
+ } else if (strcasecmp(pType, "TS") == 0) {
+ m_StreamType = stTS;
+ } else if (strcasecmp(pType, "ES") == 0) {
+ m_StreamType = stES;
+ } else if (strcasecmp(pType, "EXT") == 0) {
+ m_StreamType = stEXT;
+ }
+
+ Dprintf("before channelfromstring: type(%s) filespec(%s) fileext(%s)\n", type.c_str(), filespec.c_str(), fileext.c_str());
+
+ if ((m_ChannelList = ChannelListFromString(PathInfo.substr(0, file_pos), filespec.c_str(), fileext.c_str())) != NULL) {
+ Dprintf("Channel list requested\n");
+ return true;
+ } else if ((m_Channel = ChannelFromString(filespec.c_str(), &m_Apid[0], &m_Dpid[0])) != NULL) {
+ Dprintf("Channel found. Apid/Dpid is %d/%d\n", m_Apid[0], m_Dpid[0]);
+ return true;
} else
return false;
-
- Dprintf("after channelfromstring\n");
- return true;
}
diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h
index 0548959..1ea6ed2 100644
--- a/server/connectionHTTP.h
+++ b/server/connectionHTTP.h
@@ -1,5 +1,5 @@
/*
- * $Id: connectionHTTP.h,v 1.6 2008/10/14 11:05:48 schmirl Exp $
+ * $Id: connectionHTTP.h,v 1.6.2.1 2010/06/11 06:06:02 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
@@ -8,6 +8,7 @@
#include "connection.h"
#include "server/livestreamer.h"
+#include <map>
#include <tools/select.h>
class cChannel;
@@ -23,26 +24,19 @@ private:
hsFinished,
};
- enum eHTTPJob {
- hjTransfer,
- hjListing,
- };
-
- std::string m_Request;
- std::string m_Host;
std::string m_Authorization;
- //std::map<std::string,std::string> m_Headers; TODO: later?
eHTTPStatus m_Status;
- eHTTPJob m_Job;
// job: transfer
cStreamdevLiveStreamer *m_LiveStreamer;
- std::string m_StreamerParameter;
const cChannel *m_Channel;
- int m_Apid;
+ int m_Apid[2];
+ int m_Dpid[2];
eStreamType m_StreamType;
// job: listing
cChannelList *m_ChannelList;
+ cChannelList* ChannelListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const;
+ bool ProcessURI(const std::string &PathInfo);
protected:
bool ProcessRequest(void);
@@ -56,7 +50,6 @@ public:
virtual bool CanAuthenticate(void);
virtual bool Command(char *Cmd);
- bool CmdGET(const std::string &Opts);
virtual bool Abort(void) const;
virtual void Flushed(void);
diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c
index dc08798..7ea7e11 100644
--- a/server/connectionIGMP.c
+++ b/server/connectionIGMP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $
+ * $Id: connectionIGMP.c,v 1.1.4.1 2010/06/11 06:06:02 schmirl Exp $
*/
#include <ctype.h>
@@ -31,7 +31,7 @@ bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst)
struct in_addr ip;
ip.s_addr = Dst;
if (Connect(inet_ntoa(ip), m_ClientPort)) {
- m_LiveStreamer = new cStreamdevLiveStreamer(0);
+ m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) {
m_LiveStreamer->SetDevice(device);
if (!SetDSCP())
diff --git a/server/connectionVTP.c b/server/connectionVTP.c
index 6037ecc..ca73cfb 100644
--- a/server/connectionVTP.c
+++ b/server/connectionVTP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionVTP.c,v 1.22 2009/07/02 06:03:51 schmirl Exp $
+ * $Id: connectionVTP.c,v 1.27.2.1 2010/06/11 06:06:03 schmirl Exp $
*/
#include "server/connectionVTP.h"
@@ -40,6 +40,9 @@ private:
#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM)
enum eStates { Channel, Event, Title, Subtitle, Description, Vps, Content,
EndEvent, EndChannel, EndEPG };
+#elif APIVERSNUM >= 10711
+ enum eStates { Channel, Event, Title, Subtitle, Description, Vps, Content, Rating,
+ EndEvent, EndChannel, EndEPG };
#else
enum eStates { Channel, Event, Title, Subtitle, Description, Vps,
EndEvent, EndChannel, EndEPG };
@@ -50,7 +53,7 @@ private:
const cSchedule *m_Schedule;
const cEvent *m_Event;
int m_Errno;
- char *m_Error;
+ cString m_Error;
eStates m_State;
bool m_Traverse;
time_t m_ToTime;
@@ -67,7 +70,6 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
m_Schedule(NULL),
m_Event(NULL),
m_Errno(0),
- m_Error(NULL),
m_State(Channel),
m_Traverse(false),
m_ToTime(0)
@@ -94,12 +96,12 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
attime = strtol(p, NULL, 10);
else {
m_Errno = 501;
- m_Error = strdup("Invalid time");
+ m_Error = "Invalid time";
break;
}
} else {
m_Errno = 501;
- m_Error = strdup("Missing time");
+ m_Error = "Missing time";
break;
}
}
@@ -110,7 +112,7 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
fromtime = strtol(p, NULL, 10);
else {
m_Errno = 501;
- m_Error = strdup("Invalid time");
+ m_Error = "Invalid time";
break;
}
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
@@ -120,19 +122,19 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
m_ToTime = strtol(p, NULL, 10);
else {
m_Errno = 501;
- m_Error = strdup("Invalid time");
+ m_Error = "Invalid time";
break;
}
} else {
m_Errno = 501;
- m_Error = strdup("Missing time");
+ m_Error = "Missing time";
break;
}
}
}
} else {
m_Errno = 501;
- m_Error = strdup("Missing time");
+ m_Error = "Missing time";
break;
}
} else if (!m_Schedule) {
@@ -146,27 +148,27 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
m_Schedule = m_Schedules->GetSchedule(Channel->GetChannelID());
if (!m_Schedule) {
m_Errno = 550;
- m_Error = strdup("No schedule found");
+ m_Error = "No schedule found";
break;
}
} else {
m_Errno = 550;
- asprintf(&m_Error, "Channel \"%s\" not defined", p);
+ m_Error = cString::sprintf("Channel \"%s\" not defined", p);
break;
}
} else {
m_Errno = 501;
- asprintf(&m_Error, "Unknown option: \"%s\"", p);
+ m_Error = cString::sprintf("Unknown option: \"%s\"", p);
break;
}
p = strtok_r(NULL, delim, &strtok_next);
}
} else if (m_Schedules == NULL) {
m_Errno = 451;
- m_Error = strdup("EPG data is being modified, try again");
+ m_Error = "EPG data is being modified, try again";
}
- if (m_Error == NULL) {
+ if (*m_Error == NULL) {
if (m_Schedule != NULL)
m_Schedules = NULL;
else if (m_Schedules != NULL)
@@ -205,17 +207,15 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
cLSTEHandler::~cLSTEHandler()
{
delete m_SchedulesLock;
- if (m_Error != NULL)
- free(m_Error);
}
bool cLSTEHandler::Next(bool &Last)
{
- if (m_Error != NULL) {
+ if (*m_Error != NULL) {
Last = true;
- cString str(m_Error, true);
+ cString str(m_Error);
m_Error = NULL;
- return m_Client->Respond(m_Errno, *str);
+ return m_Client->Respond(m_Errno, "%s", *str);
}
Last = false;
@@ -285,7 +285,7 @@ bool cLSTEHandler::Next(bool &Last)
break;
case Vps:
-#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM)
+#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM) || APIVERSNUM >= 10711
m_State = Content;
#else
m_State = EndEvent;
@@ -311,6 +311,25 @@ bool cLSTEHandler::Next(bool &Last)
} else
return Next(Last);
break;
+#elif APIVERSNUM >= 10711
+ case Content:
+ m_State = Rating;
+ if (!isempty(m_Event->ContentToString(m_Event->Contents()))) {
+ char *copy = strdup(m_Event->ContentToString(m_Event->Contents()));
+ cString cpy(copy, true);
+ strreplace(copy, '\n', '|');
+ return m_Client->Respond(-215, "G %i %i %s", m_Event->Contents() & 0xF0, m_Event->Contents() & 0x0F, copy);
+ } else
+ return Next(Last);
+ break;
+
+ case Rating:
+ m_State = EndEvent;
+ if (m_Event->ParentalRating())
+ return m_Client->Respond(-215, "R %d", m_Event->ParentalRating());
+ else
+ return Next(Last);
+ break;
#endif
case EndEvent:
@@ -361,7 +380,7 @@ private:
const cChannel *m_Channel;
char *m_Option;
int m_Errno;
- char *m_Error;
+ cString m_Error;
bool m_Traverse;
public:
cLSTCHandler(cConnectionVTP *Client, const char *Option);
@@ -374,18 +393,17 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option):
m_Channel(NULL),
m_Option(NULL),
m_Errno(0),
- m_Error(NULL),
m_Traverse(false)
{
if (!Channels.Lock(false, 500)) {
m_Errno = 451;
- m_Error = strdup("Channels are being modified - try again");
+ m_Error = "Channels are being modified - try again";
} else if (*Option) {
if (isnumber(Option)) {
m_Channel = Channels.GetByNumber(strtol(Option, NULL, 10));
if (m_Channel == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Channel \"%s\" not defined", Option);
+ m_Error = cString::sprintf("Channel \"%s\" not defined", Option);
return;
}
} else {
@@ -401,7 +419,7 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option):
if (i > Channels.MaxNumber()) {
m_Errno = 501;
- asprintf(&m_Error, "Channel \"%s\" not defined", Option);
+ m_Error = cString::sprintf("Channel \"%s\" not defined", Option);
return;
}
}
@@ -410,26 +428,24 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option):
m_Traverse = true;
} else {
m_Errno = 550;
- m_Error = strdup("No channels defined");
+ m_Error = "No channels defined";
}
}
cLSTCHandler::~cLSTCHandler()
{
Channels.Unlock();
- if (m_Error != NULL)
- free(m_Error);
if (m_Option != NULL)
free(m_Option);
}
bool cLSTCHandler::Next(bool &Last)
{
- if (m_Error != NULL) {
+ if (*m_Error != NULL) {
Last = true;
- cString str(m_Error, true);
+ cString str(m_Error);
m_Error = NULL;
- return m_Client->Respond(m_Errno, *str);
+ return m_Client->Respond(m_Errno, "%s", *str);
}
int number;
@@ -452,7 +468,7 @@ bool cLSTCHandler::Next(bool &Last)
i = m_Channel->Number() + 1;
} else {
m_Errno = 501;
- asprintf(&m_Error, "Channel \"%d\" not found", i);
+ m_Error = cString::sprintf("Channel \"%d\" not found", i);
}
}
@@ -472,7 +488,7 @@ private:
cTimer *m_Timer;
int m_Index;
int m_Errno;
- char *m_Error;
+ cString m_Error;
bool m_Traverse;
public:
cLSTTHandler(cConnectionVTP *Client, const char *Option);
@@ -485,7 +501,6 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option):
m_Timer(NULL),
m_Index(0),
m_Errno(0),
- m_Error(NULL),
m_Traverse(false)
{
if (*Option) {
@@ -493,11 +508,11 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option):
m_Timer = Timers.Get(strtol(Option, NULL, 10) - 1);
if (m_Timer == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Timer \"%s\" not defined", Option);
+ m_Error = cString::sprintf("Timer \"%s\" not defined", Option);
}
} else {
m_Errno = 501;
- asprintf(&m_Error, "Error in timer number \"%s\"", Option);
+ m_Error = cString::sprintf("Error in timer number \"%s\"", Option);
}
} else if (Timers.Count()) {
m_Traverse = true;
@@ -505,27 +520,25 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option):
m_Timer = Timers.Get(m_Index);
if (m_Timer == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Timer \"%d\" not found", m_Index + 1);
+ m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1);
}
} else {
m_Errno = 550;
- m_Error = strdup("No timers defined");
+ m_Error = "No timers defined";
}
}
cLSTTHandler::~cLSTTHandler()
{
- if (m_Error != NULL)
- free(m_Error);
}
bool cLSTTHandler::Next(bool &Last)
{
- if (m_Error != NULL) {
+ if (*m_Error != NULL) {
Last = true;
- cString str(m_Error, true);
+ cString str(m_Error);
m_Error = NULL;
- return m_Client->Respond(m_Errno, *str);
+ return m_Client->Respond(m_Errno, "%s", *str);
}
bool result;
@@ -541,7 +554,7 @@ bool cLSTTHandler::Next(bool &Last)
m_Timer = Timers.Get(++m_Index);
if (m_Timer == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Timer \"%d\" not found", m_Index + 1);
+ m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1);
}
}
return result;
@@ -559,7 +572,7 @@ private:
const cEvent *m_Event;
int m_Index;
int m_Errno;
- char *m_Error;
+ cString m_Error;
bool m_Traverse;
bool m_Info;
eStates m_State;
@@ -576,7 +589,6 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option):
m_Event(NULL),
m_Index(0),
m_Errno(0),
- m_Error(NULL),
m_Traverse(false),
m_Info(false),
m_State(Recording),
@@ -591,12 +603,12 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option):
m_Info = true;
if (m_Recording == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Recording \"%s\" not found", Option);
+ m_Error = cString::sprintf("Recording \"%s\" not found", Option);
}
}
else {
m_Errno = 501;
- asprintf(&m_Error, "Error in Recording number \"%s\"", Option);
+ m_Error = cString::sprintf("Error in Recording number \"%s\"", Option);
}
}
else if (Recordings.Count()) {
@@ -605,28 +617,26 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option):
m_Recording = Recordings.Get(m_Index);
if (m_Recording == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Recording \"%d\" not found", m_Index + 1);
+ m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1);
}
}
else {
m_Errno = 550;
- m_Error = strdup("No recordings available");
+ m_Error = "No recordings available";
}
}
cLSTRHandler::~cLSTRHandler()
{
- if (m_Error != NULL)
- free(m_Error);
}
bool cLSTRHandler::Next(bool &Last)
{
- if (m_Error != NULL) {
+ if (*m_Error != NULL) {
Last = true;
- cString str(m_Error, true);
+ cString str(m_Error);
m_Error = NULL;
- return m_Client->Respond(m_Errno, *str);
+ return m_Client->Respond(m_Errno, "%s", *str);
}
if (m_Info) {
@@ -714,7 +724,7 @@ bool cLSTRHandler::Next(bool &Last)
m_Recording = Recordings.Get(++m_Index);
if (m_Recording == NULL) {
m_Errno = 501;
- asprintf(&m_Error, "Recording \"%d\" not found", m_Index + 1);
+ m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1);
}
}
return result;
@@ -871,8 +881,8 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
return Respond(220, "Capability \"%s\" accepted", Opts);
}
- if (strcasecmp(Opts, "EXTERN") == 0) {
- m_StreamType = stExtern;
+ if (strcasecmp(Opts, "EXT") == 0) {
+ m_StreamType = stEXT;
return Respond(220, "Capability \"%s\" accepted", Opts);
}
@@ -1068,7 +1078,7 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
return Respond(560, "Channel not available");
delete m_LiveStreamer;
- m_LiveStreamer = new cStreamdevLiveStreamer(1);
+ m_LiveStreamer = new cStreamdevLiveStreamer(1, this);
m_LiveStreamer->SetChannel(chan, m_StreamType);
m_LiveStreamer->SetDevice(dev);
if(m_LiveSocket)
@@ -1086,7 +1096,6 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
bool cConnectionVTP::CmdPLAY(char *Opts)
{
- Recordings.Update(true);
if (*Opts) {
if (isnumber(Opts)) {
cRecording *recording = Recordings.Get(strtol(Opts, NULL, 10) - 1);
@@ -1397,22 +1406,52 @@ bool cConnectionVTP::CmdDELT(const char *Option)
{
INIT_WRAPPER();
if (*Option) {
- if (isnumber(Option)) {
- cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
+ int number = 0;
+ bool force = false;
+ char buf[strlen(Option) + 1];
+ strcpy(buf, Option);
+ const char *delim = " \t";
+ char *strtok_next;
+ char *p = strtok_r(buf, delim, &strtok_next);
+
+ if (isnumber(p)) {
+ number = strtol(p, NULL, 10) - 1;
+ }
+ else if (strcasecmp(p, "FORCE") == 0) {
+ force = true;
+ }
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (isnumber(p)) {
+ number = strtol(p, NULL, 10) - 1;
+ }
+ else if (strcasecmp(p, "FORCE") == 0) {
+ force = true;
+ }
+ else {
+ Reply(501, "Timer not found or wrong syntax");
+ }
+ }
+
+ cTimer *timer = Timers.Get(number);
if (timer) {
- if (!timer->Recording()) {
+ if (timer->Recording()) {
+ if (force) {
+ timer->Skip();
+ cRecordControls::Process(time(NULL));
+ }
+ else {
+ Reply(550, "Timer \"%i\" is recording", number);
+ EXIT_WRAPPER();
+ }
+ }
isyslog("deleting timer %s", *timer->ToDescr());
Timers.Del(timer);
Timers.SetModified();
- Reply(250, "Timer \"%s\" deleted", Option);
+ Reply(250, "Timer \"%i\" deleted", number);
} else
- Reply(550, "Timer \"%s\" is recording", Option);
+ Reply(501, "Timer \"%i\" not defined", number);
} else
- Reply(501, "Timer \"%s\" not defined", Option);
- } else
- Reply(501, "Error in timer number \"%s\"", Option);
- } else
- Reply(501, "Missing timer number");
+ Reply(501, "Missing timer option");
EXIT_WRAPPER();
}
@@ -1706,12 +1745,17 @@ bool cConnectionVTP::CmdRENR(const char *Option)
bool cConnectionVTP::Respond(int Code, const char *Message, ...)
{
- char *buffer;
va_list ap;
va_start(ap, Message);
- vasprintf(&buffer, Message, ap);
- va_end(ap);
+#if APIVERSNUM < 10515
+ char *buffer;
+ if (vasprintf(&buffer, Message, ap) < 0)
+ buffer = strdup("???");
cString str(buffer, true);
+#else
+ cString str = cString::sprintf(Message, ap);
+#endif
+ va_end(ap);
if (Code >= 0 && m_LastCommand != NULL) {
free(m_LastCommand);
@@ -1719,6 +1763,6 @@ bool cConnectionVTP::Respond(int Code, const char *Message, ...)
}
return cServerConnection::Respond("%03d%c%s", Code >= 0,
- Code < 0 ? -Code : Code,
- Code < 0 ? '-' : ' ', buffer);
+ Code < 0 ? -Code : Code,
+ Code < 0 ? '-' : ' ', *str);
}
diff --git a/server/livestreamer.c b/server/livestreamer.c
index 71a3565..2b0065c 100644
--- a/server/livestreamer.c
+++ b/server/livestreamer.c
@@ -172,16 +172,20 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
switch (d->getDescriptorTag()) {
case SI::AC3DescriptorTag:
+ case SI::EnhancedAC3DescriptorTag:
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
+ delete d;
return stream.getPid();
case SI::TeletextDescriptorTag:
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
+ delete d;
return stream.getPid();
case SI::SubtitlingDescriptorTag:
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
+ delete d;
return stream.getPid();
default:
Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n",
@@ -214,6 +218,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
stream.getPid(), stream.getStreamType(),
d->getLength(), rawdata[2], rawdata[3],
rawdata[4], rawdata[5]);
+ delete d;
return stream.getPid();
}
}
@@ -330,10 +335,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
// --- cStreamdevLiveStreamer -------------------------------------------------
-cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Parameter):
- cStreamdevStreamer("streamdev-livestreaming"),
+cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection):
+ cStreamdevStreamer("streamdev-livestreaming", Connection),
m_Priority(Priority),
- m_Parameter(Parameter),
m_NumPids(0),
m_StreamType(stTSPIDS),
m_Channel(NULL),
@@ -443,37 +447,39 @@ void cStreamdevLiveStreamer::StartReceiver(void)
}
}
-bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid)
+bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid)
{
Dprintf("Initializing Remuxer for full channel transfer\n");
//printf("ca pid: %d\n", Channel->Ca());
m_Channel = Channel;
m_StreamType = StreamType;
- int apid[2] = { Apid, 0 };
- const int *Apids = Apid ? apid : m_Channel->Apids();
- const int *Dpids = Apid ? NULL : m_Channel->Dpids();
+ const int *Apids = Apid ? Apid : m_Channel->Apids();
+ const int *Dpids = Dpid ? Dpid : m_Channel->Dpids();
switch (m_StreamType) {
case stES:
{
int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid();
- if (Apid != 0)
- pid = Apid;
+ if (Apid && Apid[0])
+ pid = Apid[0];
+ else if (Dpid && Dpid[0])
+ pid = Dpid[0];
m_Remux = new cTS2ESRemux(pid);
return SetPids(pid);
}
case stPES:
- m_Remux = new cTS2PESRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
- m_Channel->Spids());
+ m_Remux = new cTS2PESRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
case stPS:
- m_Remux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
- m_Channel->Spids());
+ m_Remux = new cTS2PSRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
+ case stEXT:
+ m_Remux = new cExternRemux(Connection(), m_Channel, Apids, Dpids);
+ // fall through
case stTS:
// This should never happen, but ...
if (m_PatFilter) {
@@ -488,16 +494,12 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
return true;
- case stExtern:
- m_Remux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
- m_Channel->Spids(), m_Parameter);
- return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
-
case stTSPIDS:
Dprintf("pid streaming mode\n");
return true;
+ default:
+ return false;
}
- return false;
}
int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
diff --git a/server/livestreamer.h b/server/livestreamer.h
index 92448bb..283a395 100644
--- a/server/livestreamer.h
+++ b/server/livestreamer.h
@@ -18,7 +18,6 @@ class cStreamdevLiveReceiver;
class cStreamdevLiveStreamer: public cStreamdevStreamer {
private:
int m_Priority;
- std::string m_Parameter;
int m_Pids[MAXRECEIVEPIDS + 1];
int m_NumPids;
eStreamType m_StreamType;
@@ -32,13 +31,13 @@ private:
bool HasPid(int Pid);
public:
- cStreamdevLiveStreamer(int Priority, std::string Parameter = "");
+ cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection);
virtual ~cStreamdevLiveStreamer();
void SetDevice(cDevice *Device) { m_Device = Device; }
bool SetPid(int Pid, bool On);
bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
- bool SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid = 0);
+ bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
virtual int Put(const uchar *Data, int Count);
virtual uchar *Get(int &Count);
diff --git a/server/menuHTTP.c b/server/menuHTTP.c
index 8d3e404..5fb5010 100644
--- a/server/menuHTTP.c
+++ b/server/menuHTTP.c
@@ -205,8 +205,8 @@ std::string cHtmlChannelList::StreamTypeMenu()
(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
typeMenu += (streamType == stES ? (std::string) "[ES] " :
(std::string) "[<a href=\"/ES/" + self + "\">ES</a>] ");
- typeMenu += (streamType == stExtern ? (std::string) "[Extern] " :
- (std::string) "[<a href=\"/Extern/" + self + "\">Extern</a>] ");
+ typeMenu += (streamType == stEXT ? (std::string) "[EXT] " :
+ (std::string) "[<a href=\"/EXT/" + self + "\">EXT</a>] ");
return typeMenu;
}
@@ -415,13 +415,13 @@ std::string cM3uChannelList::Next()
if (channel->GroupSep())
{
- return (std::string) "#EXTINF:0," + name + "\r\n" +
+ return (std::string) "#EXTINF:-1," + name + "\r\n" +
base + "group.m3u?group=" +
(const char*) itoa(cChannelList::GetGroupIndex(channel));
}
else
{
- return (std::string) "#EXTINF:0," +
+ return (std::string) "#EXTINF:-1," +
(const char*) itoa(channel->Number()) + " " + name + "\r\n" +
base + (std::string) channel->GetChannelID().ToString();
}
diff --git a/server/menuHTTP.h b/server/menuHTTP.h
index fa699b9..cbd7b59 100644
--- a/server/menuHTTP.h
+++ b/server/menuHTTP.h
@@ -113,7 +113,12 @@ class cHtmlChannelList: public cChannelList
std::string ItemText();
std::string PageBottom();
public:
- virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: text/html\r\n\r\n"; }
+ virtual std::string HttpHeader() {
+ return cChannelList::HttpHeader()
+ + "Content-type: text/html; charset="
+ + (cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8")
+ + "\r\n";
+ }
virtual bool HasNext();
virtual std::string Next();
cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget);
@@ -128,7 +133,7 @@ class cM3uChannelList: public cChannelList
eM3uState m3uState;
cCharSetConv m_IConv;
public:
- virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl\r\n"; };
+ virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl; charset=UTF-8\r\n"; };
virtual bool HasNext();
virtual std::string Next();
cM3uChannelList(cChannelIterator *Iterator, const char* Base);
diff --git a/server/po/de_DE.po b/server/po/de_DE.po
new file mode 100644
index 0000000..5fb611d
--- /dev/null
+++ b/server/po/de_DE.po
@@ -0,0 +1,83 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Frank Schmirler <vdrdev@schmirler.de>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev 0.5.0\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: 2008-03-30 02:11+0200\n"
+"Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "VDR Streaming Server"
+msgstr "VDR Streaming Server"
+
+msgid "Streaming active"
+msgstr "Streamen im Gange"
+
+msgid "Suspend Live TV"
+msgstr "Live-TV pausieren"
+
+msgid "Offer suspend mode"
+msgstr "Pausieren anbieten"
+
+msgid "Always suspended"
+msgstr "Immer pausiert"
+
+msgid "Never suspended"
+msgstr "Nie pausiert"
+
+msgid "Common Settings"
+msgstr "Allgemeines"
+
+msgid "Maximum Number of Clients"
+msgstr "Maximalanzahl an Clients"
+
+msgid "Suspend behaviour"
+msgstr "Pausierverhalten"
+
+msgid "Client may suspend"
+msgstr "Client darf pausieren"
+
+msgid "VDR-to-VDR Server"
+msgstr "VDR-zu-VDR Server"
+
+msgid "Start VDR-to-VDR Server"
+msgstr "VDR-zu-VDR Server starten"
+
+msgid "VDR-to-VDR Server Port"
+msgstr "Port des VDR-zu-VDR Servers"
+
+msgid "Bind to IP"
+msgstr "Binde an IP"
+
+msgid "HTTP Server"
+msgstr "HTTP Server"
+
+msgid "Start HTTP Server"
+msgstr "HTTP Server starten"
+
+msgid "HTTP Server Port"
+msgstr "Port des HTTP Servers"
+
+msgid "HTTP Streamtype"
+msgstr "HTTP Streamtyp"
+
+msgid "Multicast Streaming Server"
+msgstr "Multicast Streaming Server"
+
+msgid "Start IGMP Server"
+msgstr "IGMP Server starten"
+
+msgid "Multicast Client Port"
+msgstr "Port des Multicast Clients"
+
+msgid "Multicast Streamtype"
+msgstr "Multicast Streamtyp"
+
diff --git a/server/po/fi_FI.po b/server/po/fi_FI.po
new file mode 100644
index 0000000..99c6ee5
--- /dev/null
+++ b/server/po/fi_FI.po
@@ -0,0 +1,83 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Rolf Ahrenberg <rahrenbe@cc.hut.fi>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev 0.5.0\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: 2008-03-30 02:11+0200\n"
+"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "VDR Streaming Server"
+msgstr "VDR-suoratoistopalvelin"
+
+msgid "Streaming active"
+msgstr "Suoratoistopalvelin aktiivinen"
+
+msgid "Suspend Live TV"
+msgstr "Pysyt suora TV-lhetys"
+
+msgid "Offer suspend mode"
+msgstr "tyrkyt"
+
+msgid "Always suspended"
+msgstr "aina"
+
+msgid "Never suspended"
+msgstr "ei koskaan"
+
+msgid "Common Settings"
+msgstr "Yleiset asetukset"
+
+msgid "Maximum Number of Clients"
+msgstr "Suurin sallittu asiakkaiden mr"
+
+msgid "Suspend behaviour"
+msgstr "Pysytystoiminto"
+
+msgid "Client may suspend"
+msgstr "Asiakas saa pysytt palvelimen"
+
+msgid "VDR-to-VDR Server"
+msgstr "VDR-palvelin"
+
+msgid "Start VDR-to-VDR Server"
+msgstr "Kynnist VDR-palvelin"
+
+msgid "VDR-to-VDR Server Port"
+msgstr "VDR-palvelimen portti"
+
+msgid "Bind to IP"
+msgstr "Sido osoitteeseen"
+
+msgid "HTTP Server"
+msgstr "HTTP-palvelin"
+
+msgid "Start HTTP Server"
+msgstr "Kynnist HTTP-palvelin"
+
+msgid "HTTP Server Port"
+msgstr "HTTP-palvelimen portti"
+
+msgid "HTTP Streamtype"
+msgstr "HTTP-lhetysmuoto"
+
+msgid "Multicast Streaming Server"
+msgstr "Multicast-suoratoistopalvelin"
+
+msgid "Start IGMP Server"
+msgstr "Kynnist IGMP-palvelin"
+
+msgid "Multicast Client Port"
+msgstr "Multicast-portti"
+
+msgid "Multicast Streamtype"
+msgstr "Multicast-lhetysmuoto"
+
diff --git a/server/po/fr_FR.po b/server/po/fr_FR.po
new file mode 100644
index 0000000..c4b458e
--- /dev/null
+++ b/server/po/fr_FR.po
@@ -0,0 +1,83 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Frank Schmirler <vdrdev@schmirler.de>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev 0.5.0\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: 2008-03-30 02:11+0200\n"
+"Last-Translator: micky979 <micky979@free.fr>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "VDR Streaming Server"
+msgstr "Serveur de streaming VDR"
+
+msgid "Streaming active"
+msgstr "Streaming actif"
+
+msgid "Suspend Live TV"
+msgstr "Suspendre Live TV"
+
+msgid "Offer suspend mode"
+msgstr "Offrir le mode suspendre"
+
+msgid "Always suspended"
+msgstr "Toujours suspendre"
+
+msgid "Never suspended"
+msgstr "Jamais suspendre"
+
+msgid "Common Settings"
+msgstr "Paramtres communs"
+
+msgid "Maximum Number of Clients"
+msgstr "Nombre maximun de clients"
+
+msgid "Suspend behaviour"
+msgstr "Suspendre"
+
+msgid "Client may suspend"
+msgstr "Le client peut suspendre"
+
+msgid "VDR-to-VDR Server"
+msgstr "VDR-to-VDR Serveur"
+
+msgid "Start VDR-to-VDR Server"
+msgstr "Dmarrer le serveur VDR-to-VDR"
+
+msgid "VDR-to-VDR Server Port"
+msgstr "Port du serveur VDR-to-VDR"
+
+msgid "Bind to IP"
+msgstr "Attacher aux IP"
+
+msgid "HTTP Server"
+msgstr "Serveur HTTP"
+
+msgid "Start HTTP Server"
+msgstr "Dmarrer le serveur HTTP"
+
+msgid "HTTP Server Port"
+msgstr "Port du serveur HTTP"
+
+msgid "HTTP Streamtype"
+msgstr "Type de Streaming HTTP"
+
+msgid "Multicast Streaming Server"
+msgstr ""
+
+msgid "Start IGMP Server"
+msgstr ""
+
+msgid "Multicast Client Port"
+msgstr ""
+
+msgid "Multicast Streamtype"
+msgstr ""
+
diff --git a/server/po/it_IT.po b/server/po/it_IT.po
new file mode 100644
index 0000000..d51f62a
--- /dev/null
+++ b/server/po/it_IT.po
@@ -0,0 +1,85 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Alberto Carraro <bertocar@tin.it>, 2001
+# Antonio Ospite <ospite@studenti.unina.it>, 2003
+# Sean Carlos <seanc@libero.it>, 2005
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev 0.5.0\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: 2008-04-13 23:42+0100\n"
+"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "VDR Streaming Server"
+msgstr "Server trasmissione VDR"
+
+msgid "Streaming active"
+msgstr "Trasmissione attiva"
+
+msgid "Suspend Live TV"
+msgstr "Sospendi TV dal vivo"
+
+msgid "Offer suspend mode"
+msgstr "Offri mod. sospensione"
+
+msgid "Always suspended"
+msgstr "Sempre sospeso"
+
+msgid "Never suspended"
+msgstr "Mai sospeso"
+
+msgid "Common Settings"
+msgstr "Impostazioni comuni"
+
+msgid "Maximum Number of Clients"
+msgstr "Numero massimo di Client"
+
+msgid "Suspend behaviour"
+msgstr "Tipo sospensione"
+
+msgid "Client may suspend"
+msgstr "Permetti sospensione al Client"
+
+msgid "VDR-to-VDR Server"
+msgstr "Server VDR-a-VDR"
+
+msgid "Start VDR-to-VDR Server"
+msgstr "Avvia Server VDR-a-VDR"
+
+msgid "VDR-to-VDR Server Port"
+msgstr "Porta Server VDR-a-VDR"
+
+msgid "Bind to IP"
+msgstr "IP associati"
+
+msgid "HTTP Server"
+msgstr "Server HTTP"
+
+msgid "Start HTTP Server"
+msgstr "Avvia Server HTTP"
+
+msgid "HTTP Server Port"
+msgstr "Porta Server HTTP"
+
+msgid "HTTP Streamtype"
+msgstr "Tipo flusso HTTP"
+
+msgid "Multicast Streaming Server"
+msgstr ""
+
+msgid "Start IGMP Server"
+msgstr ""
+
+msgid "Multicast Client Port"
+msgstr ""
+
+msgid "Multicast Streamtype"
+msgstr ""
+
diff --git a/server/po/lt_LT.po b/server/po/lt_LT.po
new file mode 100644
index 0000000..f12de4d
--- /dev/null
+++ b/server/po/lt_LT.po
@@ -0,0 +1,83 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Frank Schmirler <vdrdev@schmirler.de>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev 0.5.0\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: 2009-11-26 21:57+0200\n"
+"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
+"Language-Team: Lietuvių\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "VDR Streaming Server"
+msgstr "VDR transliavimo serveris"
+
+msgid "Streaming active"
+msgstr "Transliavimas vyksta"
+
+msgid "Suspend Live TV"
+msgstr "Pristabdyti Live TV"
+
+msgid "Offer suspend mode"
+msgstr "Klausti dėl sustabdymo"
+
+msgid "Always suspended"
+msgstr "Visada stabdyti"
+
+msgid "Never suspended"
+msgstr "Niekada nestabdyti"
+
+msgid "Common Settings"
+msgstr "Bendri nustatymai"
+
+msgid "Maximum Number of Clients"
+msgstr "Maksimalus klientų skaičius"
+
+msgid "Suspend behaviour"
+msgstr "Pristabdyti veikimą"
+
+msgid "Client may suspend"
+msgstr "Klientas gali pristabdyti"
+
+msgid "VDR-to-VDR Server"
+msgstr "VDR-su-VDR Serveris"
+
+msgid "Start VDR-to-VDR Server"
+msgstr "Paleisti VDR-su-VDR serverį"
+
+msgid "VDR-to-VDR Server Port"
+msgstr "VDR-su-VDR Serverio portas"
+
+msgid "Bind to IP"
+msgstr "Pririšti IP"
+
+msgid "HTTP Server"
+msgstr "HTTP Serveris"
+
+msgid "Start HTTP Server"
+msgstr "Paleisti HTTP serverį"
+
+msgid "HTTP Server Port"
+msgstr "HTTP serverio portas"
+
+msgid "HTTP Streamtype"
+msgstr "HTTP transliavimo tipas"
+
+msgid "Multicast Streaming Server"
+msgstr "Multicast transliavimo serveris"
+
+msgid "Start IGMP Server"
+msgstr "Paleisti IGMP serverį"
+
+msgid "Multicast Client Port"
+msgstr "Multicast kliento portas"
+
+msgid "Multicast Streamtype"
+msgstr "Multicast transliavimo tipas"
+
diff --git a/server/po/ru_RU.po b/server/po/ru_RU.po
new file mode 100644
index 0000000..21abeaf
--- /dev/null
+++ b/server/po/ru_RU.po
@@ -0,0 +1,83 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Frank Schmirler <vdrdev@schmirler.de>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev 0.5.0\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: 2008-06-26 15:36+0100\n"
+"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-5\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "VDR Streaming Server"
+msgstr "VDR Streaming "
+
+msgid "Streaming active"
+msgstr " "
+
+msgid "Suspend Live TV"
+msgstr " Live TV"
+
+msgid "Offer suspend mode"
+msgstr " "
+
+msgid "Always suspended"
+msgstr " "
+
+msgid "Never suspended"
+msgstr " "
+
+msgid "Common Settings"
+msgstr ""
+
+msgid "Maximum Number of Clients"
+msgstr ". "
+
+msgid "Suspend behaviour"
+msgstr " "
+
+msgid "Client may suspend"
+msgstr " "
+
+msgid "VDR-to-VDR Server"
+msgstr "VDR-to-VDR "
+
+msgid "Start VDR-to-VDR Server"
+msgstr " VDR-to-VDR "
+
+msgid "VDR-to-VDR Server Port"
+msgstr "VDR-to-VDR "
+
+msgid "Bind to IP"
+msgstr " IP"
+
+msgid "HTTP Server"
+msgstr "HTTP "
+
+msgid "Start HTTP Server"
+msgstr " HTTP "
+
+msgid "HTTP Server Port"
+msgstr "HTTP "
+
+msgid "HTTP Streamtype"
+msgstr " HTTP "
+
+msgid "Multicast Streaming Server"
+msgstr ""
+
+msgid "Start IGMP Server"
+msgstr ""
+
+msgid "Multicast Client Port"
+msgstr ""
+
+msgid "Multicast Streamtype"
+msgstr ""
+
diff --git a/server/po/sk_SK.po b/server/po/sk_SK.po
new file mode 100644
index 0000000..78d98c9
--- /dev/null
+++ b/server/po/sk_SK.po
@@ -0,0 +1,85 @@
+# VDR streamdev plugin language source file.
+# Copyright (C) 2009 streamdev development team. See http://streamdev.vdr-developer.org
+# This file is distributed under the same license as the VDR streamdev package.
+# Milan Hrala <hrala.milan@gmail.com>, 2009
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: streamdev_SK\n"
+"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"POT-Creation-Date: 2010-06-14 13:06+0200\n"
+"PO-Revision-Date: \n"
+"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
+"Language-Team: Slovak <hrala.milan@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Slovak\n"
+"X-Poedit-Country: SLOVAKIA\n"
+
+msgid "VDR Streaming Server"
+msgstr "VDR prdov server"
+
+msgid "Streaming active"
+msgstr "streamovanie aktivne"
+
+msgid "Suspend Live TV"
+msgstr "Pozastavenie ivho vysielania"
+
+msgid "Offer suspend mode"
+msgstr "Vber remu pozastavenia"
+
+msgid "Always suspended"
+msgstr "Vdy pozastavi"
+
+msgid "Never suspended"
+msgstr "Nikdy nepozastavi"
+
+msgid "Common Settings"
+msgstr "Veobecn nastavenia"
+
+msgid "Maximum Number of Clients"
+msgstr "Maximly poet klientov"
+
+msgid "Suspend behaviour"
+msgstr "Sprvanie preruenia"
+
+msgid "Client may suspend"
+msgstr "Klient me pozastavi"
+
+msgid "VDR-to-VDR Server"
+msgstr "VDR-do-VDR server"
+
+msgid "Start VDR-to-VDR Server"
+msgstr "Spusti VDR-do-VDR Server"
+
+msgid "VDR-to-VDR Server Port"
+msgstr "Port serveru pre VDR-do-VDR"
+
+msgid "Bind to IP"
+msgstr "viaza na IP"
+
+msgid "HTTP Server"
+msgstr "server HTTP"
+
+msgid "Start HTTP Server"
+msgstr "Spusti HTTP Server"
+
+msgid "HTTP Server Port"
+msgstr "Port serveru HTTP"
+
+msgid "HTTP Streamtype"
+msgstr "typ prdu HTTP"
+
+msgid "Multicast Streaming Server"
+msgstr "Multicast prdov server"
+
+msgid "Start IGMP Server"
+msgstr "Spusti IGMP Server"
+
+msgid "Multicast Client Port"
+msgstr "Port klienta Multicast"
+
+msgid "Multicast Streamtype"
+msgstr "Multicast typ streamu"
+
diff --git a/server/recplayer.c b/server/recplayer.c
index f45d8c3..384ac13 100644
--- a/server/recplayer.c
+++ b/server/recplayer.c
@@ -21,6 +21,9 @@
#include "recplayer.h"
+// for TSPLAY patch detection
+#include "vdr/device.h"
+
#define _XOPEN_SOURCE 600
#include <fcntl.h>
@@ -34,7 +37,7 @@ RecPlayer::RecPlayer(cRecording* rec)
// FIXME find out max file path / name lengths
-#if VDRVERSNUM >= 10703
+#if VDRVERSNUM >= 10703 || defined(TSPLAY_PATCH_VERSION)
indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording());
#else
indexFile = new cIndexFile(recording->FileName(), false);
@@ -58,7 +61,7 @@ void RecPlayer::scan()
for(i = 1; i < 1000; i++)
{
-#if APIVERSNUM < 10703
+#if APIVERSNUM < 10703 || !defined(TSPLAY_PATCH_VERSION)
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
//log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
file = fopen(fileName, "r");
@@ -99,7 +102,7 @@ int RecPlayer::openFile(int index)
char fileName[2048];
-#if APIVERSNUM >= 10703
+#if APIVERSNUM >= 10703 || defined(TSPLAY_PATCH_VERSION)
snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index);
isyslog("openFile called for index %i string:%s", index, fileName);
@@ -222,7 +225,7 @@ uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)
{
if (!indexFile) return 0;
-#if VDRVERSNUM >= 10703
+#if VDRVERSNUM >= 10703 || defined(TSPLAY_PATCH_VERSION)
uint16_t retFileNumber;
off_t retFileOffset;
#else
diff --git a/server/setup.c b/server/setup.c
index 710b1fa..986f876 100644
--- a/server/setup.c
+++ b/server/setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: setup.c,v 1.6 2009/02/13 10:39:22 schmirl Exp $
+ * $Id: setup.c,v 1.9.2.2 2010/06/18 19:07:32 schmirl Exp $
*/
#include <vdr/menuitems.h>
@@ -45,35 +45,72 @@ bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
return true;
}
+const char* cStreamdevServerMenuSetupPage::StreamTypes[st_Count - 1] = {
+ "TS",
+ "PES",
+ "PS",
+ "ES",
+ "EXT"
+};
+
+const char* cStreamdevServerMenuSetupPage::SuspendModes[sm_Count] = {
+ trNOOP("Offer suspend mode"),
+ trNOOP("Always suspended"),
+ trNOOP("Never suspended")
+};
+
cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) {
m_NewSetup = StreamdevServerSetup;
+ Set();
+}
+
+cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() {
+}
+
+void cStreamdevServerMenuSetupPage::Set(void) {
+ static const char* modes[sm_Count];
+ for (int i = 0; i < sm_Count; i++)
+ modes[i] = tr(SuspendModes[i]);
+
+ int current = Current();
+ Clear();
AddCategory (tr("Common Settings"));
- AddRangeEdit(tr("Maximum Number of Clients"), m_NewSetup.MaxClients, 0, 100);
- AddSuspEdit (tr("Suspend behaviour"), m_NewSetup.SuspendMode);
- AddBoolEdit (tr("Client may suspend"), m_NewSetup.AllowSuspend);
+ Add(new cMenuEditIntItem (tr("Maximum Number of Clients"), &m_NewSetup.MaxClients, 0, 100));
+
+ Add(new cMenuEditStraItem(tr("Suspend behaviour"), &m_NewSetup.SuspendMode, sm_Count, modes));
+ if (m_NewSetup.SuspendMode == smOffer)
+ Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend));
AddCategory (tr("VDR-to-VDR Server"));
- AddBoolEdit (tr("Start VDR-to-VDR Server"), m_NewSetup.StartVTPServer);
- AddShortEdit(tr("VDR-to-VDR Server Port"), m_NewSetup.VTPServerPort);
- AddIpEdit (tr("Bind to IP"), m_NewSetup.VTPBindIP);
+ Add(new cMenuEditBoolItem(tr("Start VDR-to-VDR Server"), &m_NewSetup.StartVTPServer));
+ Add(new cMenuEditIntItem (tr("VDR-to-VDR Server Port"), &m_NewSetup.VTPServerPort, 0, 65535));
+ Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.VTPBindIP));
AddCategory (tr("HTTP Server"));
- AddBoolEdit (tr("Start HTTP Server"), m_NewSetup.StartHTTPServer);
- AddShortEdit(tr("HTTP Server Port"), m_NewSetup.HTTPServerPort);
- AddTypeEdit (tr("HTTP Streamtype"), m_NewSetup.HTTPStreamType);
- AddIpEdit (tr("Bind to IP"), m_NewSetup.HTTPBindIP);
+ Add(new cMenuEditBoolItem(tr("Start HTTP Server"), &m_NewSetup.StartHTTPServer));
+ Add(new cMenuEditIntItem (tr("HTTP Server Port"), &m_NewSetup.HTTPServerPort, 0, 65535));
+ Add(new cMenuEditStraItem(tr("HTTP Streamtype"), &m_NewSetup.HTTPStreamType, st_Count - 1, StreamTypes));
+ Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.HTTPBindIP));
AddCategory (tr("Multicast Streaming Server"));
- AddBoolEdit (tr("Start IGMP Server"), m_NewSetup.StartIGMPServer);
- AddShortEdit(tr("Multicast Client Port"), m_NewSetup.IGMPClientPort);
- AddTypeEdit (tr("Multicast Streamtype"), m_NewSetup.IGMPStreamType);
- AddIpEdit (tr("Bind to IP"), m_NewSetup.IGMPBindIP);
- SetCurrent(Get(1));
+ Add(new cMenuEditBoolItem(tr("Start IGMP Server"), &m_NewSetup.StartIGMPServer));
+ Add(new cMenuEditIntItem (tr("Multicast Client Port"), &m_NewSetup.IGMPClientPort, 0, 65535));
+ Add(new cMenuEditStraItem(tr("Multicast Streamtype"), &m_NewSetup.IGMPStreamType, st_Count - 1, StreamTypes));
+ Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.IGMPBindIP));
+ SetCurrent(Get(current));
+ Display();
}
-cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() {
-}
+void cStreamdevServerMenuSetupPage::AddCategory(const char *Title) {
+
+ cString str = cString::sprintf("--- %s -------------------------------------------------"
+ "---------------", Title );
+ cOsdItem *item = new cOsdItem(*str);
+ item->SetSelectable(false);
+ Add(item);
+}
+
void cStreamdevServerMenuSetupPage::Store(void) {
bool restart = false;
if (m_NewSetup.StartVTPServer != StreamdevServerSetup.StartVTPServer
@@ -110,3 +147,10 @@ void cStreamdevServerMenuSetupPage::Store(void) {
cStreamdevServer::Initialize();
}
+eOSState cStreamdevServerMenuSetupPage::ProcessKey(eKeys Key) {
+ int oldMode = m_NewSetup.SuspendMode;
+ eOSState state = cMenuSetupPage::ProcessKey(Key);
+ if (oldMode != m_NewSetup.SuspendMode)
+ Set();
+ return state;
+}
diff --git a/server/setup.h b/server/setup.h
index d2b1592..f71162f 100644
--- a/server/setup.h
+++ b/server/setup.h
@@ -1,5 +1,5 @@
/*
- * $Id: setup.h,v 1.2 2009/02/13 10:39:22 schmirl Exp $
+ * $Id: setup.h,v 1.3.2.1 2010/06/18 19:07:32 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SETUPSERVER_H
@@ -30,12 +30,17 @@ struct cStreamdevServerSetup {
extern cStreamdevServerSetup StreamdevServerSetup;
-class cStreamdevServerMenuSetupPage: public cStreamdevMenuSetupPage {
+class cStreamdevServerMenuSetupPage: public cMenuSetupPage {
private:
+ static const char* StreamTypes[];
+ static const char* SuspendModes[];
cStreamdevServerSetup m_NewSetup;
+ void AddCategory(const char *Title);
+ void Set();
protected:
virtual void Store(void);
+ virtual eOSState ProcessKey(eKeys Key);
public:
cStreamdevServerMenuSetupPage(void);
diff --git a/server/streamdev-server.c b/server/streamdev-server.c
new file mode 100644
index 0000000..8e9f979
--- /dev/null
+++ b/server/streamdev-server.c
@@ -0,0 +1,143 @@
+/*
+ * streamdev.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: streamdev-server.c,v 1.1.2.1 2010/06/14 10:40:20 schmirl Exp $
+ */
+
+#include <getopt.h>
+#include <vdr/tools.h>
+#include "streamdev-server.h"
+#include "server/setup.h"
+#include "server/server.h"
+#include "server/suspend.h"
+
+#if !defined(APIVERSNUM) || APIVERSNUM < 10509
+#error "VDR-1.5.9 API version or greater is required!"
+#endif
+
+const char *cPluginStreamdevServer::DESCRIPTION = trNOOP("VDR Streaming Server");
+
+cPluginStreamdevServer::cPluginStreamdevServer(void)
+{
+}
+
+cPluginStreamdevServer::~cPluginStreamdevServer()
+{
+ free(opt_auth);
+ free(opt_remux);
+}
+
+const char *cPluginStreamdevServer::Description(void)
+{
+ return tr(DESCRIPTION);
+}
+
+const char *cPluginStreamdevServer::CommandLineHelp(void)
+{
+ // return a string that describes all known command line options.
+ return
+ " -a <LOGIN:PASSWORD>, --auth=<LOGIN:PASSWORD> Credentials for HTTP authentication.\n"
+ " -r <CMD>, --remux=<CMD> Define an external command for remuxing.\n"
+ ;
+}
+
+bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[])
+{
+ // implement command line argument processing here if applicable.
+ static const struct option long_options[] = {
+ { "auth", required_argument, NULL, 'a' },
+ { "remux", required_argument, NULL, 'r' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int c;
+ while((c = getopt_long(argc, argv, "a:r:", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'a':
+ {
+ if (opt_auth)
+ free(opt_auth);
+ int l = strlen(optarg);
+ cBase64Encoder Base64((uchar*) optarg, l, l * 4 / 3 + 3);
+ const char *s = Base64.NextLine();
+ if (s)
+ opt_auth = strdup(s);
+ }
+ break;
+ case 'r':
+ if (opt_remux)
+ free(opt_remux);
+ opt_remux = strdup(optarg);
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cPluginStreamdevServer::Start(void)
+{
+ I18nRegister(PLUGIN_NAME_I18N);
+ if (!StreamdevHosts.Load(STREAMDEVHOSTSPATH, true, true)) {
+ esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTSPATH);
+ fprintf(stderr, "streamdev-server: error while loading %s\n", STREAMDEVHOSTSPATH);
+ if (access(STREAMDEVHOSTSPATH, F_OK) != 0) {
+ fprintf(stderr, " Please install streamdevhosts.conf into the path "
+ "printed above. Without it\n"
+ " no client will be able to access your streaming-"
+ "server. An example can be\n"
+ " found together with this plugin's sources.\n");
+ }
+ return false;
+ }
+ if (!opt_remux)
+ opt_remux = strdup(DEFAULT_EXTERNREMUX);
+
+ cStreamdevServer::Initialize();
+
+ return true;
+}
+
+void cPluginStreamdevServer::Stop(void)
+{
+ cStreamdevServer::Destruct();
+}
+
+cString cPluginStreamdevServer::Active(void)
+{
+ if (cStreamdevServer::Active())
+ {
+ static const char *Message = NULL;
+ if (!Message) Message = tr("Streaming active");
+ return Message;
+ }
+ return NULL;
+}
+
+const char *cPluginStreamdevServer::MainMenuEntry(void)
+{
+ if (StreamdevServerSetup.SuspendMode == smOffer && !cSuspendCtl::IsActive())
+ return tr("Suspend Live TV");
+ return NULL;
+}
+
+cOsdObject *cPluginStreamdevServer::MainMenuAction(void)
+{
+ cControl::Launch(new cSuspendCtl);
+ return NULL;
+}
+
+cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void)
+{
+ return new cStreamdevServerMenuSetupPage;
+}
+
+bool cPluginStreamdevServer::SetupParse(const char *Name, const char *Value)
+{
+ return StreamdevServerSetup.SetupParse(Name, Value);
+}
+
+VDRPLUGINCREATOR(cPluginStreamdevServer); // Don't touch this!
diff --git a/server/streamdev-server.h b/server/streamdev-server.h
new file mode 100644
index 0000000..1224ecf
--- /dev/null
+++ b/server/streamdev-server.h
@@ -0,0 +1,33 @@
+/*
+ * $Id: streamdev-server.h,v 1.1.2.1 2010/06/14 10:40:20 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEVSERVER_H
+#define VDR_STREAMDEVSERVER_H
+
+#include "common.h"
+
+#include <vdr/plugin.h>
+
+class cPluginStreamdevServer : public cPlugin {
+private:
+ static const char *DESCRIPTION;
+
+public:
+ cPluginStreamdevServer(void);
+ virtual ~cPluginStreamdevServer();
+
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void);
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual bool Start(void);
+ virtual void Stop(void);
+ virtual cString Active(void);
+ virtual const char *MainMenuEntry(void);
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+};
+
+#endif // VDR_STREAMDEVSERVER_H
diff --git a/server/streamer.c b/server/streamer.c
index 42e7efa..b545b21 100644
--- a/server/streamer.c
+++ b/server/streamer.c
@@ -1,5 +1,5 @@
/*
- * $Id: streamer.c,v 1.19 2009/06/19 06:32:45 schmirl Exp $
+ * $Id: streamer.c,v 1.19.2.1 2010/06/11 06:06:03 schmirl Exp $
*/
#include <vdr/ringbuffer.h>
@@ -100,8 +100,9 @@ void cStreamdevWriter::Action(void)
// --- cStreamdevStreamer -----------------------------------------------------
-cStreamdevStreamer::cStreamdevStreamer(const char *Name):
+cStreamdevStreamer::cStreamdevStreamer(const char *Name, const cServerConnection *Connection):
cThread(Name),
+ m_Connection(Connection),
m_Writer(NULL),
m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2,
true, "streamdev-streamer")),
diff --git a/server/streamer.h b/server/streamer.h
index 6561bc2..d3ddd23 100644
--- a/server/streamer.h
+++ b/server/streamer.h
@@ -1,5 +1,5 @@
/*
- * $Id: streamer.h,v 1.11 2009/06/19 06:32:45 schmirl Exp $
+ * $Id: streamer.h,v 1.11.2.1 2010/06/11 06:06:03 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_STREAMER_H
@@ -11,6 +11,7 @@
class cTBSocket;
class cStreamdevStreamer;
+class cServerConnection;
#ifndef TS_SIZE
#define TS_SIZE 188
@@ -64,6 +65,7 @@ public:
class cStreamdevStreamer: public cThread {
private:
+ const cServerConnection *m_Connection;
cStreamdevWriter *m_Writer;
cStreamdevBuffer *m_RingBuffer;
cStreamdevBuffer *m_SendBuffer;
@@ -74,9 +76,11 @@ protected:
bool IsRunning(void) const { return m_Writer; }
public:
- cStreamdevStreamer(const char *Name);
+ cStreamdevStreamer(const char *Name, const cServerConnection *Connection = NULL);
virtual ~cStreamdevStreamer();
+ const cServerConnection* Connection(void) const { return m_Connection; }
+
virtual void Start(cTBSocket *Socket);
virtual void Stop(void);
bool Abort(void);