[vdr-plugin-streamdev] 02/04: Imported Upstream version 0.6.1

Tobias Grimm tiber-guest at moszumanska.debian.org
Tue Nov 4 21:19:13 UTC 2014


This is an automated email from the git hooks/post-receive script.

tiber-guest pushed a commit to branch master
in repository vdr-plugin-streamdev.

commit 6b03675cc24558d415c805d75f253af46833b021
Author: etobi <git at e-tobi.net>
Date:   Tue Nov 4 22:03:05 2014 +0100

    Imported Upstream version 0.6.1
---
 CONTRIBUTORS                                       |  11 ++
 HISTORY                                            |  26 ++++
 README                                             |  31 +++--
 client/device.c                                    |  42 +++---
 client/po/fi_FI.po                                 |   4 +-
 client/po/sk_SK.po                                 |  43 ++++---
 client/socket.c                                    |  12 +-
 common.c                                           |   2 +-
 patches/vdr-1.4.x-localchannelprovide.diff         | 102 ---------------
 ...ff => vdr-1.6.0-1.7.29-ignore_missing_cam.diff} |   0
 ....patch => vdr-1.6.0-1.7.29-intcamdevices.patch} |   0
 remux/ts2ps.c                                      |   3 +
 remux/ts2ps.h                                      |   4 +
 server/connection.c                                |  27 +++-
 server/connection.h                                |   8 +-
 server/connectionHTTP.c                            | 141 +++++++++++++++++----
 server/connectionHTTP.h                            |   6 +-
 server/connectionIGMP.c                            |   5 +-
 server/connectionVTP.c                             |  15 ++-
 server/livestreamer.c                              |   2 +
 server/menuHTTP.c                                  |   6 +-
 server/menuHTTP.h                                  |   1 +
 server/po/de_DE.po                                 |  16 ++-
 server/po/fi_FI.po                                 |   5 +-
 server/po/sk_SK.po                                 |  52 ++++----
 server/recplayer.c                                 |  43 ++++++-
 server/recplayer.h                                 |   6 +-
 server/recstreamer.c                               |  11 +-
 server/recstreamer.h                               |   7 +-
 server/setup.c                                     |  11 ++
 server/setup.h                                     |   8 ++
 server/streamdev-server.c                          |  10 ++
 server/streamdev-server.h                          |   1 +
 server/suspend.c                                   |   2 +-
 34 files changed, 402 insertions(+), 261 deletions(-)

diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index e4aad04..ae9918f 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -214,3 +214,14 @@ Chris Tallon
 
 macmenot
   for adapting Makefiles to VDR 1.7.36+
+
+thomasjfox
+  for fixing cSuspendCtl preventing idle shutdown
+
+hivdr
+  for adding the pos= parameter for replaying recordings from a certain position
+  for suggesting to add the HTTP "Server" header
+
+hummel99
+  for reporting and helping to debug channel switch issues with priority > 0
+  for reporting a race condition when switching the server's LiveTV device
diff --git a/HISTORY b/HISTORY
index 64d17d7..028e1a7 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,32 @@
 VDR Plugin 'streamdev' Revision History
 ---------------------------------------
  
+2013-11-28: Version 0.6.1
+
+- Updated Slovak translation (thanks to Milan Hrala)
+- Updated Finnish translation (thanks to Rolf Ahrenberg)
+- Disabled PS remuxer which is said to produce anything but PS
+- The patches intcamdevices and ignore_missing_cam are no longer required
+  on VDR >= 1.7.30. The localchannelprovide patch became obsolete with VDR
+  1.7.21.
+- Added option to suspend live TV when the server starts
+- Set device occupied when streamdev switches away LiveTV on the server, to
+  reduce the risk that the VDR main loop immediately switches back, resulting
+  in a black screen on the client (reported by hummel99)
+- Fixed channel switch issues with priority > 0 (reported by hummel99)
+- Removed noisy debug messages
+- Fixed HTTP menu destruction
+- API change of VDR 2.1.2
+- Fixed priority handling, messed up when adding multi-device support
+- Added HTTP "Server" header (suggested by hivdr)
+- Ignore dummy file extensions (.ts, .vob, .vdr) when parsing HTTP URIs
+- Select start position for replaying a recording by parameter pos=. Supported
+  values are resume, mark.#, time.#, frame.# or a plain # representing a
+  percentage if < 100 or a byte position otherwise (thanks to hivdr)
+- Start cSuspendCtl hidden or it will prevent idle shutdown (thanks to
+  thomasjfox)
+- Fixed recordings menu inode numbers: ino_t is a long long on some systems
+- Updated Slovak translation (thanks to Milan Hrala)
 - Adapted Makefiles to VDR 1.7.36+ (thanks to macmenot). Old makefiles have
   been renamed to Makefile-1.7.33.
 - API changes of VDR 1.7.38 (thanks to mal at vdr-developer)
diff --git a/README b/README
index 2e0165f..46da3f0 100644
--- a/README
+++ b/README
@@ -218,6 +218,10 @@ image is displayed instead. This would allow a low priority client to switch
 to a different transponder. Enable "Client may suspend" in the server setup
 to allow VDR clients to suspend live TV remotely.
 
+In the server's setup there's also an option to suspend live TV when starting
+the server. The "auto" option will suspend live TV if there's no device with
+an MPEG decoder available which is typically the case on a headless server.
+
 NOTE: Precedence is mainly an issue on One-Card-Systems, since with multiple
 cards there is no need to switch transponders on the primary interface, if on
 of the other cards is idle (i.e. if it is not blocked by a recording). If all
@@ -236,7 +240,6 @@ has been requested in the URL (see below). The supported stream types are:
 
   TS     Transport Stream (i.e. a dump from the device)
   PES    Packetized Elemetary Stream (VDR's native recording format)
-  PS     Program Stream (SVCD, DVD like stream)
   ES     Elementary Stream (only Video, if available, otherwise only Audio)
   EXT    Pass stream through external script (e.g. for converting with mencoder)
 
@@ -263,9 +266,9 @@ In addition, you can specify the desired stream type as a path to the channel.
   http://hostname:3000/PES/S19.2E-0-12480-898
 
 The first one would deliver the stream in TS, the second one in PES format. 
-Possible values are 'PES', 'TS', 'PS', 'ES' and 'EXT'. You need to specify
-the ES format explicitly if you want to listen to radio channels. Play them
-back i.e. with mpg123.
+Possible values are 'PES', 'TS', 'ES' and 'EXT'. You need to specify the ES
+format explicitly if you want to listen to radio channels. Play them back i.e.
+with mpg123.
 
   mpg123 http://hostname:3000/ES/200
 
@@ -545,10 +548,10 @@ The script should perform the following steps (pseudocode):
 6. Known Problems:
 ------------------
 
-* Viewing encrypted channels became an issue with VDR's new CAM handling code.
-Streamdev doesn't provide a (dummy) CAM, so out of the box, VDR won't ever try
-to receive encrypted channels from streamdev. Pick one of the following
-solutions to work around the problem:
+* In VDR before 1.7.30 viewing encrypted channels is an issue as Streamdev
+doesn't provide a (dummy) CAM. So out of the box, VDR won't ever try to receive
+encrypted channels from streamdev. Pick one of the following solutions to work
+around the problem:
 
 1. Force VDR to use streamdev. Open the channels menu on the client (or edit its
 channels.conf if you know how to do this) and set the CA field of all channels
@@ -558,9 +561,9 @@ up. So please consider the logs for the correct value. Remember to fill in
 hexadecimal values if you are using an editor to modify your channels.conf
 (number 10 becomes an "a", number 11 a "b", ...).
 
-2. Apply either patch "patches/vdr-1.6.0-intcamdevices.patch" or patch
-"patches/vdr-1.6.0-ignore_missing_cam.diff" to your client VDR. Intcamdevices
-is the clean solution, but it modifies the VDR API. So you will need to
-recompile all of your plugins. The ignore_missing_cam patch is trivial, no need
-to recompile other plugins. However it is not suitable for clients with a DVB
-card of their own.
+2. Apply either patch "patches/vdr-1.6.0-1.7.29-intcamdevices.patch" or patch
+"patches/vdr-1.6.0-1.7.29-ignore_missing_cam.diff" to your client VDR.
+Intcamdevices is the clean solution, but it modifies the VDR API. So you will
+need to recompile all of your plugins. The ignore_missing_cam patch is trivial,
+no need to recompile other plugins. However it is not suitable for clients with
+a DVB card of their own.
diff --git a/client/device.c b/client/device.c
index ef16690..de0865f 100644
--- a/client/device.c
+++ b/client/device.c
@@ -90,18 +90,10 @@ bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel)
 
 bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority, 
 		bool *NeedsDetachReceivers) const {
-#if APIVERSNUM >= 10725
-	bool prio = Priority == IDLEPRIORITY || Priority >= m_ClientSocket->Priority();
-#else
-	bool prio = Priority < 0 || Priority > m_ClientSocket->Priority();
-#endif
-	bool res = prio;
-	bool ndr = false;
-
 	if (m_Disabled || Channel == m_DenyChannel)
 		return false;
 
-	Dprintf("ProvidesChannel, Channel=%s, Prio=%d\n", Channel->Name(), Priority);
+	Dprintf("ProvidesChannel, Channel=%s, Priority=%d, SocketPrio=%d\n", Channel->Name(), Priority, m_ClientSocket->Priority());
 
 	if (StreamdevClientSetup.MinPriority <= StreamdevClientSetup.MaxPriority)
 	{
@@ -116,6 +108,20 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
 			return false;
 	}
 
+	int newPrio = Priority;
+	if (Priority == LIVEPRIORITY) {
+		if (m_ClientSocket->ServerVersion() >= 100 || StreamdevClientSetup.LivePriority >= 0)
+			newPrio = StreamdevClientSetup.LivePriority;
+	}
+
+#if APIVERSNUM >= 10725
+	bool prio = Priority == IDLEPRIORITY || newPrio >= m_ClientSocket->Priority();
+#else
+	bool prio = Priority < 0 || newPrio > m_ClientSocket->Priority();
+#endif
+	bool res = prio;
+	bool ndr = false;
+
 #if APIVERSNUM >= 10722
 	if (IsTunedToTransponder(Channel)) {
 #else
@@ -129,18 +135,10 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
 			ndr = true;
 	}
 	else if (prio) {
-		if (Priority == LIVEPRIORITY) {
-			if (m_ClientSocket->ServerVersion() >= 100) {
-				Priority = StreamdevClientSetup.LivePriority;
-				UpdatePriority(true);
-			}
-			else {
-				if (StreamdevClientSetup.LivePriority >= 0)
-					Priority = StreamdevClientSetup.LivePriority;
-			}
-		}
+		if (Priority == LIVEPRIORITY && m_ClientSocket->ServerVersion() >= 100)
+			UpdatePriority(true);
 
-		res = m_ClientSocket->ProvidesChannel(Channel, Priority);
+		res = m_ClientSocket->ProvidesChannel(Channel, newPrio);
 		ndr = Receiving();
 
 		if (m_ClientSocket->ServerVersion() >= 100)
@@ -296,8 +294,8 @@ void cStreamdevDevice::UpdatePriority(bool SwitchingChannels) const {
 		if (m_ClientSocket->SupportsPrio() && m_ClientSocket->DataSocket(siLive)) {
 			int Priority = this->Priority();
 			// override TRANSFERPRIORITY (-1) with live TV priority from setup
-			if (this == cDevice::ActualDevice() && m_ClientSocket->Priority() == TRANSFERPRIORITY) {
-				int Priority = StreamdevClientSetup.LivePriority;
+			if (Priority == TRANSFERPRIORITY && this == cDevice::ActualDevice()) {
+				Priority = StreamdevClientSetup.LivePriority;
 				// temporarily lower priority
 				if (SwitchingChannels)
 					Priority--;
diff --git a/client/po/fi_FI.po b/client/po/fi_FI.po
index 2416506..6b55ac5 100644
--- a/client/po/fi_FI.po
+++ b/client/po/fi_FI.po
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: streamdev 0.5.0\n"
-"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
 "POT-Creation-Date: 2013-01-28 22:16+0100\n"
 "PO-Revision-Date: 2008-03-30 02:11+0200\n"
 "Last-Translator: Rolf Ahrenberg\n"
@@ -32,7 +32,7 @@ msgid "Hide Mainmenu Entry"
 msgstr "Piilota valinta päävalikosta"
 
 msgid "Simultaneously used Devices"
-msgstr ""
+msgstr "Yhtäaikaiset laitteet"
 
 msgid "Remote IP"
 msgstr "Etäkoneen IP-osoite"
diff --git a/client/po/sk_SK.po b/client/po/sk_SK.po
old mode 100644
new mode 100755
index 0037e27..65f9a10
--- a/client/po/sk_SK.po
+++ b/client/po/sk_SK.po
@@ -6,8 +6,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: streamdev_SK\n"
-"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
-"POT-Creation-Date: 2013-01-28 22:16+0100\n"
+"Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
+"POT-Creation-Date: 2013-03-13 14:20+0100\n"
 "PO-Revision-Date: \n"
 "Last-Translator: Milan Hrala <hrala.milan at gmail.com>\n"
 "Language-Team: Slovak <hrala.milan at gmail.com>\n"
@@ -18,23 +18,11 @@ msgstr ""
 "X-Poedit-Language: Slovak\n"
 "X-Poedit-Country: SLOVAKIA\n"
 
-msgid "VTP Streaming Client"
-msgstr "VTP pr�dov� klient"
-
-msgid "Suspend Server"
-msgstr "Server pozastaven�"
-
-msgid "Server is suspended"
-msgstr "Server je do�asne preru�en�"
-
-msgid "Couldn't suspend Server!"
-msgstr "Nepodarilo sa pozastavi� Server!"
-
 msgid "Hide Mainmenu Entry"
 msgstr "Schova� polo�ku v hlavnom menu"
 
 msgid "Simultaneously used Devices"
-msgstr ""
+msgstr "S�be�ne pou��va� zariadenia"
 
 msgid "Remote IP"
 msgstr "Vzdialen� IP"
@@ -43,19 +31,32 @@ msgid "Remote Port"
 msgstr "Vzdialen� port"
 
 msgid "Timeout (s)"
-msgstr ""
+msgstr "�asov� limit (s)"
 
 msgid "Filter Streaming"
-msgstr "filtrova� pr�dy"
+msgstr "Filtrova� d�tov� pr�d"
 
 msgid "Live TV Priority"
-msgstr ""
+msgstr "Priorita �iv�ho vysielania"
 
 msgid "Minimum Priority"
-msgstr "minim�lna priorita"
+msgstr "Minim�lna priorita"
 
 msgid "Maximum Priority"
-msgstr "maxim�lna priorita"
+msgstr "Maxim�lna priorita"
 
 msgid "Broadcast Systems / Cost"
-msgstr ""
+msgstr "Syst�my vysielania / Hodnota"
+
+msgid "VTP Streaming Client"
+msgstr "VDR klient streamovania"
+
+msgid "Suspend Server"
+msgstr "Pozastavi� server"
+
+msgid "Server is suspended"
+msgstr "Server je do�asne pozastaven�"
+
+msgid "Couldn't suspend Server!"
+msgstr "Server sa nepodarilo pozastavi�!"
+
diff --git a/client/socket.c b/client/socket.c
index c0a6d1f..eeece5d 100644
--- a/client/socket.c
+++ b/client/socket.c
@@ -40,10 +40,9 @@ cClientSocket::~cClientSocket()
 
 void cClientSocket::Reset(void) 
 {
-	for (int it = 0; it < si_Count; ++it) {
-		if (m_DataSockets[it] != NULL)
-			DELETENULL(m_DataSockets[it]);
-	}
+	for (int it = 0; it < si_Count; ++it)
+		DELETENULL(m_DataSockets[it]);
+	m_Priority = -100;
 }
 
 cTBSocket *cClientSocket::DataSocket(eSocketId Id) const {	
@@ -115,18 +114,15 @@ bool cClientSocket::CheckConnection(void) {
 	if (IsOpen()) {
 		cTBSelect select;
 
-		Dprintf("connection open\n");
-
 		// XXX+ check if connection is still alive (is there a better way?)
 		// There REALLY shouldn't be anything readable according to PROTOCOL here
 		// If there is, assume it's an eof signal (subseq. read would return 0)
 		select.Add(*this, false);
 		int res;
 		if ((res = select.Select(0)) == 0) {
-			Dprintf("select said nothing happened\n");
 			return true;
 		}
-		Dprintf("closing connection (res was %d)", res);
+		Dprintf("closing connection (res was %d)\n", res);
 		Close();
 	}
 
diff --git a/common.c b/common.c
index 4ac7c6f..2f9dd91 100644
--- a/common.c
+++ b/common.c
@@ -10,7 +10,7 @@
 
 using namespace std;
 
-const char *VERSION = "0.6.0-git";
+const char *VERSION = "0.6.1";
 
 const char cMenuEditIpItem::IpCharacters[] = "0123456789.";
 
diff --git a/patches/vdr-1.4.x-localchannelprovide.diff b/patches/vdr-1.4.x-localchannelprovide.diff
deleted file mode 100644
index 857c1a2..0000000
--- a/patches/vdr-1.4.x-localchannelprovide.diff
+++ /dev/null
@@ -1,102 +0,0 @@
-# Apply this patch to VDR if you want to use a fullfeatured DVB card
-# as pure output device. Infact the patch will keep VDR from using the
-# tuner of any local DVB card (also budget cards). It will not affect
-# other input devices like e.g. streamdev-client or DVB cards provided
-# by plugins (e.g. Hauppauge PVR).
-#
-# By default the patch is DISABLED. There will be a new OSD menu entry
-# in Setup->DVB which allows you to enable or disable the patch at any
-# time.
-diff -ru vdr-1.4.3.orig/config.c vdr-1.4.3/config.c
---- vdr-1.4.3.orig/config.c	2006-07-22 13:57:51.000000000 +0200
-+++ vdr-1.4.3/config.c	2006-11-16 08:16:37.000000000 +0100
-@@ -273,6 +273,7 @@
-   CurrentChannel = -1;
-   CurrentVolume = MAXVOLUME;
-   CurrentDolby = 0;
-+  LocalChannelProvide = 1;
-   InitialChannel = 0;
-   InitialVolume = -1;
- }
-@@ -434,6 +435,7 @@
-   else if (!strcasecmp(Name, "CurrentChannel"))      CurrentChannel     = atoi(Value);
-   else if (!strcasecmp(Name, "CurrentVolume"))       CurrentVolume      = atoi(Value);
-   else if (!strcasecmp(Name, "CurrentDolby"))        CurrentDolby       = atoi(Value);
-+  else if (!strcasecmp(Name, "LocalChannelProvide")) LocalChannelProvide = atoi(Value);
-   else if (!strcasecmp(Name, "InitialChannel"))      InitialChannel     = atoi(Value);
-   else if (!strcasecmp(Name, "InitialVolume"))       InitialVolume      = atoi(Value);
-   else
-@@ -502,6 +504,7 @@
-   Store("CurrentChannel",     CurrentChannel);
-   Store("CurrentVolume",      CurrentVolume);
-   Store("CurrentDolby",       CurrentDolby);
-+  Store("LocalChannelProvide",LocalChannelProvide);
-   Store("InitialChannel",     InitialChannel);
-   Store("InitialVolume",      InitialVolume);
- 
-diff -ru vdr-1.4.3.orig/config.h vdr-1.4.3/config.h
---- vdr-1.4.3.orig/config.h	2006-09-23 15:56:08.000000000 +0200
-+++ vdr-1.4.3/config.h	2006-11-16 08:16:57.000000000 +0100
-@@ -250,6 +250,7 @@
-   int CurrentChannel;
-   int CurrentVolume;
-   int CurrentDolby;
-+  int LocalChannelProvide;
-   int InitialChannel;
-   int InitialVolume;
-   int __EndData__;
-diff -ru vdr-1.4.3.orig/dvbdevice.c vdr-1.4.3/dvbdevice.c
---- vdr-1.4.3.orig/dvbdevice.c	2006-08-14 11:38:32.000000000 +0200
-+++ vdr-1.4.3/dvbdevice.c	2006-11-16 08:17:58.000000000 +0100
-@@ -766,6 +766,8 @@
- 
- bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
- {
-+  if (Setup.LocalChannelProvide != 1)
-+     return false;
-   bool result = false;
-   bool hasPriority = Priority < 0 || Priority > this->Priority();
-   bool needsDetachReceivers = false;
-diff -ru vdr-1.4.3.orig/i18n.c vdr-1.4.3/i18n.c
---- vdr-1.4.3.orig/i18n.c	2006-09-16 11:08:30.000000000 +0200
-+++ vdr-1.4.3/i18n.c	2006-11-16 08:36:53.000000000 +0100
-@@ -3546,6 +3546,28 @@
-     "Foretrukket sprog",
-     "Preferovan� jazyk",
-   },
-+  { "Setup.DVB$Use DVB receivers",
-+    "DVB Empfangsteile benutzen",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+    "",
-+  },
-   { "Setup.DVB$Primary DVB interface",
-     "Prim�res DVB-Interface",
-     "Primarna naprava",
-diff -ru vdr-1.4.3.orig/menu.c vdr-1.4.3/menu.c
---- vdr-1.4.3.orig/menu.c	2006-07-23 11:23:11.000000000 +0200
-+++ vdr-1.4.3/menu.c	2006-11-16 08:37:27.000000000 +0100
-@@ -2354,6 +2354,7 @@
- 
-   Clear();
- 
-+  Add(new cMenuEditBoolItem(tr("Setup.DVB$Use DVB receivers"),      &data.LocalChannelProvide));
-   Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
-   Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"),          &data.VideoFormat, "4:3", "16:9"));
-   if (data.VideoFormat == 0)
diff --git a/patches/vdr-1.6.0-ignore_missing_cam.diff b/patches/vdr-1.6.0-1.7.29-ignore_missing_cam.diff
similarity index 100%
rename from patches/vdr-1.6.0-ignore_missing_cam.diff
rename to patches/vdr-1.6.0-1.7.29-ignore_missing_cam.diff
diff --git a/patches/vdr-1.6.0-intcamdevices.patch b/patches/vdr-1.6.0-1.7.29-intcamdevices.patch
similarity index 100%
rename from patches/vdr-1.6.0-intcamdevices.patch
rename to patches/vdr-1.6.0-1.7.29-intcamdevices.patch
diff --git a/remux/ts2ps.c b/remux/ts2ps.c
index 2a97dee..69274ad 100644
--- a/remux/ts2ps.c
+++ b/remux/ts2ps.c
@@ -1,3 +1,5 @@
+#ifdef STREAMDEV_PS
+
 #include "remux/ts2ps.h"
 #include "server/streamer.h"
 #include <vdr/channels.h>
@@ -216,3 +218,4 @@ uchar *cTS2PSRemux::Get(int &Count)
 	return resultData;
 }
 
+#endif
diff --git a/remux/ts2ps.h b/remux/ts2ps.h
index 2380c15..0c1f0fb 100644
--- a/remux/ts2ps.h
+++ b/remux/ts2ps.h
@@ -1,3 +1,5 @@
+#ifdef STREAMDEV_PS
+
 #ifndef VDR_STREAMDEV_TS2PSREMUX_H
 #define VDR_STREAMDEV_TS2PSREMUX_H
 
@@ -34,3 +36,5 @@ public:
 } // namespace Streamdev
 
 #endif // VDR_STREAMDEV_TS2PSREMUX_H
+
+#endif
diff --git a/server/connection.c b/server/connection.c
index 9c7ae31..e0e7f88 100644
--- a/server/connection.c
+++ b/server/connection.c
@@ -14,6 +14,11 @@
 #include <stdarg.h>
 #include <errno.h>
 
+// device occupied timeout to prevent VDR main loop to immediately switch back
+// when streamdev switched the live TV channel.
+// Note that there is still a gap between the GetDevice() and SetOccupied()
+// calls where the VDR main loop could strike
+#define STREAMDEVTUNETIMEOUT 5
 
 cServerConnection::cServerConnection(const char *Protocol, int Type):
 		cTBSocket(Type),
@@ -23,6 +28,7 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
 		m_ReadBytes(0),
 		m_WriteBytes(0),
 		m_WriteIndex(0),
+		m_OccupiedDev(NULL),
 		m_SwitchTo(NULL)
 {
 }
@@ -204,7 +210,7 @@ bool cServerConnection::UsedByLiveTV(cDevice *device)
 		(device->IsPrimaryDevice() && device->HasDecoder() && !device->Replaying());
 }
 
-cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority) 
+cDevice *cServerConnection::SwitchDevice(const cChannel *Channel, int Priority) 
 {
 	// turn off the streams of this connection
 	Detach();
@@ -216,8 +222,22 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
 		dsyslog("streamdev: GetDevice failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex());
 	}
 	else if (!device->IsTunedToTransponder(Channel) && UsedByLiveTV(device)) {
-		// switched away live TV
-		m_SwitchTo = Channel;
+		// make sure VDR main loop doesn't switch back
+		device->SetOccupied(STREAMDEVTUNETIMEOUT);
+		if (device->SwitchChannel(Channel, false)) {
+			// switched away live TV
+			m_OccupiedDev = device;
+			m_SwitchTo = Channel;
+		}
+		else {
+			dsyslog("streamdev: SwitchChannel (live) failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
+			device->SetOccupied(0);
+			device = NULL;
+		}
+	}
+	else if (!device->SwitchChannel(Channel, false)) {
+		dsyslog("streamdev: SwitchChannel failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
+		device = NULL;
 	}
 	return device;
 }
@@ -240,6 +260,7 @@ void cServerConnection::MainThreadHook()
 			Channels.SwitchTo(m_SwitchTo->Number());
 			Skins.Message(mtInfo, tr("Streaming active"));
 		}
+		m_OccupiedDev->SetOccupied(0);
 		m_SwitchTo = NULL;
 	}
 }
diff --git a/server/connection.h b/server/connection.h
index ba1f7bb..e7fb21b 100644
--- a/server/connection.h
+++ b/server/connection.h
@@ -34,6 +34,8 @@ private:
 	uint        m_WriteBytes;
 	uint        m_WriteIndex;
 
+	/* Set to occupied device when live TV was interrupted */
+	cDevice        *m_OccupiedDev;
 	/* Set to this connection's current channel when live TV was interrupted */
 	const cChannel *m_SwitchTo;
 
@@ -106,10 +108,8 @@ public:
 	   channel. This call has no side effects. */
 	static cDevice *CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice = NULL);
 
-	/* Will retrieve an unused device for transmitting data. Receivers have
-	   already been attached from the device if necessary. Use the returned
-	   cDevice in a following call to StartTransfer */
-	cDevice *GetDevice(const cChannel *Channel, int Priority);
+	/* Find a suitable device and tune it to the requested channel. */
+	cDevice *SwitchDevice(const cChannel *Channel, int Priority);
 
 	/* Test if a call to GetDevice would return a usable device. */
 	bool ProvidesChannel(const cChannel *Channel, int Priority);
diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c
index ec10824..ce004a6 100644
--- a/server/connectionHTTP.c
+++ b/server/connectionHTTP.c
@@ -24,7 +24,9 @@ cConnectionHTTP::cConnectionHTTP(void):
 		m_Streamer(NULL),
 		m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
 		m_Channel(NULL),
-		m_Recording(NULL),
+		m_RecPlayer(NULL),
+		m_ReplayPos(0),
+		m_ReplayFakeRange(false),
 		m_MenuList(NULL)
 {
 	Dprintf("constructor hsRequest\n");
@@ -35,7 +37,8 @@ cConnectionHTTP::cConnectionHTTP(void):
 cConnectionHTTP::~cConnectionHTTP() 
 {
 	delete m_Streamer;
-	delete m_Recording;
+	delete m_RecPlayer;
+	delete m_MenuList;
 }
 
 bool cConnectionHTTP::CanAuthenticate(void)
@@ -174,9 +177,8 @@ bool cConnectionHTTP::ProcessRequest(void)
 		else if (m_Channel != NULL) {
 			cDevice *device = NULL;
 			if (ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority))
-				device = GetDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
+				device = SwitchDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
 			if (device != NULL) {
-				device->SwitchChannel(m_Channel, false);
 				cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.HTTPPriority, this);
 				m_Streamer = liveStreamer;
 				if (liveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) {
@@ -197,14 +199,25 @@ bool cConnectionHTTP::ProcessRequest(void)
 			}
 			return HttpResponse(503, true);
 		}
-		else if (m_Recording != NULL) {
+		else if (m_RecPlayer != NULL) {
 			Dprintf("GET recording\n");
-			cStreamdevRecStreamer* recStreamer = new cStreamdevRecStreamer(m_Recording, this);
-			m_Streamer = recStreamer;
 			int64_t from, to;
+			bool hasRange = ParseRange(from, to);
+
+			cStreamdevRecStreamer* recStreamer;
+			if (from == 0 && hasRange && m_ReplayFakeRange) {
+				recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this);
+				from += m_ReplayPos;
+				if (to >= 0)
+					to += m_ReplayPos;
+			}
+			else
+				recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this, m_ReplayPos);
+			m_Streamer = recStreamer;
 			uint64_t total = recStreamer->GetLength();
-			if (ParseRange(from, to)) {
+			if (hasRange) {
 				int64_t length = recStreamer->SetRange(from, to);
+				Dprintf("range response: %lld-%lld/%lld, len %lld\n", (long long)from, (long long)to, (long long)total, (long long)length);
 				if (length < 0L)
 					return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
 				else
@@ -238,13 +251,23 @@ bool cConnectionHTTP::ProcessRequest(void)
 			}
 			return HttpResponse(503, true);
 		}
-		else if (m_Recording != NULL) {
+		else if (m_RecPlayer != NULL) {
 			Dprintf("HEAD recording\n");
-			cStreamdevRecStreamer *recStreamer = new cStreamdevRecStreamer(m_Recording, this);
-			m_Streamer = recStreamer;
 			int64_t from, to;
+			bool hasRange = ParseRange(from, to);
+			
+			cStreamdevRecStreamer* recStreamer;
+			if (from == 0 && hasRange && m_ReplayFakeRange) {
+				recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this, m_ReplayPos);
+				from += m_ReplayPos;
+				if (to >= 0)
+					to += m_ReplayPos;
+			}
+			else
+				recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this, m_ReplayPos);
+			m_Streamer = recStreamer;
 			uint64_t total = recStreamer->GetLength();
-			if (ParseRange(from, to)) {
+			if (hasRange) {
 				int64_t length = recStreamer->SetRange(from, to);
 				if (length < 0L)
 					return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
@@ -301,7 +324,8 @@ bool cConnectionHTTP::HttpResponse(int Code, bool Last, const char* ContentType,
 	if (rc)
 		rc = Respond("Connection: close")
 			&& Respond("Pragma: no-cache")
-			&& Respond("Cache-Control: no-cache");
+			&& Respond("Cache-Control: no-cache")
+			&& Respond("Server: VDR-%s / streamdev-server-%s", true, VDRVERSION, VERSION);
 
 	time_t t = time(NULL);
 	struct tm *gmt = gmtime(&t);
@@ -449,8 +473,10 @@ cMenuList* cConnectionHTTP::MenuListFromString(const std::string& Path, const st
 	return NULL;
 }
 
-cRecording* cConnectionHTTP::RecordingFromString(const char *FileBase, const char *FileExt) const
+RecPlayer* cConnectionHTTP::RecPlayerFromString(const char *FileBase, const char *FileExt)
 {
+	RecPlayer *recPlayer = NULL;
+
 	if (strcasecmp(FileExt, ".rec") != 0)
 		return NULL;
 
@@ -459,25 +485,69 @@ cRecording* cConnectionHTTP::RecordingFromString(const char *FileBase, const cha
 	if (p != FileBase && l > 0L) {
 		if (*p == ':') {
 			// get recording by dev:inode
-			unsigned long inode = strtoul(p + 1, &p, 0);
+			ino_t inode = (ino_t) strtoull(p + 1, &p, 0);
 			if (*p == 0 && inode > 0) {
 				struct stat st;
 				cThreadLock RecordingsLock(&Recordings);
 				for (cRecording *rec = Recordings.First(); rec; rec = Recordings.Next(rec)) {
-					if (stat(rec->FileName(), &st) == 0 && st.st_dev == (dev_t) l && st.st_ino == (ino_t) inode)
-						return new cRecording(rec->FileName());
+					if (stat(rec->FileName(), &st) == 0 && st.st_dev == (dev_t) l && st.st_ino == inode)
+						recPlayer = new RecPlayer(rec->FileName());
 				}
 			}
 		}
 		else if (*p == 0) {
 			// get recording by index
 			cThreadLock RecordingsLock(&Recordings);
-			cRecording* rec = Recordings.Get((int) l - 1);
+			cRecording *rec = Recordings.Get((int) l - 1);
 			if (rec)
-				return new cRecording(rec->FileName());
+				recPlayer = new RecPlayer(rec->FileName());
+		}
+
+		if (recPlayer) {
+			const char *pos = NULL;
+			tStrStrMap::const_iterator it = m_Params.begin();
+			while (it != m_Params.end()) {
+				if (it->first == "pos") {
+					pos = it->second.c_str();
+					break;
+				}
+				++it;
+			}
+			if (pos) {
+				// With prefix "full_" we try to fool players
+				// by replying with a content range starting
+				// at the requested position instead of 0.
+				// This is a heavy violation of standards.
+				// Use at your own risk!
+				if (strncasecmp(pos, "full_", 5) == 0) {
+					m_ReplayFakeRange = true;
+					pos += 5;
+				}
+				if (strncasecmp(pos, "resume", 6) == 0) {
+					int id = pos[6] == '.' ? atoi(pos + 7) : 0;
+					m_ReplayPos = recPlayer->positionFromResume(id);
+				}
+				else if (strncasecmp(pos, "mark.", 5) == 0) {
+					int index = atoi(pos + 5);
+					m_ReplayPos = recPlayer->positionFromMark(index);
+				}
+				else if (strncasecmp(pos, "time.", 5) == 0) {
+					int seconds = atoi(pos + 5);
+					m_ReplayPos = recPlayer->positionFromTime(seconds);
+				}
+				else if (strncasecmp(pos, "frame.", 6) == 0) {
+					int frame = atoi(pos + 6);
+					m_ReplayPos = recPlayer->positionFromFrameNumber(frame);
+				}
+				else {
+					m_ReplayPos = atol(pos);
+					if (m_ReplayPos > 0L && m_ReplayPos < 100L)
+						m_ReplayPos = recPlayer->positionFromPercent((int) m_ReplayPos);
+				}
+			}
 		}
 	}
-	return NULL;
+	return recPlayer;
 }
 
 bool cConnectionHTTP::ProcessURI(const std::string& PathInfo) 
@@ -487,11 +557,24 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
 
 	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)
+		if (ext_pos != std::string::npos) {
 			// file extension including leading .
 			fileext = PathInfo.substr(ext_pos);
+			const char *ext = fileext.c_str();
+			// ignore dummy file extensions
+			if (strcasecmp(ext, ".ts") == 0 ||
+					strcasecmp(ext, ".vdr") == 0 ||
+					strcasecmp(ext, ".vob") == 0) {
+				size_t ext_end = ext_pos;
+				if (ext_pos > 0)
+					ext_pos = PathInfo.rfind('.', ext_pos - 1);
+				if (ext_pos == std::string::npos)
+					ext_pos = ext_end;
+				fileext = PathInfo.substr(ext_pos, ext_end - ext_pos);
+			}
+		}
+		// file basename with leading / stripped off
+		filespec = PathInfo.substr(file_pos + 1, ext_pos - file_pos - 1);
 	}
 	if (fileext.length() > 5) {
 		//probably not an extension
@@ -502,10 +585,12 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
 	// 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) {
+	if (strcasecmp(pType, "PES") == 0) {
 		m_StreamType = stPES;
+#ifdef STREAMDEV_PS
+	} else if (strcasecmp(pType, "PS") == 0) {
+		m_StreamType = stPS;
+#endif
 	} else if (strcasecmp(pType, "TS") == 0) {
 		m_StreamType = stTS;
 	} else if (strcasecmp(pType, "ES") == 0) {
@@ -519,8 +604,8 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
 	if ((m_MenuList = MenuListFromString(PathInfo.substr(1, file_pos), filespec.c_str(), fileext.c_str())) != NULL) {
 		Dprintf("Channel list requested\n");
 		return true;
-	} else if ((m_Recording = RecordingFromString(filespec.c_str(), fileext.c_str())) != NULL) {
-		Dprintf("Recording %s found\n", m_Recording->Name());
+	} else if ((m_RecPlayer = RecPlayerFromString(filespec.c_str(), fileext.c_str())) != NULL) {
+		Dprintf("Recording %s found\n", m_RecPlayer->getCurrentRecording()->Name());
 		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]);
diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h
index e946242..e02f221 100644
--- a/server/connectionHTTP.h
+++ b/server/connectionHTTP.h
@@ -34,12 +34,14 @@ private:
 	int                               m_Apid[2];
 	int                               m_Dpid[2];
 	// job: replay
-	cRecording                       *m_Recording;
+	RecPlayer                        *m_RecPlayer;
+	int64_t                           m_ReplayPos;
+	bool                              m_ReplayFakeRange;
 	// job: listing
 	cMenuList                        *m_MenuList;
 
 	cMenuList* MenuListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const;
-	cRecording* RecordingFromString(const char* FileBase, const char* FileExt) const;
+	RecPlayer* RecPlayerFromString(const char* FileBase, const char* FileExt);
 
 	bool ProcessURI(const std::string &PathInfo);
 	bool HttpResponse(int Code, bool Last, const char* ContentType = NULL, const char* Headers = "", ...);
diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c
index 1f8f3d8..ab80a6a 100644
--- a/server/connectionIGMP.c
+++ b/server/connectionIGMP.c
@@ -44,9 +44,8 @@ void cConnectionIGMP::Welcome()
 {
 	cDevice *device = NULL;
 	if (ProvidesChannel(m_Channel, StreamdevServerSetup.IGMPPriority))
-		device = GetDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
+		device = SwitchDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
 	if (device != NULL) {
-		device->SwitchChannel(m_Channel, false);
 		m_LiveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.IGMPPriority, this);
 		if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType)) {
 			m_LiveStreamer->SetDevice(device);
@@ -61,7 +60,7 @@ void cConnectionIGMP::Welcome()
 		}
 	}
 	else
-		esyslog("streamdev-server IGMP: GetDevice failed");
+		esyslog("streamdev-server IGMP: SwitchDevice failed");
 }
 
 bool cConnectionIGMP::Close()
diff --git a/server/connectionVTP.c b/server/connectionVTP.c
index 57afafa..31906cf 100644
--- a/server/connectionVTP.c
+++ b/server/connectionVTP.c
@@ -872,10 +872,12 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
 		return Respond(220, "Capability \"%s\" accepted", Opts);
 	}
 
+#ifdef STREAMDEV_PS
 	if (strcasecmp(Opts, "PS") == 0) {
 		m_StreamType = stPS;
 		return Respond(220, "Capability \"%s\" accepted", Opts);
 	}
+#endif
 
 	if (strcasecmp(Opts, "PES") == 0) {
 		m_StreamType = stPES;
@@ -1118,11 +1120,8 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
 		if (!ProvidesChannel(chan, prio))
 			return Respond(560, "Channel not available (ProvidesChannel)");
 	}
-	if ((dev = GetDevice(chan, prio)) == NULL)
-		return Respond(560, "Channel not available (GetDevice)");
-
-	if (!dev->SwitchChannel(chan, false))
-		return Respond(560, "Channel not available (SwitchChannel)");
+	if ((dev = SwitchDevice(chan, prio)) == NULL)
+		return Respond(560, "Channel not available (SwitchDevice)");
 
 	delete m_LiveStreamer;
 	m_LiveStreamer = new cStreamdevLiveStreamer(prio, this);
@@ -1150,7 +1149,7 @@ bool cConnectionVTP::CmdPLAY(char *Opts)
 				if (m_RecPlayer) {
 					delete m_RecPlayer;
 				}
-				m_RecPlayer = new RecPlayer(recording);
+				m_RecPlayer = new RecPlayer(recording->FileName());
 				return Respond(220, "%llu (Bytes), %u (Frames)", (long long unsigned int) m_RecPlayer->getLengthBytes(), (unsigned int) m_RecPlayer->getLengthFrames());
 			}
 			else {
@@ -1377,7 +1376,11 @@ bool cConnectionVTP::CmdSTAT(const char *Option)
 	if (*Option) {
 		if (strcasecmp(Option, "DISK") == 0) {
 			int FreeMB, UsedMB;
+#if APIVERSNUM < 20102
 			int Percent = VideoDiskSpace(&FreeMB, &UsedMB);
+#else
+			int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB, &UsedMB);
+#endif
 			Reply(250, "%dMB %dMB %d%%", FreeMB + UsedMB, FreeMB, Percent);
 		}
 		else if (strcasecmp(Option, "NAME") == 0) {
diff --git a/server/livestreamer.c b/server/livestreamer.c
index 8ae9437..07f7273 100644
--- a/server/livestreamer.c
+++ b/server/livestreamer.c
@@ -496,9 +496,11 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
 		m_Remux = new cTS2PESRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
+#ifdef STREAMDEV_PS
 	case stPS:  
 		m_Remux = new cTS2PSRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
+#endif
 
 	case stEXT:
 		m_Remux = new cExternRemux(Connection(), m_Channel, Apids, Dpids);
diff --git a/server/menuHTTP.c b/server/menuHTTP.c
index de46f00..e512c4b 100644
--- a/server/menuHTTP.c
+++ b/server/menuHTTP.c
@@ -28,7 +28,7 @@ const cString cRecordingsIterator::ItemRessource() const
 {
 	struct stat st;
 	if (stat(current->FileName(), &st) == 0)
-		return cString::sprintf("%lu:%lu.rec", st.st_dev, st.st_ino);
+		return cString::sprintf("%lu:%llu.rec", (unsigned long) st.st_dev, (unsigned long long) st.st_ino);
 	return "";
 }
 
@@ -260,8 +260,10 @@ std::string cHtmlMenuList::StreamTypeMenu()
 	std::string typeMenu;
 	typeMenu += (streamType == stTS ? (std::string) "[TS] " :
 			(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
+#ifdef STREAMDEV_PS
 	typeMenu += (streamType == stPS ? (std::string) "[PS] " :
 			(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
+#endif
 	typeMenu += (streamType == stPES ? (std::string) "[PES] " :
 			(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
 	typeMenu += (streamType == stES ? (std::string) "[ES] " :
@@ -402,7 +404,9 @@ std::string cHtmlMenuList::ItemText()
 
 	switch (streamType) {
 		case stTS: suffix = (std::string) ".ts"; break;
+#ifdef STREAMDEV_PS
 		case stPS: suffix = (std::string) ".vob"; break;
+#endif
 		// for Network Media Tank
 		case stPES: suffix = (std::string) ".vdr"; break; 
 		default: suffix = "";
diff --git a/server/menuHTTP.h b/server/menuHTTP.h
index e6141e0..2a396d4 100644
--- a/server/menuHTTP.h
+++ b/server/menuHTTP.h
@@ -18,6 +18,7 @@ class cItemIterator
 		virtual const cString ItemRessource() const = 0;
 		virtual const char* Alang(int i) const = 0;
 		virtual const char* Dlang(int i) const = 0;
+		virtual ~cItemIterator() {};
 };
 
 class cRecordingsIterator: public cItemIterator
diff --git a/server/po/de_DE.po b/server/po/de_DE.po
index 37fa078..0c9387c 100644
--- a/server/po/de_DE.po
+++ b/server/po/de_DE.po
@@ -5,9 +5,9 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: streamdev 0.5.0\n"
-"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
-"POT-Creation-Date: 2012-03-31 15:06+0200\n"
+"Project-Id-Version: streamdev\n"
+"Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
+"POT-Creation-Date: 2013-11-02 16:55+0100\n"
 "PO-Revision-Date: 2008-03-30 02:11+0200\n"
 "Last-Translator: Frank Schmirler <vdrdev at schmirler.de>\n"
 "Language-Team: German <vdr at linuxtv.org>\n"
@@ -16,9 +16,6 @@ msgstr ""
 "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"
 
@@ -37,6 +34,9 @@ msgstr "Allgemeines"
 msgid "Hide Mainmenu Entry"
 msgstr "Hauptmen�eintrag verstecken"
 
+msgid "Start with Live TV suspended"
+msgstr "Live-TV beim Start pausieren"
+
 msgid "Maximum Number of Clients"
 msgstr "Maximalanzahl an Clients"
 
@@ -87,3 +87,7 @@ msgstr "Port des Multicast Clients"
 
 msgid "Multicast Streamtype"
 msgstr "Multicast Streamtyp"
+
+msgid "VDR Streaming Server"
+msgstr "VDR Streaming Server"
+
diff --git a/server/po/fi_FI.po b/server/po/fi_FI.po
index 54bbfe4..697f8a0 100644
--- a/server/po/fi_FI.po
+++ b/server/po/fi_FI.po
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: streamdev 0.5.0\n"
-"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
+"Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
 "POT-Creation-Date: 2012-03-31 15:06+0200\n"
 "PO-Revision-Date: 2008-03-30 02:11+0200\n"
 "Last-Translator: Rolf Ahrenberg\n"
@@ -37,6 +37,9 @@ msgstr "Yleiset asetukset"
 msgid "Hide Mainmenu Entry"
 msgstr "Piilota valinta päävalikosta"
 
+msgid "Start with Live TV suspended"
+msgstr "Käynnistä Live-katselu pysäytettynä"
+
 msgid "Maximum Number of Clients"
 msgstr "Suurin sallittu asiakkaiden määrä"
 
diff --git a/server/po/sk_SK.po b/server/po/sk_SK.po
old mode 100644
new mode 100755
index 8c2a152..7fb8ba8
--- a/server/po/sk_SK.po
+++ b/server/po/sk_SK.po
@@ -6,9 +6,9 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: streamdev_SK\n"
-"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
-"POT-Creation-Date: 2012-03-31 15:06+0200\n"
-"PO-Revision-Date: 2011-12-11 11:25+0100\n"
+"Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
+"POT-Creation-Date: 2013-11-22 23:07+0100\n"
+"PO-Revision-Date: 2013-11-22 23:39+0100\n"
 "Last-Translator: Milan Hrala <hrala.milan at gmail.com>\n"
 "Language-Team: Slovak <hrala.milan at gmail.com>\n"
 "Language: sk\n"
@@ -18,20 +18,17 @@ msgstr ""
 "X-Poedit-Language: Slovak\n"
 "X-Poedit-Country: SLOVAKIA\n"
 
-msgid "VDR Streaming Server"
-msgstr "VDR pr�dov� server"
-
 msgid "Streaming active"
-msgstr "streamovanie aktivne"
+msgstr "Streamovanie akt�vne"
 
 msgid "Streamdev Connections"
-msgstr ""
+msgstr "Streamdev spojenia"
 
 msgid "Disconnect"
-msgstr ""
+msgstr "Odpoji�"
 
 msgid "Suspend"
-msgstr "Pozastavenie"
+msgstr "Pozastavi�"
 
 msgid "Common Settings"
 msgstr "V�eobecn� nastavenia"
@@ -39,53 +36,60 @@ msgstr "V
 msgid "Hide Mainmenu Entry"
 msgstr "Schova� v hlavnom menu"
 
+msgid "Start with Live TV suspended"
+msgstr "Pozastavi� Live TV pri �tarte"
+
 msgid "Maximum Number of Clients"
 msgstr "Maxim�ly po�et klientov"
 
 msgid "VDR-to-VDR Server"
-msgstr "VDR-do-VDR server"
+msgstr "Prenos z VDR do VDR"
 
 msgid "Start VDR-to-VDR Server"
-msgstr "Spusti� VDR-do-VDR Server"
+msgstr "Spusti� prenos z VDR do VDR"
 
 msgid "VDR-to-VDR Server Port"
-msgstr "Port serveru pre VDR-do-VDR"
+msgstr "Port servera prenosu z VDR do VDR"
 
 msgid "Bind to IP"
-msgstr "viaza� na IP"
+msgstr "Viaza� na IP"
 
 msgid "Legacy Client Priority"
-msgstr ""
+msgstr "Dodato�n� priorita klienta"
 
 msgid "Client may suspend"
-msgstr "Klient m�e pozastavi�"
+msgstr "Klient m�e server pozastavi�"
 
 msgid "Loop Prevention"
-msgstr ""
+msgstr "Prevencia slu�ky"
 
 msgid "HTTP Server"
-msgstr "server HTTP"
+msgstr "HTTP server "
 
 msgid "Start HTTP Server"
 msgstr "Spusti� HTTP Server"
 
 msgid "HTTP Server Port"
-msgstr "Port serveru HTTP"
+msgstr "Port HTTP servera"
 
 msgid "Priority"
-msgstr ""
+msgstr "Priorita"
 
 msgid "HTTP Streamtype"
-msgstr "typ pr�du HTTP"
+msgstr "Typ HTTP streamu"
 
 msgid "Multicast Streaming Server"
-msgstr "Multicast pr�dov� server"
+msgstr "Streamovanie Multicastov�ho servera"
 
 msgid "Start IGMP Server"
 msgstr "Spusti� IGMP Server"
 
 msgid "Multicast Client Port"
-msgstr "Port klienta Multicast"
+msgstr "Port Multicast klienta"
 
 msgid "Multicast Streamtype"
-msgstr "Multicast typ streamu"
+msgstr "Typ Multicast streamu"
+
+msgid "VDR Streaming Server"
+msgstr "VDR server streamovania"
+
diff --git a/server/recplayer.c b/server/recplayer.c
index f4fe1cd..3885b4c 100644
--- a/server/recplayer.c
+++ b/server/recplayer.c
@@ -28,17 +28,17 @@
 #define _XOPEN_SOURCE 600
 #include <fcntl.h>
 
-RecPlayer::RecPlayer(cRecording* rec)
+RecPlayer::RecPlayer(const char* FileName)
 {
   file = NULL;
   fileOpen = 0;
   lastPosition = 0;
-  recording = rec;
+  recording = new cRecording(FileName);
   for(int i = 1; i < 1000; i++) segments[i] = NULL;
 
   // FIXME find out max file path / name lengths
 
-  indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording());
+  indexFile = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
   if (!indexFile) esyslog("ERROR: Streamdev: Failed to create indexfile!");
 
   scan();
@@ -85,6 +85,8 @@ RecPlayer::~RecPlayer()
   int i = 1;
   while(segments[i++]) delete segments[i];
   if (file) fclose(file);
+  delete indexFile;
+  delete recording;
 }
 
 int RecPlayer::openFile(int index)
@@ -210,6 +212,41 @@ cRecording* RecPlayer::getCurrentRecording()
   return recording;
 }
 
+#if VDRVERSNUM < 10732
+#define ALIGNED_POS(x) (positionFromFrameNumber(indexFile->GetNextIFrame(x, 1)))
+#else
+#define ALIGNED_POS(x) (positionFromFrameNumber(indexFile->GetClosestIFrame(x)))
+#endif
+uint64_t RecPlayer::positionFromResume(int ResumeID)
+{
+	int resumeBackup = Setup.ResumeID;
+	Setup.ResumeID = ResumeID;
+	cResumeFile resume(recording->FileName(), recording->IsPesRecording());
+	Setup.ResumeID = resumeBackup;
+	return ALIGNED_POS(resume.Read());
+}
+
+uint64_t RecPlayer::positionFromMark(int MarkIndex)
+{
+	cMarks marks;
+	if (marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count()) {
+		cMark *mark = marks.cConfig<cMark>::Get(MarkIndex);
+		if (mark)
+			return ALIGNED_POS(mark->Position());
+	}
+	return 0;
+}
+
+uint64_t RecPlayer::positionFromTime(int Seconds)
+{
+	return ALIGNED_POS(SecondsToFrames(Seconds, recording->FramesPerSecond()));
+}
+
+uint64_t RecPlayer::positionFromPercent(int Percent)
+{
+	return ALIGNED_POS(getLengthFrames() * Percent / 100L);
+}
+
 uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)
 {
   if (!indexFile) return 0;
diff --git a/server/recplayer.h b/server/recplayer.h
index 3da6c89..e56c2cd 100644
--- a/server/recplayer.h
+++ b/server/recplayer.h
@@ -36,7 +36,7 @@ class Segment
 class RecPlayer
 {
   public:
-    RecPlayer(cRecording* rec);
+    RecPlayer(const char* FileName);
     ~RecPlayer();
     uint64_t getLengthBytes();
     uint32_t getLengthFrames();
@@ -45,6 +45,10 @@ class RecPlayer
     uint64_t getLastPosition();
     cRecording* getCurrentRecording();
     void scan();
+    uint64_t positionFromResume(int ResumeID);
+    uint64_t positionFromMark(int MarkIndex);
+    uint64_t positionFromTime(int Seconds);
+    uint64_t positionFromPercent(int Percent);
     uint64_t positionFromFrameNumber(uint32_t frameNumber);
     uint32_t frameNumberFromPosition(uint64_t position);
     bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);
diff --git a/server/recstreamer.c b/server/recstreamer.c
index 73af53b..bd01b96 100644
--- a/server/recstreamer.c
+++ b/server/recstreamer.c
@@ -12,13 +12,14 @@ using namespace Streamdev;
 
 // --- cStreamdevRecStreamer -------------------------------------------------
 
-cStreamdevRecStreamer::cStreamdevRecStreamer(cRecording *Rec, const cServerConnection *Connection):
+cStreamdevRecStreamer::cStreamdevRecStreamer(RecPlayer *RecPlayer, const cServerConnection *Connection, int64_t StartOffset):
 		cStreamdevStreamer("streamdev-recstreaming", Connection),
-		m_RecPlayer(Rec),
+		m_RecPlayer(RecPlayer),
+		m_StartOffset(StartOffset),
 		m_From(0L)
 {
 	Dprintf("New rec streamer\n");
-	m_To = (int64_t) m_RecPlayer.getLengthBytes() - 1;
+	m_To = (int64_t) m_RecPlayer->getLengthBytes() - StartOffset - 1;
 }
 
 cStreamdevRecStreamer::~cStreamdevRecStreamer() 
@@ -29,7 +30,7 @@ cStreamdevRecStreamer::~cStreamdevRecStreamer()
 
 int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To)
 {
-	int64_t l = (int64_t) m_RecPlayer.getLengthBytes();
+	int64_t l = (int64_t) GetLength();
 	if (From < 0L) {
 		From += l;
 		if (From < 0L)
@@ -55,7 +56,7 @@ int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To)
 uchar* cStreamdevRecStreamer::GetFromReceiver(int &Count)
 {
 	if (m_From <= m_To) {
-		Count = (int) m_RecPlayer.getBlock(m_Buffer, m_From, sizeof(m_Buffer));
+		Count = (int) m_RecPlayer->getBlock(m_Buffer, m_StartOffset + m_From, sizeof(m_Buffer));
 		return m_Buffer;
 	}
 	return NULL;
diff --git a/server/recstreamer.h b/server/recstreamer.h
index 83df8c1..ee4b120 100644
--- a/server/recstreamer.h
+++ b/server/recstreamer.h
@@ -11,7 +11,8 @@
 class cStreamdevRecStreamer: public cStreamdevStreamer {
 private:
 	//Streamdev::cTSRemux    *m_Remux;
-	RecPlayer               m_RecPlayer;
+	RecPlayer              *m_RecPlayer;
+	int64_t                 m_StartOffset;
 	int64_t                 m_From;
 	int64_t                 m_To;
 	uchar                   m_Buffer[RECBUFSIZE];
@@ -22,10 +23,10 @@ protected:
 
 public:
 	virtual bool IsReceiving(void) const { return m_From <= m_To; };
-	inline uint64_t GetLength() { return m_RecPlayer.getLengthBytes(); }
+	uint64_t GetLength() { return m_RecPlayer->getLengthBytes() - m_StartOffset; }
 	int64_t SetRange(int64_t &From, int64_t &To);
 	virtual cString ToText() const;
-	cStreamdevRecStreamer(cRecording *Recording, const cServerConnection *Connection);
+	cStreamdevRecStreamer(RecPlayer *RecPlayer, const cServerConnection *Connection, int64_t StartOffset = 0L);
 	virtual ~cStreamdevRecStreamer();
 };
 
diff --git a/server/setup.c b/server/setup.c
index 862c917..b3d23d4 100644
--- a/server/setup.c
+++ b/server/setup.c
@@ -12,6 +12,7 @@ cStreamdevServerSetup StreamdevServerSetup;
 cStreamdevServerSetup::cStreamdevServerSetup(void) {
 	HideMenuEntry   = false;
 	MaxClients      = 5;
+	StartSuspended  = ssAuto;
 	StartVTPServer  = true;
 	VTPServerPort   = 2004;
 	VTPPriority     = 0;
@@ -33,6 +34,7 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) {
 bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
 	if      (strcmp(Name, "HideMenuEntry") == 0)   HideMenuEntry   = atoi(Value);
 	else if (strcmp(Name, "MaxClients") == 0)      MaxClients      = atoi(Value);
+	else if (strcmp(Name, "StartSuspended") == 0)  StartSuspended  = atoi(Value);
 	else if (strcmp(Name, "StartServer") == 0)     StartVTPServer  = atoi(Value);
 	else if (strcmp(Name, "ServerPort") == 0)      VTPServerPort   = atoi(Value);
 	else if (strcmp(Name, "VTPPriority") == 0)     VTPPriority     = atoi(Value);
@@ -71,10 +73,18 @@ cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() {
 }
 
 void cStreamdevServerMenuSetupPage::Set(void) {
+	static const char *StartSuspendedItems[ss_Count] =
+	{
+		trVDR("no"),
+		trVDR("yes"),
+		trVDR("auto")
+	};
+
 	int current = Current();
 	Clear();
 	AddCategory (tr("Common Settings"));
 	Add(new cMenuEditBoolItem(tr("Hide Mainmenu Entry"),       &m_NewSetup.HideMenuEntry));
+	Add(new cMenuEditStraItem(tr("Start with Live TV suspended"),   &m_NewSetup.StartSuspended, ss_Count, StartSuspendedItems));
 	Add(new cMenuEditIntItem (tr("Maximum Number of Clients"), &m_NewSetup.MaxClients, 0, 100));
 
 	
@@ -131,6 +141,7 @@ void cStreamdevServerMenuSetupPage::Store(void) {
 	
 	SetupStore("HideMenuEntry",   m_NewSetup.HideMenuEntry);
 	SetupStore("MaxClients",      m_NewSetup.MaxClients);
+	SetupStore("StartSuspended",  m_NewSetup.StartSuspended);
 	SetupStore("StartServer",     m_NewSetup.StartVTPServer);
 	SetupStore("ServerPort",      m_NewSetup.VTPServerPort);
 	SetupStore("VTPBindIP",       m_NewSetup.VTPBindIP);
diff --git a/server/setup.h b/server/setup.h
index aa66378..8358a4f 100644
--- a/server/setup.h
+++ b/server/setup.h
@@ -7,6 +7,13 @@
 
 #include "common.h"
 
+enum eStartSuspended {
+	ssNo,
+	ssYes,
+	ssAuto,
+	ss_Count
+};
+
 struct cStreamdevServerSetup {
 	cStreamdevServerSetup(void);
 
@@ -14,6 +21,7 @@ struct cStreamdevServerSetup {
 
 	int HideMenuEntry;
 	int MaxClients;
+	int StartSuspended;
 	int StartVTPServer;
 	int VTPServerPort;
 	char VTPBindIP[20];
diff --git a/server/streamdev-server.c b/server/streamdev-server.c
index 65ed23e..e5c6e45 100644
--- a/server/streamdev-server.c
+++ b/server/streamdev-server.c
@@ -12,6 +12,7 @@
 #include "server/menu.h"
 #include "server/setup.h"
 #include "server/server.h"
+#include "server/suspend.h"
 
 #if !defined(APIVERSNUM) || APIVERSNUM < 10725
 #error "VDR-1.7.25 or greater required to compile server! Use 'make client' to compile client only."
@@ -21,6 +22,7 @@ const char *cPluginStreamdevServer::DESCRIPTION = trNOOP("VDR Streaming Server")
 
 cPluginStreamdevServer::cPluginStreamdevServer(void) 
 {
+	m_Suspend = false;
 }
 
 cPluginStreamdevServer::~cPluginStreamdevServer() 
@@ -98,6 +100,9 @@ bool cPluginStreamdevServer::Start(void)
 
 	cStreamdevServer::Initialize();
 
+	m_Suspend = StreamdevServerSetup.StartSuspended == ssAuto ?
+			!cDevice::PrimaryDevice()->HasDecoder() :
+			StreamdevServerSetup.StartSuspended;
 	return true;
 }
 
@@ -129,6 +134,11 @@ cOsdObject *cPluginStreamdevServer::MainMenuAction(void)
 
 void cPluginStreamdevServer::MainThreadHook(void)
 {
+	if (m_Suspend) {
+		cControl::Launch(new cSuspendCtl);
+		m_Suspend = false;
+	}
+
 	cThreadLock lock;
 	const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
 	for (cServerConnection *s = clients.First(); s; s = clients.Next(s))
diff --git a/server/streamdev-server.h b/server/streamdev-server.h
index f1be8aa..a89f6c7 100644
--- a/server/streamdev-server.h
+++ b/server/streamdev-server.h
@@ -12,6 +12,7 @@
 class cPluginStreamdevServer : public cPlugin {
 private:
 	static const char *DESCRIPTION;
+	bool m_Suspend;
 
 public:
 	cPluginStreamdevServer(void);
diff --git a/server/suspend.c b/server/suspend.c
index b6e1382..fd351b6 100644
--- a/server/suspend.c
+++ b/server/suspend.c
@@ -39,7 +39,7 @@ void cSuspendLive::Action(void) {
 bool cSuspendCtl::m_Active = false;
 
 cSuspendCtl::cSuspendCtl(void):
-		cControl(m_Suspend = new cSuspendLive) {
+		cControl(m_Suspend = new cSuspendLive, true) {
 	m_Active = true;
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-streamdev.git



More information about the pkg-vdr-dvb-changes mailing list